martes, 31 de octubre de 2017

Solaris recovery detach device - Recuperar device detachado de zpool Solaris 10

Esta es una historia que jamas debió haber pasado pero que se sabe pasa en días que transcurren, acompañen me a visitar este carrusel de emociones en donde encontraremos miedo, odio, resignación y como en toda buena historia una luz de esperanza al fin del camino; pues bien, iniciemos.

Capitulo 1 - El desastre.

Un día cualquiera por cuestiones de la vida, en nuestro centro de datos ocurrió una variación  de energía y nuestro  almacenamiento EVA perdió discos en sus VG tanto que los volúmenes se volvieron inaccesibles, esta EVA presentaba LUNs a nuestra Sun Sparc M5000 las cuales dejaron de ver la información y se volvió inaccesible la información.

A continuación una evidencia de lo sucedido.

















Ante esta situación claramente no teníamos nada que hacer, revisamos nuestra EVA y los volúmenes estaban protejidos y sin respaldos actuales, lo único que teníamos era un espejo en algo viejo en otra EVA, espejo que habíamos detachado (detach) del zpool mirror en que estaba. Por lo que erá la única esperanza de recuperar los datos medianamente usables, esto después de buscar respaldos por todos lados y sin tener un punto de donde recuperarnos a través del sistema de respaldos.

Capitulo 2 - Buscando un punto de apoyo en el abismo.

Ante la situación comenzamos a tratar de acceder a los volumenes de la EVA la cual tenía los espejos a travez de "zpool import -F XXXDBPNINST" la mala noticia es que este comando no arrojaba nada, el volumen aparentemente no tenía información y comenzaron las preocupaciones, decidimos revisar si la base de datos de zfs contenía algo en el volumen, esto lo hicimos con:






















Al parecer nuestra información si estaba en el disco, solo que algo pasaba con la metadata, revisando la documentación de zpool nos encontramos con que detach reescribe todo el uberblock del volumen, justo aquí fuimos concientes en el problema enorme en el que estábamos, una pequeña búsqueda en internet nos dio a entender que no se podía recuperar la información por medios tradicionales, por lo cual no nos quedó mas que buscar ayuda en el soporte de Oracle, después de varios correos de control nos dan la fabulosa noticia que la proxima vez que queramos desacoplar un disco utilicemos split y no detach (ya sabíamos que era lo que hacía detach), Buscamos ayuda a uno de nuestros proveedores y la respuesta fue muy similar, ellos no podían hacer mucho ya que era un tema bastante complejo, lo mejor era buscar ayuda con Oracle.

Con el animo por el piso y con unas cuantas amenazas de lo que podía suceder si no recuperabamos la información decidimos buscar un poco mas en internet y con la calma y con los términos y documentación un poco mas afianzada y nos encontramos con este enlace (agrego una copia del correo con el código fuente)del 2008, en resumidas cuentas a alguien le había pasado lo mismo pero en solaris x86 y logro acceder al volumen, esto lo logró escribiendo un programa en C que básicamente lo que hacía era reescanear la base del disco para encontrar los puntos de inicio del zpool y de esta forma volver a reescribir el ublock, todo un hacker de zfs.

Capitulo 3 - Una luz al final del tunel

Pues bien ya se tenía la tarea para hacer, lo primero que se intento fue usar el compilado que vienen adjunto en la lista de correo, claramente no funciono, lo siguiente fue intentar compilarlo en solaris, para desgracia de nosotros el código fuente fue hecho para opensolaris y no para solaris en si mismo, así que tampoco nos funciono, eso y nuestros conocimientos de desarrollo no nos permitieron hacer las modificaciones necesarias.

Al no poder hacer mucho desde la maquina que si tenía acceso a la información decidimos extraer imagenes puras de la LUN para copiarlas a otro servidor y poder hacer las pruebas necesarias, así que decidimos hacer copias con dd en los solaris y pasarlas por scp al servidor donde originalmente habían ocurrido los daños.

