# rm-rf.es | Administración de sistemas

Bitácora personal de un SysAdmin Gnu/Linux, Windows, BSD...

Red Hat Cluster: “generic error” al crear un IP Resource

redhat logoLlevo unos días haciendo pruebas con una maqueta de Red Hat Cluster Suite en CentOS. De momento, voy estudiando los distintos comandos y ficheros de configuración, aunque utilizo luci/ricci para la gestión del cluster vía web.

Uno de los primeros problemas que me encontré es de lo más simple. La idea es crear un recurso IP, que levanta una IP virtual en uno de los nodos del cluster. Esa IP la podemos utilizar posteriormente como recurso para un servicio HTTP ó MySQL por ejemplo, IP que en caso de fallo del nodo activo se traspasará junto con el resto de servicio a otro nodo del cluster.

Lo único que hay que tener claro es que la subred de esa IP debe estar configurada en alguna de las interfaces de red de los nodos, sino el rgmanager no sabrá donde levantarla. La máscara es opcional, pero por ahí venían todos mis problemas. Recibía el siguiente error al levantar el servicio:

Dec 28 21:41:53 nodo1 rgmanager[3563]: Initializing service:IP
Dec 28 21:42:32 nodo1 rgmanager[3563]: Recovering failed service service:IP
Dec 28 21:42:32 nodo1 rgmanager[3563]: start on ip "192.168.1.200/255.255.255.0" returned 1 (generic error)
Dec 28 21:42:33 nodo1 rgmanager[3563]: #68: Failed to start service:IP; return value: 1
Dec 28 21:42:33 nodo1 rgmanager[3563]: Stopping service service:IP
Dec 28 21:42:35 nodo1 rgmanager[3563]: Service service:IP is recovering

Y la configuración del recurso/servicio:

<service autostart="0" domain="IP_FAILOVER" name="IP" recovery="relocate">
<ip address="192.168.1.200/255.255.255.0" monitor_link="1" sleeptime="10"/>
</service>

El problema, tras darle unas cuantas vueltas era tan simple como que la máscara se especifica como bits de máscara de red, es decir, en lugar de 255.255.255.0, 24:

<service autostart="0" domain="IP_FAILOVER" name="IP" recovery="relocate">
<ip address="192.168.1.200/24" monitor_link="1" sleeptime="10"/>
</service>

Tratamos de arrancar el servicio y ya levanta la IP virtual correctamente. Puede parecer una tontería pero es útil tenerlo en cuenta por si os pasa.

Dec 28 21:47:31 nodo1 rgmanager[3331]: Starting stopped service service:IP
Dec 28 21:47:37 nodo1 rgmanager[8561]: [ip] Adding IPv4 address 192.168.1.200/24 to eth0
Dec 28 21:47:44 nodo1 rgmanager[3331]: Service service:IP started

Bonding/Teaming/Trunking en RHEL y CentOS

bonding linux

El Bonding (también conocido como teaming, y en switching como trunking) es, básicamente, la unión de varias interfaces de red para que trabajen como una única interfaz lógica. Esta configuración permite establecer configuraciones de activo-pasivo, balanceo de carga o crear un agregado de interfaces con un ancho de banda que supone la suma del de todas las interfaces asignadas.

Antes de comenzar la configuración, nos aseguramos de tener cargado el módulo bonding:

# lsmod | grep bonding
bonding               109558  0
ipv6                  264641  29 bonding,ip6t_REJECT,nf_conntrack_ipv6,nf_defrag_ipv6,cnic

En caso de no estar lo cargamos:

# modprobe bonding

Tenemos que configurar unos parámetros de kernel para añadir esta nueva interfaz/funcionalidad:

# vi /etc/modprobe.conf
alias bond0 bonding
options bond0 mode=6 miimon=100

