SyntaxHighlighter

viernes, 31 de octubre de 2014

Cambio de disco en una cabina de discos HP Modular Smart Array (MSA 2000)

No es la primera vez, ni será la última. Puedes gastarte un dineral en comprar los dispositivos más fiables del mercado, intentar que las condiciones de funcionamiento sean las mejores (UPS, refrigeración, etc) pero al final sabes que se romperán.

Los administradores de sistemas tenemos la obligación de ser paranoicos dentro de las posibilidades económicas de la empresa y las de que nuestra salud mental, por eso en cada intervención delicada en uno de nuestros sistemas debemos, al menos:

  1. Ponernos al día sobre la actuación leyendo el material recomendado por el fabricante, foros explicando procedimientos similares
  2. Documentar el estado actual del sistema, para poder reproducirlo después del cambio: versiones del software, opciones de configuración más importantes, etc
  3. Ensayar la actuación en un sistema de pre-producción
  4. Hacer copias de seguridad
  5. Si es posible tener un sistema "gemelo" montado aunque sea en máquinas menos potentes o virtuales para usar como "plan B" en caso de que las cosas se compliquen
  6. Hacer copias de seguridad... ¿Lo he puesto antes? Da igual, no está de más decirlo otra vez
Presento el sistema. Matriz de discos HP MSA Modular:


Los sistemas de gama empresarial normalmente sintonizan con nuestra paranoia. Algo tan aparentemente leve como que uno de los discos tarde un poco más en girar (spin-up time) o se detecte alguna anomalía eléctrica hace que se disparen las alarmas y el disco pase a ser "no confiable". Ahora entran en juego dos conceptos muy importantes en sistemas de este tipo.

RAID y SPARE

  • RAID. Algunas configuraciones de RAID son tolerantes a fallos, de manera que aunque perdemos espacio de almacenamiento ganamos seguridad. Por ejemplo, un conjunto de discos configurados en RAID 5 utiliza el espacio de almacenamiento de un disco como espacio de redundancia, de manera que si perdemos un disco, no se pierden datos. Se puede sustituir por otro disco y el sistema reconstruirá el conjunto.
  • Discos SPARE (hotspare) o "discos reserva". Además podemos definir dentro de la cabina discos que no se utilizan, pero están preparados para sustituir a otro que falle inmediatamente, sin intervención nuestra.
En sistemas de este nivel SIEMPRE se utiliza algún sistema de redundancia que variará para maximizar la seguridad, la velocidad de escritura, la velocidad de lectura, etc.,  y, por supuesto, discos spare.

Por ejemplo, los sistemas RAID 1 (mirror) acelera las lecturas ya que se puede leer de dos discos al mismo tiempo, en cambio, la escritura lleva un tiempo similar a sistemas de disco único. Usamos la mitad de la capacidad total en datos de redundancia. Aquí somos tolerantes a fallos siempre que el disco o discos se encuentren en el mismo conjunto del espejo.

Otros niveles de RAID, como RAID5, hacen que se pierda menos espacio. Si tenemos n discos, el espacio total será el de n-1 discos ya que uno se usa como disco redundante. Aquí no se gana tanto rendimiento de lectura como en RAID1 pero aún así, bajo ciertas circunstancias, se acelera la lectura respecto a sistemas de disco único. La escritura se ve penalizada al tener que calcular el contenido del bloque de paridad, que ya no es un proceso tan inmediato como hacer una copia del bloque en otro disco. Este nivel RAID tolera fallos en un sólo disco. RAID6, es similar a RAID5, pero usa dos discos para redundancia, por lo que se tiene tolerancia a fallos en dos discos.

Las combinaciones de niveles RAID están permitidas. Es decir, se puede hacer RAID5+0.

Frío y Calor

Hay sistemas capaces de implementar RAID en software, pero lo interesante es tener una controladora de discos que lo soporte en hardware y así hacerlo menos dependiente del sistema operativo. Éste es el caso de las controladoras de discos que estamos viendo.

Suponiendo una configuración RAID5 con spare, en el momento que falle un disco, la cabina lo detecta, lo tacha como "no confiable" y usa el disco spare como nuevo disco en el conjunto RAID. Este proceso puede hacerse en frío, si necesitamos reiniciar el sistema o dar la orden de resconstrucción y esperar el tiempo necesario para que se reconstruya; o en caliente, si la controladora es capaz de seguir dando servicio mientras el disco spare se reconstruye y además no necesita que intervengamos en el proceso.

Rompiendo un disco