Una vez las imagenes en el servidor donde si podiamos hacer las pruebas procedimos a crear LUNs con espacios exactamente iguales, label iguales y sectores de disco iguales, lo siguiente fue inyectar los datos con dd a las nuevas LUNs y verificar con zdb, las cuales eran iguales a lo que teníamos en el servidor espejo, bien, en este punto estabamos casi al inicio pero con nuestra información ya en la otra EVA, el problema seguía siendo como accederla, después de buscar mas y mas nos encontramos con esta entrada en donde solicitan que se ingrese una funcionalidad a zfsonlinux (si, el mismo port de opensolaris a linux) y donde  mencionan otro articulo donde se hace una modificación del código fuente del 2008, las esperanzas comenzaron a regenerarse, leyendo un poco los comentarios básicamente las pruebas habían sido exitosas con Ubuntu 14.04 y zfsonlinux 0.6.5.1.

Lo siguiente fue montar nuestro servidor Ubuntu, presentar las LUNs a este servidor y seguir las instrucciones siguientes:

Originally written by Jeff Bonwick (http://www.mail-archive.com/zfs-discuss@opensolaris.org/msg15748.html), and updated by James Lee to work with modern ZFS libs (https://www.mail-archive.com/zfs-discuss@opensolaris.org/msg47316.html), I was able to compile this life-saving utility in Ubuntu 14.04 and have verified that it works. (I'm using ZFSonLinux.)
Download the ZFSonLinux tarball and replace the cmd/zhack/zhack.c file with "labelfix.c". Note that zhack is just a simple utility that we're replacing so that we don't have to setup the build environment. (It's hard, so we'll reuse the good work of the ZFSonLinux people.)
Run "./configure; make" and if all goes well then the zfs tools will be built, except for zhack, which we replaced. Run that with the device path to recover your data.

El codigo fuente modificado para zfsonlinux es el siguiente:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

/*
 * Write a label block with a ZBT checksum.
 */
static void
label_write(int fd, uint64_t offset, uint64_t size, void *buf)
{
        zio_eck_t *zbt, zbt_orig;
        zio_cksum_t zc;

        zbt = (zio_eck_t *)((char *)buf + size) - 1;
        zbt_orig = *zbt;

        ZIO_SET_CHECKSUM(&zbt->zec_cksum, offset, 0, 0, 0);

        zio_checksum_SHA256(buf, size, &zc);
        zbt->zec_cksum = zc;

        VERIFY(pwrite64(fd, buf, size, offset) == size);

        *zbt = zbt_orig;
}

int
main(int argc, char **argv)
{
        int fd;
        vdev_label_t vl;
        nvlist_t *config;
        uberblock_t *ub = (uberblock_t *)vl.vl_uberblock;
        uint64_t txg;
        char *buf;
        size_t buflen;

        VERIFY(argc == 2);
        VERIFY((fd = open(argv[1], O_RDWR)) != -1);
        VERIFY(pread64(fd, &vl, sizeof (vdev_label_t), 0) ==
            sizeof (vdev_label_t));
        VERIFY(nvlist_unpack(vl.vl_vdev_phys.vp_nvlist,
            sizeof (vl.vl_vdev_phys.vp_nvlist), &config, 0) == 0);
        VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, &txg) == 0);
        VERIFY(txg == 0);
        VERIFY(ub->ub_txg == 0);
        VERIFY(ub->ub_rootbp.blk_birth != 0);

        txg = ub->ub_rootbp.blk_birth;
        ub->ub_txg = txg;

        VERIFY(nvlist_remove_all(config, ZPOOL_CONFIG_POOL_TXG) == 0);
        VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG, txg) == 0);
        buf = vl.vl_vdev_phys.vp_nvlist;
        buflen = sizeof (vl.vl_vdev_phys.vp_nvlist);
        VERIFY(nvlist_pack(config, &buf, &buflen, NV_ENCODE_XDR, 0) == 0);

        label_write(fd, offsetof(vdev_label_t, vl_uberblock),
            1ULL << UBERBLOCK_SHIFT, ub);

        label_write(fd, offsetof(vdev_label_t, vl_vdev_phys),
            VDEV_PHYS_SIZE, &vl.vl_vdev_phys);

        fsync(fd);

        return (0);
}