El valor mode, especificado en 6 indica que el tipo de bonding va a ser de balanceo de carga. Los posibles valores son de 0 a 6:

  • 0: round robin policy, defecto
  • 1: active backup policy
  • 2: XOR
  • 3: brodcast
  • 4: 802.3ad
  • 5:  balance-tlb
  • 6:  balance-alb

El valor miimon indica con un valor entero la frecuencia de monitorización del link. Para conocer todos estos parámetros en condiciones os recomiendo revisar la documentación del kernel sobre bonding

Ahora vamos a crear el fichero de configuración para la interfaz Bond0, que será la que en nuestro caso creará el bonding de eth0 y eth1. El fichero de configuración se crea en la misma ruta que el resto /etc/sysconfig/network-scripts/ifcfg-XXX. Este fichero es el que contendrá la configuración IP, NETMASK, etc.

# vim /etc/sysconfig/network-scripts/ifcfg-bond0
DEVICE=bond0
ONBOOT=yes
IPADDR=192.168.1.190
NETMASK=255.255.255.0
BROADCAST=192.168.1.255
NETWORK=192.168.1.0
USERCTL=no
BOOTPROTO=none

Ahora configuramos eth0 y eth1, en ellas no establecemos ninguna configuración IP, sino que especificamos que es una interfaz esclavo (slave) y que su master es bond0:

vi /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
ONBOOT=yes
USERCTL=no
BOOTPROTO=none
MASTER=bond0
SLAVE=yes
vi /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
ONBOOT=yes
USERCTL=no
BOOTPROTO=none
MASTER=bond0
SLAVE=yes

Una vez configurado, reiniciamos el servicio de red:

# /etc/init.d/network restart

Si todo ha ido bien ya veremos la interfaz bond0 en ifconfig:

# ifconfig
bond0     Link encap:Ethernet  HWaddr 08:00:27:00:C8:7A
          inet addr:192.168.1.190  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fe00:c87a/64 Scope:Link
          UP BROADCAST RUNNING MASTER MULTICAST  MTU:1500  Metric:1
          RX packets:1029 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1198 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:101972 (99.5 KiB)  TX bytes:182347 (178.0 KiB)

eth0      Link encap:Ethernet  HWaddr 08:00:27:00:C8:7A
          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
          RX packets:946 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1144 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:90003 (87.8 KiB)  TX bytes:175136 (171.0 KiB)
          Interrupt:11 Base address:0xc020 

eth1      Link encap:Ethernet  HWaddr 08:00:27:00:C8:7A
          UP BROADCAST RUNNING SLAVE MULTICAST  MTU:1500  Metric:1
          RX packets:94 errors:0 dropped:0 overruns:0 frame:0
          TX packets:59 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:12695 (12.3 KiB)  TX bytes:8325 (8.1 KiB)
          Interrupt:10 Base address:0xc060 

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:1241 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1241 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:170253 (166.2 KiB)  TX bytes:170253 (166.2 KiB)

Podemos monitorizar el estado del bonding desde /proc/net/bonding/bond0:

# cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v3.6.0 (September 26, 2009)

Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 0
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: eth0
MII Status: up
Speed: 100 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 08:00:27:00:c8:7a
Slave queue ID: 0

Slave Interface: eth1
MII Status: up
Speed: 100 Mbps
Duplex: full
Link Failure Count: 0
Permanent HW addr: 08:00:27:fd:48:08
Slave queue ID: 0

Múltiples VLAN por interfaz en Windows Server

broadcom advanced control suiteDe forma nativa (que yo sepa) Windows Server no ofrece la posibilidad de configurar múltiples VLAN por interfaz de red. Esto nos obliga a recurrir a las utilidades que el fabricante del dispositivo de red nos facilite.

Broadcom por ejemplo nos ofrece la utilidad “Broadcom Advanced Control Suite” que nos permite, además de crear VLANs virtuales, hacer balanceo de carga o Ethernet bonding. Podéis leer la guía de utilización en este enlace y descargar la suite desde el sitio web de Broadcom. Por supuesto se presupone que la configuración de red en los switches para las VLAN (trunk, etc) es la correcta. En el caso de esta utilidad, todo se puede configurar a través de los asistentes de forma gráfica y/o en modo experto así que no tiene demasiada complejidad.