Lo que voy a hacer es reproducir el proceso de sustitución de un disco en fallo en una cabina en la que todos los discos están bien. Extraeré uno de los discos del array para simular en fallo. 
Primero vamos a ver el estado de la cabina:


En la imagen vemos que hay ocho discos, siete forman un conjunto RAID6 y uno de ellos configurado como SPARE. Podrían romperse dos discos del conjunto RAID6 y aún no perderíamos datos. Además, como veremos, en el momento que falle uno de ellos el disco SPARE intentará sustituirlo.

Otra vista, pero esta vez voy a insertar un disco nuevo en la cabina. Como no hemos dicho para qué debe utilizar ese nuevo disco lo define como "disponible". Este disco no se utilizará para nada hasta que no se defina su función de forma explícita. Vemos el disco spare (VDISKSP).


Sacamos un disco y a ver que pasa.


Reconstrucción de un VDISK (RAID 6)

Si pinchamos en el estado de la MSA vemos que ha empezado a reconstruir el RAID6 inmediatamente. El proceso tardará unas horas dependiendo del tamaño del VDISK, la configuración RAID y el grado de utilización de los datos de la cabina mientras se hace la reconstrucción ya que la cabina seguirá activa para lectura y escritura.

En la figura anterior tenemos varios campos relacionados con la salud (health). Vemos que la cabina está degradada aunque aún es tolerante a fallos. En la parte inferior vemos en current job que el disco se está reconstruyendo.


En el esquema gráfico de la cabina se puede ver que hemos vuelto "pinchar" el disco en su lugar. La MSA sabe qué disco es, sabe que ha estado pinchado con anterioridad y por algún motivo ha fallado, así que lo marca como LEFTOVR (descartado). No usará este disco más a no ser que la "hagamos olvidar".

Una vez reconstruido el disco tenemos esta estructura.


El disco 1.8 que antes estaba como SPARE pasa a formar parte del VDISK.

Ahora para recuperar el disco que hemos sacado debemos borrar sus metadatos. Esto se puede hacer desde la opción clear disk metadata, como vemos en la imagen siguiente.


Borrando los metadatos el disco volverá a estar disponible (AVAIL). Por último modificamos los discos SPARE de la MSA para incluir estos discos disponibles no usados.


En el menú provisioning la opción Manage Global Spares donde podemos definir los discos que se podrán usar como SPARE en cualquier VDISK de la MSA. También podríamos definir discos SPARE reservados para un VDISK determinado.

Este sería el estado final donde se ve el primer disco que retiramos de la cabina como Global Spare. Y el VDISK totalmente reconstruido.


Todo correcto :D



viernes, 21 de marzo de 2014

Data Protector. Recuperación usando la directiva POST-EXEC y SCRIPTING

Con Data Protector podemos programar una agenda de copias de seguridad fácilmente usando la GUI Java, lo que no es tan simple es planificar una calendario de restauración que, por ejemplo, recupere la última copia de seguridad realizada en otra localización.

La primera aproximación sería intentar ejecutar esta restauración llamando al programa omnir con los argumentos necesarios e incluir la llamada en el cron del servidor para que se ejecute periódicamente. Lo que a priori parece algo sencillo se complica con sólo mirar la la página de manual de omnir (o buscar "data protector cli reference" en cualquier buscador). El Backend de comandos de Data Protector da toda la funcionalidad que necesitamos para restaurar una copia de seguridad, pero es necesario la ejecución de varias órdenes para "montar" los argumentos que necesita omnir.

Hay otro problema en cuanto a la inclusión en cron de esta orden podría dar lugar a solapamientos en el uso de la unidad sobre la que estemos haciendo la copia de seguridad.

Imaginad que la copia de seguridad programada comienza a las 2:00 am, y nuestra orden de restauración se ejecuta vía cron a las 4:00 am. Si la copia de seguridad tarda más de 2h, la restauración se podrá en cola. Pasado cierto tiempo de espera configurable en Data Protector, si aún no ha comenzado el trabajo de restauración, se procederá a su cancelación. Esto se puede evitar usando las opciones POST-EXEC y PRE-EXEC del trabajo de copia de seguridad.

Estas dos opciones se encargan de ejecutar un script en el cliente de data protector que indiquemos antes (PRE-EXEC) o después (POST-EXEC) de que se realice el trabajo de backup. El uso más extendido de estas dos opciones es el de parar un servicio antes de realizar el trabajo de copia y levantarlo después.