Con animos de gastar todas las opciones disponibles, compilamos el código fuente como lo dice la sección anterior, el cual arrojo un error pero a la hora de revisar los binarios del paquete efectivamente se encontraba el binario zhack.

Capitulo 4 - Lecciones aprendidas

Con el momento de la verdad delante de nosotros ejecutamos el comando ./zhack /dev/dsk/c5t600508B40009BD73000050000F3F0000d0s2 el comando no arrojo ningún error, pero al momento de hacer el zimport nuevamente nos mostró la información en el ubuntu, en ese momento pudimos descansar, lo siguiente fue pasar por rsync la información al solaris ya que el hack no permitia ver el volumen en el solaris, así que con nuevos volumenes en el solaris nos faltaba hacer rsync a todo el volumen abierto y realizar las configuraciones faltantes.

Lo que aprendimos de toda esta odisea fue que siempre, siempre debemos tener respaldos, el tener un soporte no te garantiza que te hagan el trabajo sucio y por ultimo que internet es una fuente inagotable de información.

Espero que esta recopilación de información sea útil para algún sysadmin y pueda acceder a toda la historia del hack sin tener que deambular días por la web.




viernes, 9 de junio de 2017

Akonadi postgresql backend

Una entrada rápida, solo con el fin de registrar una curiosidad de KDE.

Para llevar a cabo nuestra premisa necesitamos tener instalados dos componentes fundamentales.
Es importante detener los servicios de akonadi para llevar a cabo estas tareas, esto lo logramos desde una terminal de un usuario normal.

akonadictl stop

El motor de base de datos y el driver de qt para postgres.

Fedora
yum install postgresql-server qt-postgresql

Opensuse
zypper install postgresql-server libQt5Sql5-postgresql


Lo siguiente sería modificar la configuración de akonadi para que use postgresql en lugar de mysql, la configuración se encuentra en la ruta.

/home/usuario/.config/akonadi/akonadiserverrc

[Debug]
Tracer=null

[%General]
Driver=QPSQL

[QPSQL]
Host=/tmp/akonadi-usuario.HTtCtb
InitDbPath=/usr/bin/initdb
Name=akonadi
Options=
Password=akonadi
ServerPath=/usr/bin/pg_ctl
StartServer=true
User=akonadi


Para tener en cuenta los campos marcados en negrita, donde básicamente indicamos los datos de conexión.

Con esto iniciamos el motor por primera vez con el comando.

akonadictl start

Esto intentará iniciar el motor de akonadi pero fallará ya que el script de inicio no crea la base de datos y los usuarios dentro del motor de postgres, por ello procedemos a crear la base de datos para akonadi.

Antes de conectarnos necesitamos hacer un pequeño truco para poder acceder al motor de postgresql con la herramienta psql y es crear unos enlaces simbolicos, esto lo haremos con el usuario root:

ln -s /tmp/akonadi-usuario.HTtCtb/.s.PGSQL.5432 /var/run/postgresql/.s.PGSQL.5432

Para conectarnos al motor es necesario hacerlo desde el usuario normal con el siguiente comando.

psql postgres

esto nos ingresará a la consola de postgresql en donde crearemos nuestra base de datos y usuarios para recibir la conexión de akonadi.



create database akonadi;
CREATE ROLE akonadi WITH LOGIN PASSWORD 'akonadi';
grant ALL ON DATABASE akonadi TO akonadi;



Con esto ya tendremos la base de datos y los permisos necesarios para la conexión, ahora solo nos resta iniciar nuevamente el servidor de akonadi con:

akonadictl start

Y esto sería todo, con eso ya se tendría el servidor de akonadi con su backend en postgresql, hay que recordar que para grandes cargas de correo hay que tunear postgresql de lo contrario dará algunos problemas de lentitud.

Si hay dudas comenten y con gusto intentaré resolverlas.