Básicamente, primero se crea un Team, se le asignan las intefaces de red que queramos y a partir de ahí se configuran las VLAN virtuales, el balanceo de carga o lo que necesitemos. Una vez finalizado el asistente, si hemos creado VLAN virtuales, los nuevos dispositivos virtuales aparecerán en el centro de redes de Windows, donde podremos asignarle la IP correspondiente como si un dispositivo estándar se tratara.

Si necesitáis este tipo de configuraciones no perdáis el tiempo e id a buscar directamente las utilidades del proveedor de las tarjetas de red.

DB_File.xs:101: db.h: No such file or directory

La situación es la siguiente. Estamos compilando en Solaris 10 el módulo de Perl DB_File. El requerimiento lógico es tener instalado BerkeleyDB en el servidor así que procedemos a ello:

# pkgadd -d db-4.7.25.NC-sol10-x86-local

Ahora procedemos a la típica compilación (Elegir el compilador correcto para Perl en Solaris) y nos encontramos con uno de estos dos errores:

  cc -c -I/usr/local/include -Dbool=char -DHAS_BOOL
  -O2    -DVERSION=\"1.64\" -DXS_VERSION=\"1.64\" -fpic
  -I/usr/local/lib/perl5/i586-linux/5.00404/CORE -DmDB_Prefix_t=size_t
  -DmDB_Hash_t=u_int32_t DB_File.c
  DB_File.xs:101: db.h: No such file or directory
  LD_RUN_PATH="/lib" cc -o blib/arch/auto/DB_File/DB_File.so  -shared
  -L/usr/local/lib DB_File.o    -L/usr/local/lib -ldb
  ld: cannot open -ldb: No such file or directory

Es raro porque el fichero db.h se encuentra en la ruta de instalación de DB. El problema es que el fichero de configuración para la compilación del módulo presupone una ruta estándar que en este caso no se cumple. Así que modificamos dicho fichero de esta forma:

Antes (config.in):

	INCLUDE = /usr/local/BerkeleyDB/include
	LIB     = /usr/local/BerkeleyDB/lib

Por la ruta donde se encuentre, en mi caso /usr/local/BerkeleyDB.4.7/include/db.h:

	INCLUDE = /usr/local/BerkeleyDB.4.7/include
	LIB     = /usr/local/BerkeleyDB.4.7/lib

Y a compilar.

Elegir el compilador correcto para Perl en Solaris

Cuando compilamos módulos de Perl en Solaris (en este caso Solaris 10) hay que tener muy claro el compilador a utilizar. En esta versión de Solaris tenemos por defecto la versión 5.8.4 de Perl, la cual ha sido compilada con la suite de compilación de Sun Studio. La forma habitual de compilar módulos es la siguiente:

# perl Makefile.PL
# make
# make test
# make install

Si lo hacemos así, el sistema utilizará el compilador Sun Studio y habrá flags incompatibles, errores de compilación, etc. Lo que tenemos que hacer es forzar la utilización del compilador GNU C/C++, que por defecto lo encontraremos en /usr/sfw/bin como nos indica el Solaris Install CookBook.

Lo primero que tenemos que hacer es añadir esta ruta al PATH ya que por defecto no está:

export PATH=$PATH:/usr/sfw/bin

Para la ejecución del Makefile.PL utilizaremos perlgcc en lugar de perl a secas, está en la ruta “/usr/perl5/bin/perlgcc“. Para los make forzaremos la utilización de gmake en la ruta anteriormente citada. La lista de comandos sería la siguiente:

