Receta rápida: evitar desconexión por timeout en ssh

Problema: El servidor ssh al que te conectas cierra la conexión cuando detecta inactividad del usuario. Como tienes varias ventanas y tareas abiertas a la vez, ese timeout hace que la sesión ssh se quede bloqueada cada dos por tres.

Solución: crear un fichero ~/.ssh/config con el contenido que indico a continuación. Ese fichero se leerá cada vez que iniciemos una conexión ssh con cualquier host. Lo que indicamos es que queremos lanzar un paquete a modo de señal cada 120 segundos (2 minutos), haciendo saber que seguimos conectados y que no queremos que nos corte la conexión. Si por cualquier razón el servidor no respondiera tras 3 intentos de envío de señal (2*3 = 6 minutos), se cancelará la conexión.

cat ~/.ssh/config 
Host *
    ServerAliveInterval 120
    ServerAliveCountMax 3

Cómo pedir ayuda para corregir un problema de programación

Estimado amigo/a,

acabo de leer tu descripción del error y petición de ayuda:

«He probado algunas cosas y la aplicación Java me falla siempre diciendo no sé qué error. Ya no sé qué hacer. Ayúdame»

Tengo algunos consejos para poder ayudarte. En concreto 10, que se resumen en uno: especifica el error. Si no describes con más detalle el error que obtienes no sabré ni por dónde empezar a ayudarte. El siguiente decálogo es un mínimo, cualquier otra informacióna adicional contribuirá a que pueda ayudarte con más posibilidades de éxito:

1) Una descripción detallada de lo que quieres ejecutar y cuál es el resultado esperado.

2) Una descripción detallada de lo que tu aplicación devuelve al ejecutarla. El mensaje de error en texto Y si es posible, una captura de pantalla adjunta. Es decir, el resultado obtenido.

3) Una descripción detallada del proceso que has seguido, punto por punto, hasta llegar al mensaje de error.

4) Un programa mínimo, que aísle las líneas de código de tu aplicación que crees que fallan. Ese programa, como te indico, debe ser lo más pequeño posible y debe demostrar la situación de error que quieres corregir. Envíame su código fuente (NO el ejecutable) junto con al menos un caso de prueba (cuantos más casos de prueba, mejor, pero al menos uno que demuestre el error).

5) Para el/los caso(s) de prueba del programa anterior, indica también cuál es el resultado que obtienes y cuál es el que esperabas obtener

6) Especifica el sistema operativo que estás usando en tus pruebas (nombre, versión, idioma). Si tu aplicación requiere a su vez de otras aplicaciones para ser ejecutada (bibliotecas de funciones o navegador o una configuración especial del sistema), indica todos los datos posibles de esas otras dependencias (como mínimo nombre y versión)

7) Especifica la versión exacta de Java que estás usando.

8) Indica qué pruebas has realizado hasta ahora y por qué no han funcionado.

9) Indica, si es posible, cuál crees tú que es la causa del error y qué cadenas de búsqueda has utilizado en Google/Bing/Yahoo para rastrear dicha causa… Si no lo has hecho hasta ahora, no busques sólo en castellano, hazlo también en inglés. Y utiliza portales especializados (p.ej.: StackOverflow.com) y grupos de discusión (Google Groups).

10) No te quedes parado tras pedir ayuda. Informa de avances en tu búsqueda y pruebas. Sigue investigando por tu cuenta. Pregunta en distintos foros siguiendo las normas de lanzar consultas técnicas sobre errores de programación de este mismo decálogo y si encuentras alguna pista más, infórmame de la misma.

Un «bonus» consejo más: cuida tu ortografía, gramática y expresión en los mensajes de texto que envíes. Pero de esos puntos ya hablé aquí en Enero y Diciembre de 2009, así que te recomiendo encarecidamente su lectura.

Quedo a la espera de tu respuesta.

Visualizando un grafo de dependencias en PHP

Receta rápida para visualizar un grafo de dependencias en PHP, como el que acompaña a este post (pincha sobre la imagen para hacer zoom sobre ella). Se trata del grafo de dependencias PHP de la aplicación Babelium Project, pero piensa que el objetivo es aprender a generar un grafo como éste de cualquier aplicación que te interese.

En concreto, queremos ver gráficamente qué ficheros incluyen a qué otros (con include, require o require_once). Para ello, haremos uso de la extensión «inclued» (sí, al parecer es un juego con las letras de include).