Para conseguir el comportamiento que necesitamos lo ideal sería ejecutar un script en POST-EXEC que llame a omnir con los datos de la última copia de seguridad. Para conseguir los datos necesarios de la última sesión de copia de seguridad hay que ejecutar la orden onmidb, que consulta la BD de Data Protector para extraer la información que requiere omnir:

/opt/omni/bin/omnir -filesystem [datalist] [label] -session [session] -tree [path] -as [target_path] -target [target_client]

Pasos del script:
  1. Considera un número de días hacia atrás desde la fecha actual para buscar la última sesión de la agenda especificada.
  2. Determinar sesión más reciente que se terminó satisfactoriamente en el intervalo definido en el paso anterior.
  3. Buscar el árbol de directorios que queremos restaurar y extraer el datalist y label, argumentos necesarios para ejecutar omnir.
  4. Ejecutar omnir con los parámetros adecuados.
El código del script (un poco sucio):

#!/bin/bash
OMNI_PATH=/opt/omni/bin/

if [ $# -ne 5 ]; then
  echo "Ilegal number of arguments" >&2
  echo "Use: $0 [dataList] [label] [targetClient] [targetDir] [RestoreOnlyIfFull 0/1]" >&2
  exit 1
fi

ARG_DATALIST=$1
ARG_LABEL=$2
ARG_TARGETCLIENT=$3
ARG_TARGETDIR=$4
ARG_ONLYFULL=$5
DAYSTOINSPECT=30

INITIALDATE=$(date '+%Y/%m/%d' --date="${DAYSTOINSPECT} days ago")
LASTSESSION=$(${OMNI_PATH}omnidb -session -datalist $ARG_DATALIST -since $INITIALDATE | grep -i backup | grep -i completed | tail -n1 | cut -f 1 -d " ")
FILESYSTEM=$(${OMNI_PATH}omnidb -session $LASTSESSION | grep \'${ARG_LABEL}\' | cut -f1 -d " ")
LABEL=$(${OMNI_PATH}omnidb -session $LASTSESSION | grep \'${ARG_LABEL}\' | cut -f2 -d " ")
BACKUP_LEVEL=$(${OMNI_PATH}omnidb -filesystem $FILESYSTEM ${ARG_LABEL} -session $LASTSESSION | egrep -o "Incremental|Full")

if [ -z "$LASTSESSION" ]; then
 echo "Session not found: $ARG_DATALIST. Available schedules:"
 ls /etc/opt/omni/server/schedules >&2
 exit 1
fi

if [[ $ARG_ONLYFULL -eq 1 && $BACKUP_LEVEL != "Full" ]]; then
 echo "Mode is set to full but cannot find full backup" >&2
 exit 1
fi

if [ -z "$LABEL" ]; then 
 echo "Label not found: $ARG_LABEL. Backed up filesystems and labels:"
 omnidb -filesystem >&2
 exit 1
fi

#Print command options
echo "Restoring label: ${LABEL}, filesystem: < $FILESYSTEM > from Session: $LASTSESSION into ${ARG_TARGETCLIENT}:${ARG_TARGETDIR}, backup_level: $BACKUP_LEVEL"
#Print omnir command used to perform the restore job. Debug.
echo ${OMNI_PATH}omnir -filesystem ${FILESYSTEM} ${LABEL} -session ${LASTSESSION} -tree ${ARG_LABEL} -as ${ARG_TARGETDIR} -target ${ARG_TARGETCLIENT}
OMNI_COMMAND="${OMNI_PATH}omnir -filesystem ${FILESYSTEM} ${LABEL} -session ${LASTSESSION} -tree ${ARG_LABEL} -as ${ARG_TARGETDIR} -target ${ARG_TARGETCLIENT}"
eval $OMNI_COMMAND

Si a la orden omnir que se llama al final del script añadimos -full antes del argumento -filesystem se restaurará una copia completa del árbol de directorios usando la última copia completa que se realizó y todas las incrementales hasta la sesión que estamos restaurando. De otra manera sólo se restaurarán los ficheros que se respaldaron en la sesión en cuestión.  El último argumento del script controla los problemas que se puedan derivar de esto: sólo se ejecutará la restauración si la última copia ha sido full.

No está de más ejecutar el script comentando la última línea (eval ...), para comprobar que todo es correcto antes de empezar a utilizarlo. Si alguno de los parámetros no es correcto imprimirá posibles soluciones.

Por último, el directorio en el que tenemos que incluir el script para que no haya problemas es /opt/omni/lbin y así podremos llamarlo sin usar path completo, algo que parece que no funciona bien si configuramos el POST-EXEC desde la GUI Java.

NOTA. Si la restauración toma demasiado tiempo, Data Protector puede abortar el Script. Para evitarlo se puede modificar la opción ScriptOutputTimeout en el fichero /etc/opt/omni/server/options/global

jueves, 20 de marzo de 2014

Netstat y Zabbix

Ya he hablado otras veces de la herramienta de monitorización de servidores Zabbix y de lo fácil que resulta extenderla.

Hoy hemos recibido una petición por parte de compañeros para que añadiéramos varios monitores más a los datos que se recogen de los servidores, en particular, datos derivados de la ejecución de la orden netstat que devuelve datos sobre las conexiones de red establecidas con el servidor. Por ejemplo, para ver el número de conexiones establecidas a un determinado puerto, ya sean de salida o de entrada. La orden en cuestión es: netstat -an | grep STABLISHED  | grep [port]

Para poder parametrizar la orden he creado un fichero de configuración de zabbix similar al que hay en varios foros para valores de mysql, que nos permite utilizar argumentos. Fichero userparameter_netstat.conf (crear en /etc/zabbix/ e incluir desde el dichero /etc/zabbix/zabbix_agentd.conf):

# Flexible parameter to grab global variables. On the frontend side, use keys like netstat.port[Port_number].
# Key syntax is netstat.port[Port_number].
UserParameter=netstat.port[*],netstat -na | grep $1 | grep ESTABLISH | wc -l
O mejor aún (actualizado):
UserParameter=netstat.port[*],netstat -na | grep ESTABLISH | egrep ':$1[[:blank:]]+' | wc -l

Para considerar sólo cadenas que del tipo: "dos puntos + puerto especificado + espacios" y así, evitar que se incluyan en el conteo líneas que en realidad no son conexiones a ese puerto.
Con esto conseguimos que zabbix_agent responda a peticiones de un nuevo parámetro: netstat.port[puerto] con la orden

netstat-na | grep puerto | grep STABLISH | wc -l

que devuelve el número de conexiones al puerto que se le pase.

Activamos los cambios reiniciando el servicio zabbix-agent. Y probamos que la instrucción funciona correctamente llamando al parámetro por línea de órdenes:
[root@host zabbix]# zabbix_agentd --test netstat.port[80]
netstat.port[80]                            [t|4]

En caso de no estar bien configurado la respuesta sería
[root@host zabbix]# zabbix_agentd --test netstat.port[80]
netstat.port[80]                            [t|NOT_SUPPORTED]

Ya tenemos la "parte cliente" hecha. Ahora toca crear una plantilla que podamos asociar a nuestros hosts para que se llame a ese parámetro de usuario.

Vamos a la sección de plantillas dentro de la administración de Zabbix y creamos una nueva plantilla. Añadimos tantos items como puertos queramos monitorizar. Por ejemplo para el puerto HTTP usaríamos la siguiente definición de item:

netstat.port[80]

Añadimos los items que queramos y por último podemos incluso añadir un gráfico a la plantilla añadiendo todos los monitores de netstat.

Una vez creada la plantilla hay que enlazarla al host que queremos monitorizar y que debe tener en su fichero de configuración la definición del userparameter. Activamos los items para que comience su monitorización y listo.

Archivo XML de la plantilla:

    2.0
    2014-03-20T12:10:04Z
    
        
            Templates
        
    
    
        
    
    
        
            Connections (netstat)
            500
            200
            0.0000
            100.0000
            1
            1
            0
            1
            0
            0.0000
            0.0000
            0
            0
            0
            0
            
                
                    0
                    0
                    00DD00
                    0
                    2
                    0
                    
                        Template_Netstat
                        netstat.port[80]
                    
                
                
                    1
                    0
                    BBBB00
                    0
                    2
                    0
                    
                        Template_Netstat
                        netstat.port[43]
                    
                
                
                    2
                    0
                    CC00CC
                    0
                    2
                    0
                    
                        Template_Netstat
                        netstat.port[3306]
                    
                
                
                    3
                    0
                    0000CC
                    0
                    2
                    0
                    
                        Template_Netstat
                        netstat.port[1251]
                    
                
            
        
    

jueves, 13 de febrero de 2014

Alta disponibilidad Moodle

Muy buen vídeo sobre alta disponibilidad para la plataforma Moodle, aunque sea un poco antiguo (Moodlemoot 2009).

Todo el reconocimiento para Antonio Jesús Lozano y Felipe Retortillo.