# /usr/perl5/bin/perlgcc Makefile.PL
# /usr/sfw/bin/gmake MAKE=/usr/sfw/bin/gmake
# /usr/sfw/bin/gmake MAKE=/usr/sfw/bin/gmake test
# /usr/sfw/bin/gmake MAKE=/usr/sfw/bin/gmake install

Instalar una máquina virtual KVM con Kickstart

Ya he hablado en otras ocasiones de Kickstart, explicando el modo de automatizar instalaciones de CentOS con Kickstart. En este caso el proceso es igual, pero aplicándolo a la automatización en virtualización. Si desconocéis como funciona Kickstart/Anaconda os recomiendo revisar antes ese post.

Vamos a ver como automatizar la instalación de máquina virtuales, en este caso KVM, pero es aplicable a Xen y otros sistemas de virtualización.

Vamos a hacer uso de la herramienta virt-install para las instalaciones. Esta es la línea de comandos que podemos usar para instalar una máquina virtual Scientific Linux (sería igual para RHEL, CentOS, Fedora…) sin intervención manual:

# virt-install  --name testKS \
                --ram 512 \
                --disk /var/lib/libvirt/images/testks.img,size=5 \
                 -l "ftp://ftp.scientificlinux.org/linux/scientific/6.1/x86_64/os/" \
                 -x "ks=ftp://192.168.1.130/pub/ks.cfg"

Starting install...
Retrieving file .treeinfo...                           |  768 B     00:00 ...
Retrieving file vmlinuz...                             | 7.4 MB     00:05 ...
Retrieving file initrd.img...                          |  68 MB     00:53 ...
Creating domain...                                     |    0 B     00:00

Los parámetros utilizados son los siguientes:

  • –name: nombre de la máquina virtual.
  • –ram: tamaño de memoria RAM en MB.
  • –disk: ruta y nombre del fichero .img que será utilizado como disco duro virtual. Tras la ruta a la imagen se especifica el tamaño en GB de la imágen (5).
  • -l (–location): especifica el lugar donde se encuentra el instalador del sistema (vmlinuz e initrd.img), en este caso especificamos el respositorio oficial de Scifi Linux y la ruta exacta para 64bits.
  • -x (–extra-args): especificamos argumentos extra para la instalación, en este caso tiene que ser la ruta al fichero Kickstart que tiene toda la configuración del proceso de instalación.

Y esto es todo. Si el fichero Kickstart está bien, se realizará una instalación totalmente desatendida del sistema operativo.

Desactivar el acceso por proxy en Debian a APT

Esta mañana nos encontrábamos instalando una máquina virtual Debian Squeeze a través de netinstall y por restricciones de seguridad hemos tenido que configurar vía proxy la descarga de paquetes para la instalación.

Una vez instalado e intentar actualizar el sistema nos hemos dado cuenta que seguíamos usando el proxy al usar apt/aptitude. Cuando instalamos Debian a través de un proxy, luego hay que desactivarlo en apt si no queremos seguir usándolo.

Para ello, debemos eliminar las líneas en /etc/apt/apt.conf que contienen la configuración del proxy: Acquire::http::Proxy ó Acquire::ftp::Proxy seguido de la URL del proxy:

Acquire::http::Proxy "http://miproxy.com:8213";
Acquire::ftp::Proxy "http://miproxy.com:8213";

Ejemplos prácticos de grep y egrep

grep searchGrep es sin duda alguna no de los comandos más utilizados en el día a día por los administradores de sistemas. Muchos no van más allá de sus usos más básicos, que si bien cumplen a la perfección su función son una mínima parte de las posibilidades que nos ofrece. Algunos de estos ejemplos se pueden ejecutar tanto con grep como con egrep (egrep= grep -E), independientemente de que casi siempre se ejecuten con egrep en el post. Espero que os sean de utilidad.

Este es el texto que se va a utilizar para trabajar como ejemplo. Sí, es un fichero de configuración de un Cluster MySQL de prueba, pero es que no tenía otra cosa a mano y no me apetecía preparar un fichero específicamente para esto ;)