$ sudo pear install inclued-beta

Configuramos a continuación el fichero php.ini para activar la extensión, añadiendo esta línea

extension=inclued.so

y en la parte inferior del mismo fichero, una variable de configuración:

[inclued]
inclued.enabled = On

Ahora reiniciamos Apache para que coja los cambios:

$ sudo /etc/init.d/apache2 restart

Editamos la página inicial (index.php o similar) de la aplicación de la queremos obtener el grafo, y añadimos al final lo siguiente:

// File to store the inclued information
$fp = fopen('/tmp/wp.ser', 'w');
if ($fp) {
    $clue = inclued_get_data();
    if ($clue) {
        fwrite($fp, serialize($clue));
    }
    fclose($fp);
}

Esto generará un fichero /tmp/wp.ser con información serializada de los includes y requires que carga index.php y sus ficheros dependientes (es decir, el análisis se hace de forma recursiva)

Sólo falta un paso: usar graphviz para generar un fichero .dot que luego podremos convertir a .png con la utilidad dot.

# creamos el dot
$ php graphviz.php -i /tmp/wp.ser -o wp.dot
# lo convertimos a png
$ dot -Tpng -o inclued.png wp.dot

Forma tu propia nube de palabras (wordcloud) con R

Una receta rápida para que no se me traspapele 🙂 El siguiente script en R lee un fichero de texto (/tmp/article.txt), lo analiza y genera una vistosa nube de palabras. Depende de los paquetes tm (text mining), RColorBrewer (para la gestión de paletas de color) y wordcloud (el verdadero artífice de la nube final). En la imagen que acompaña a este artículo se muestra la nube de palabras correspondiente al Plan vasco de Ciencia, Tecnología e Innovación 2015 (PCTi2015). Esa imagen es el resultado de ejecutar el código R objeto de este post (se genera en /tmp/cloud.png).
Quedaría ver cómo añadir el código que falta para deshacerse de los adverbios, preposiciones y demás hierbas mayores de 4 letras…

require(tm)
require(wordcloud)
require(RColorBrewer)
 
 
r <- paste(readLines(file.path("/tmp","article.txt")), collapse=' ')
r <- gsub("[ft.,;:`'\"\(\)<>]+", " ", r)
words <- tolower(strsplit(r, " +")[[1]])
 
words <- table(words)
# remove words with _bad_ chars (non utf-8 stuff)
words=words[nchar(names(words), "c")==nchar(names(words), "b")]
# remove words shorter then 4 chars
words=words[nchar(names(words), "c")>3]
# remove words accuring less than 5 times
words=words[words>4]
 
# create the image
png("/tmp/cloud.png", width=580, height=580)
pal2 <- brewer.pal(8,"Set2")
wordcloud(names(words), words, scale=c(9,.1),min.freq=3,
           max.words=Inf, random.order=F, rot.per=.3, colors=pal2)
dev.off()

Openshift: computación gratuita en la nube de RedHat

OpenShift Express es una plataforma (PaaS) gratuita para el despliegue de aplicaciones en la nube proporcionada por RedHat. En ella podremos desplegar aplicaciones Java, Perl, PHP, Python y Ruby.  Además, permite la instalación (también gratuita) de un servidor de bases de datos como MySQL, Postgres o MongoDB.  El procedimiento es bastante simple: al abrir una cuenta, OpenShift te generará una URL única para tu aplicación y un repositorio git asociado.  Tus desarrollos se guardarán en git de tal forma que al hacer git push , automáticamente, aparte de subir tus cambios al repositorio remoto, estarás dando una orden de despliegue de la aplicación (internamente lo hace a través de hooks o ejecución de scripts ante eventos como un git push)

Dejo esbozados aquí los pasos necesarios para crear una cuenta, desplegar tu propia BBDD MySQL y subir un pequeño script PHP que hace uso de dicha base de datos:

1) Darte de alta en OpenShift Express (existe otra modalidad de pago, llamada Openshift Flex, para usuarios con necesidades más avanzadas)

2) Entrar en el panel de control de Express

3) Crear un namespace (la URL de tus aplicaciones siempre serán del tipo  nombreaplicacion-namespace.rhcloud.com). En la imagen superior he creado un namespace = babelium