[ndb_mgmd]
hostname=192.168.0.10           # Hostname or IP address of management node
datadir=/var/lib/mysql-cluster  # Directory for management node log files

# Options for data node "A":
[ndbd]
                                # (one [ndbd] section per data node)
hostname=192.168.0.30           # Hostname or IP address
datadir=/usr/local/mysql/data   # Directory for this data node's data files

# Options for data node "B":
[ndbd]
hostname=192.168.0.40           # Hostname or IP address
datadir=/usr/local/mysql/data   # Directory for this data node's data files

# SQL node options:
[mysqld]
hostname=192.168.0.20           # Hostname or IP address
                                # (additional mysqld connections can be
                                # specified for this node for various
                                # purposes such as running ndb_restore)

Buscar dos ó n strings distintas dentro de un mismo fichero

La sintaxis es ‘(cadena1|cadena2|cadenaN)’. La salida será todas aquellas líneas que contienen cualquiera de esas strings. Esto nos permite hacer múltiples búsquedas en un único comando:

$ egrep '(192.168.0.30|192.168.0.40)' test
hostname=192.168.0.30           # Hostname or IP address
hostname=192.168.0.40           # Hostname or IP address
$ egrep '(192.168.0.30|192.168.0.40|192.168.0.20)' test
hostname=192.168.0.30           # Hostname or IP address
hostname=192.168.0.40           # Hostname or IP address
hostname=192.168.0.20           # Hostname or IP address

Usar los corchetes para reducir el rango de búsqueda

Podemos hacer uso de los corchetes [] para definir, dentro de una misma string, que una sección contenga únicamente X carácteres, un rango de ellos, etc.

En este caso queremos sacar únicamente los resultados que contengan 192.168.0.30 y 192.168.0.40:

$ egrep 192.168.0.[30,40] test
hostname=192.168.0.30           # Hostname or IP address
hostname=192.168.0.40           # Hostname or IP address

Pero si quisiéramos definir los rangos que queremos mostrar para los dos últimos caracteres, en este caso numéricos (se podría hacer con alfanuméricos) podemos hacerlo separando el valor inicial y el final con “-”. En este ejemplo queremos que nos muestre aquello que cumpla la condición de que el primer número del último bloque tiene que ser 0,1 ó 2:

$ egrep 192.168.0.[0-2]0 test
hostname=192.168.0.10           # Hostname or IP address of management node
hostname=192.168.0.20           # Hostname or IP address

Y en este que el primer número del último bloque sea 1,2 ó 3 y el último entre 0 y 9:

$ egrep 192.168.0.[0-3][0-9] test
hostname=192.168.0.10           # Hostname or IP address of management node
hostname=192.168.0.30           # Hostname or IP address
hostname=192.168.0.20           # Hostname or IP address

Un ejemplo práctico con caracteres alfanuméricos sería usar por ejemplo [a-c]test, que buscaría atest, btest y ctest ó por ejemplo [ar4d]test que buscaría atest, rtest, 4test y dtest.

Uso de clases predefinidas

Existen clases predefinidas que nos pueden llegar a ahorrar mucho trabajo. Son las siguientes:

[:alnum:], [:alpha:], [:cntrl:], [:digit:], [:graph:], [:lower:], [:print:], [:punct:], [:space:], [:upper:], [:xdigit:]

Lo que hace cada una de ellas está claro por su nombre, no obstante vamos a ver un ejemplo. Podemos buscar toda línea que contenga un carácter en mayúsculas:

$ egrep [[:upper:]] test
hostname=192.168.0.10           # Hostname or IP address of management node
datadir=/var/lib/mysql-cluster  # Directory for management node log files
...
...

Todo lo que comienza o termina por…

Esto es sencillo, las líneas comienzan por el carácter ^ y terminan con $. Por lo que:

Buscar todo lo que comience por “hostname”:

$ egrep ^hostname test
hostname=192.168.0.10           # Hostname or IP address of management node
hostname=192.168.0.30           # Hostname or IP address
hostname=192.168.0.40           # Hostname or IP address
hostname=192.168.0.20           # Hostname or IP address

O todo lo que termine por “node”:

$ egrep node$ test
hostname=192.168.0.10           # Hostname or IP address of management node

Más expresiones regulares

Ya hicimos un artículo sobre ello hace tiempo, podéis revisarlo aquí: unix: Expresiones regulares, ahí también encontraréis unos cuantos ejemplos de grep. Son muy útiles los operadores de repetición:

       ?      El carácter que precede es opcional y coincide al menos una vez.
       *      El carácter que precede coincidirá 0 o más veces.
       +      El carácter que precede coincidirá 1 o más veces.
       {n}    El carácter que precede coincidirá exactamente n veces.
       {n,}   El carácter que precede coincidirá n o más veces.
       {,m}   El carácter que precede coincidirá como máximo m veces.
       {n,m}  El carácter que precede coincidirá entre n y m veces.

Podemos entonces buscar todas las líneas del fichero que contienen una IP. Usamos primero los corchetes para definir que puede haber números del 0 al 9, con las llaves decimos que habrá 1 o 3 números en cada bloque y así cuatro veces (nota: hay que escapar las llaves):

$ grep '[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}.[0-9]\{1,3\}' test
hostname=192.168.0.10           # Hostname or IP address of management node
hostname=192.168.0.30           # Hostname or IP address
hostname=192.168.0.40           # Hostname or IP address
hostname=192.168.0.20           # Hostname or IP address

Buscar palabras completas, contar resultados

Para indicar a grep que queremos que la búsqueda se centre en palabras y no en caracteres sueltos especificamos el parámetro “-w”. Podemos ver la diferencia buscando “data” en el ejemplo, contamos los resultados satisfactorios con el parámetro “-c”:

$ grep -cw data test
5
$ grep -c data test
6

Excluir resultados, sensibilidad a mayúsculas

Algo básico a la hora de usar grep es conocer los parámetros “-v” que excluye la cadena indicada en el resultado y “-i” que especifica que no se tendrá en cuenta si el resultado es mayúscula o minúscula.

Eliminamos las líneas que tienen comodines:

$ grep -v "#" test
[ndb_mgmd]

[ndbd]

[ndbd]

[mysqld]

Uso de pipes

Todos usamos pipes (|) para acotar resultados. Hacemos un primer grep, con el resultado de ese hacemos otro y así sucesivamente:

$ grep -iw hostname test | grep 192.168.0.[0-9]0 | grep -v 192.168.0.40 | grep -vw node
hostname=192.168.0.30           # Hostname or IP address
hostname=192.168.0.20           # Hostname or IP address

Listar los archivos que contienen la cadena

Con el parámetro -l podemos ejecutar grep contra varios archivos (y de forma recursiva en múltiples directorios con -R) y recibiremos el listado de archivos con coincidencias sin mostrar las líneas que contienen la cadena:

$ grep -lR SQL *
config.ini
header.xcf
iptables.sh
test
dir1/test.sql
dir2/prueba.txt
...

Número de línea en la que se encuentran los resultados

Para saber el número de línea en la que se encuentra el resultado utilizaremos el parámetro -n:

$ grep -n hostname test
2:hostname=192.168.0.10           # Hostname or IP address of management node
8:hostname=192.168.0.30           # Hostname or IP address
...

Cuantas veces se encuentran resultados

Si “-n” nos monstraba el nº de línea en el que estaba la coincidencia, “-c” nos dice cuantas veces está la búsqueda en el fichero:

$ grep -c hostname test
4

Bueno, de momento esto es todo. Por supuesto hay muchas más opciones y explotar la potencia de grep llevaría mucho tiempo así que a partir de aquí investigáis vosotros ;)