4) Crear una aplicación de tipo Java, PHP, Python, Ruby o Perl. En mi ejemplo el nombre de la aplicación es «demo» (tras mucho estrujarme los sesos 😉 y se trata de una aplicación PHP.

Como puede verse en la imagen, tras el paso 4 se creará un repo git en la dirección ssh://xxxxxx@demo-babelium.rhcloud.com/~/git/demo.git/

5) Opcional: para poder acceder por ssh a nuestra instancia (sí! tenemos acceso ssh gratuito!) subimos la parte pública de nuestra clave RSA ( normalmente la tendrás situada en  ~/.ssh/rsa_id.pub )

6) Clonamos el repo git del paso 4

$ cd /opt
$ git clone ssh://xxxxxx@demo-babelium.rhcloud.com/~/git/demo.git
$ ls -al demo
-rw-r--r--  1 juanan juanan      0 2012-01-25 17:43 deplist.txt
drwxr-xr-x  8 juanan juanan   4096 2012-01-25 17:43 .git
drwxr-xr-x  2 juanan juanan   4096 2012-01-25 17:43 libs
drwxr-xr-x  2 juanan juanan   4096 2012-01-25 17:43 misc
drwxr-xr-x  4 juanan juanan   4096 2012-01-25 17:43 .openshift
drwxr-xr-x  2 juanan juanan   4096 2012-01-25 17:43 php
-rw-r--r--  1 juanan juanan   1315 2012-01-25 17:43 README

Bien… ¿me sigues? Ok, los pasos que he comentado hasta ahora (crear namespace, nombre de aplicación, asociar la aplicación a un entorno PHP, etc. se puede hacer desde la línea de comandos. Para ello, debes instalar las utilidades rhc (RedHat Cloud) que son scripts en Ruby (gemas) para control remoto de las aplicaciones en Openshift. Desde Ubuntu basta con que hagas:

sudo gem install rhc
PATH=$PATH:/usr/lib/ruby/gems/1.9.2/gems/rhc-0.84.15/bin/

Ojo con el path, igual en tu máquina las gemas rhc no se instalan exactamente en la misma ruta, ¡échale un vistazo antes!

¿Por dónde íbamos? Ah! sí, por el paso 7 🙂

7) Bien, vamos a instalar soporte MySQL en nuestro entorno. Para ello, ahora sí desde la línea de comandos, porque el panel de control por ahora no ofrece la opción de hacerlo vía point&click:

/opt/demo$ rhc-ctl-app -a "demo" -e add-mysql-5.1 -l usuario@dominio.com
RESULT: Mysql 5.1 database added.  
Please make note of these credentials:    
Root User: xxxxxxxx  
Root Password: xxxxxxxxxxx   
Database Name: demo 
Connection URL: mysql://127.1.48.1:3306/ 
You can manage your new Mysql database by also embedding phpmyadmin-3.4.

Olé! MySQL 5.1 instalado por la patilla… y ¿qué es eso de que incruste phpmyadmin? No me digas que también lo tengo por el mismo precio! Pues así es amigos… 🙂 De hecho, tengo varios cartuchos (cartridges le llaman en RHC) disponibles:

$ rhc-ctl-app -a "demo" -L
List of supported embedded cartridges:
 
Obtaining list of cartridges (please excuse the delay)...
postgresql-8.4, metrics-0.1, mysql-5.1, jenkins-client-1.4, 10gen-mms-agent-0.1, phpmyadmin-3.4, rockmongo-1.1, mongodb-2.0

Olé y olé… jenkins… mmmmmhhh… eso lo dejo para otro día 🙂 Por ahora vamos a instalar phpmyadmin.

$ rhc-ctl-app -a "demo" -e add-phpmyadmin-3.4 -l usuario@dominio.com

Acabamos de enganchar a nuestra aplicación demo un phpmyadmin-3.4 . Para los que se acuerden de artículos anteriores de DiarioLinux, esa sintaxis le sonará al entorno juju de Ubuntu. El login y pass será el mismo que te han dado para MySQL. La URL de acceso también la tendrás al ejecutar el comando anterior.

Nota: teniendo phpMyAdmin, crear las tablas en la BBDD es trivial. Pero existen otras formas de hacerlo (sin usar phpMyAdmin). Una de ellas en entrar por ssh a tu instancia y crear las tablas desde la línea de comandos mysql, pero otra forma más elegante es usar un hook de git. En concreto, en tu repo tendrás un directorio .openshift, y dentro del mismo un subdirectorio llamado action_hooks. Lo que hay ahí son scripts que se ejecutan en distintos momentos tras hacer un git push. El script deploy es el más adecuado para generar tus tablas y poblar con tuplas las mismas. Edita ese script (/opt/demo/.openshift/action_hooks) así (gracias a schabell.org por enseñarnos a hacerlo):

#!/bin/bash
# This deploy hook gets executed after dependencies are resolved and the
# build hook has been run but before the application has been started back
# up again.  This script gets executed directly, so it could be python, php,
# ruby, etc.
set -e
 
if [ -z $OPENSHIFT_DB_HOST ]
then
    echo 1>&2
    echo "Could not find mysql database.  Please run:" 1>&2
    echo "rhc-ctl-app -a $OPENSHIFT_APP_NAME -e add-mysql-5.1" 1>&2
    echo "then make a sample commit (add whitespace somewhere) and re-push" 1>&2
    echo 1>&2
    exit 5
fi
 
# check for database.
if ! /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" -e "show tables;" $OPENSHIFT_APP_NAME > /dev/null
then
    echo 1>&2
    echo "Could not find mysql database. " 1>&2
    echo "Creating database for application named: $OPENSHIFT_APP_NAME." 1 >&2
    /usr/bin/mysqladmin -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" create "$OPENSHIFT_APP_NAME"
fi
 
# Confirm database exists, if not create it
if ! /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" -e "select * from guesses;;" "$OPENSHIFT_APP_NAME" > /dev/null
then
    echo
    echo "Schema not found!  Importing schema from .openshift/action_hooks/baby.sql"
    echo
    /usr/bin/mysql -u "$OPENSHIFT_DB_USERNAME" --password="$OPENSHIFT_DB_PASSWORD" -h "$OPENSHIFT_DB_HOST" "$OPENSHIFT_APP_NAME" < "$OPENSHIFT_REPO_DIR/.openshift/action_hooks/baby.sql"
    echo
    echo "done."
else
    echo "Database found, skipping import."
fi

Como ves existen algunas variables de entorno predefinidas: $OPENSHIFT_DB_HOST (dirección del host que alberga tu MySQL), $OPENSHIFT_DB_NAME (nombre de la base de datos de tu aplicación), etc. Como digo son variables predefinidas, ya tienen el valor correcto asignado sin que tú hagas nada. El script bash anterior, lo que hace es comprobar que tienes mysql instalado en OpenShift (y en caso de no tenerlo lo instala), que tienes la BD instalada (si no, la crea también) y que la has cargado con tuplas (y si no, la carga, leyendo del dump baby.sql situado en el mismo directorio que el script). El dump baby.sql lo tienes que crear previamente, claro, con instrucciones SQL de creación de tablas e inserción de tuplas. Por ejemplo:

USE babygame;

DROP TABLE IF EXISTS guesses;
CREATE TABLE guesses
(
	timestamp timestamp,
	name varchar(50) NOT NULL,
	email varchar(50) NOT NULL,
	birthdate timestamp,
	birthsex varchar(4) NOT NULL,
	babyname varchar(100),
	PRIMARY KEY (timestamp, name)
);

Tus scripts en PHP serán como siempre han sido, no hay ningún cambio salvo las variables de entorno predefinidas que en un entorno php «normal» no existen y en Openshift sí. Por tanto, en la carpeta /opt/demo/php podrías crear un script php para conectar con tu BBDD:

define( "DB_SERVER",    $_ENV['OPENSHIFT_DB_HOST'] );
define( "DB_USER",      $_ENV['OPENSHIFT_DB_USERNAME'] );	
define( "DB_PASSWORD",  $_ENV['OPENSHIFT_DB_PASSWORD'] );	
define( "DB_DATABASE",  "demo" );	
$connect = mysql_connect( DB_SERVER, DB_USER, DB_PASSWORD );
@mysql_select_db( DB_DATABASE, $connect ) or die( "Unable to select database");
// etc...

Ahora, desde la línea de comandos lanzas un «git push» y verás como el servidor despliega tu aplicación, ejecuta el script de creación de tablas y tuplas mysql (creándolas en caso necesario) y te deja la URL lista para ser usada: http://demo-babelium.rhcloud.com/

Espero que no os guste demasiado este post, no vaya a ser que OpenShift se sature 😉
[Nota: ha sido un post largo y con aplicación práctica inmediata, para compensar el mes largo sin actualizaciones 😉 ]