En el capítulo anterior creamos un programa de ejemplo con unos requerimientos específicos con la intención de ejecutarlo periódicamente de forma automática.
Ahora que tenemos nuestro programa funcionando, vamos a ponerlo a funcionar bajo linux.
La idea es crear un script del shell para llamar a nuestro programa, hacer algunas verificaciones y enviar el reporte resultante por correo.
Verificaciones previas
Correo
Para este proyecto utilizaremos Sendmail, que se instala con casi todas las distribución de linux mas conocidas. Cómo configurar sendmail escapa del objetivo de este artículo, hay un montón de artículos al respecto en la red.Podemos enviar un mensaje de prueba con el siguiente comando:
echo -e "Subject: ping \n\nthis goes on the body" | sendmail -f micuenta@dominio.com otracuenta@gmail.com
Verificamos si tenemos java instalado
Para distribuciones basadas en Debian utilizamos el siguiente comando:dpkg --get-selections | grep openjdk
Para distribuciones que utilizan RPM utilizamos esto:
rpm -qa | grep openjdk
Copiar archivos al servidor
A los efectos de nuestro proyecto crearemos una carpeta chequeodesatendido en /opt, aunque no es obligatorio y podría ir en otro lugar, por ejemplo en /usr/local o /usr/lib.Ahora debemos copiar nuestro programa a la caja linux, personalmente utilizo WinSCP. En realidad no necesitamos copiar todos los archivos que nos creó el Deployment Wizard, solo necesitamos las carperas Shared y chequeodesatendido.
Pruebas preliminares
Ya tenemos todo lo necesario para empezar a probar nuestro programa. Creamos un archivo llamado test.sh y le agregamos el siguiente código:#!/bin/bash # get current date with file name friendly format FECHA=`date +"%Y-%m-%d_%H-%M"` # output file ARCHIVO_SALIDA=cr_$FECHA # output folder DIRECTORIO_SALIDA="$PWD/reportes" GXCLASSPATH="Shared/.:Shared/gxclassp.jar:Shared/iText.jar:chequeodesatendido/chequeodesatendido_GXWS.jar" HOY=`date +"%d/%m/%y"` java -cp $GXCLASSPATH achequeodesatendido "$HOY" "$HOY" "$DIRECTORIO_SALIDA/$ARCHIVO_SALIDA" $> "$DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log"
En este script la variable FECHA captura la fecha y la hora del sistema, a diferencia del script que utilizamos bajo windows que solo capturaba la fecha.
Atender que la lista GXCLASSPATH bajo linux debe estar separada por ":" mientras que bajo windows va separada por ";"
La variable HOY es nueva en este script y es simplemente la fecha del sistema en el órden y formato que espera nuestro programa.
Atender que la lista GXCLASSPATH bajo linux debe estar separada por ":" mientras que bajo windows va separada por ";"
La variable HOY es nueva en este script y es simplemente la fecha del sistema en el órden y formato que espera nuestro programa.
Ejecutamos la prueba:
sh test.sh
Como en el capítulo anterior, deberíamos tener un PDF en la carpeta reportes.
El script definitivo
Creamos un script llamado run.sh y le agregamos el siguiente código:#!/bin/bash #cambiamos al directorio base cd /opt/chequeodesatendido FECHA=`date +"%Y-%m-%d_%H-%M"` ARCHIVO_SALIDA="cr_$FECHA" DIRECTORIO_SALIDA="$PWD/reportes" GXCLASSPATH="Shared/.:Shared/gxclassp.jar:Shared/iText.jar:chequeodesatendido/chequeodesatendido_GXWS.jar" # a quien notificar LISTA_NOTIFICACION="destino1@dominio.com" # si tenemos mas de un destinatario, separar cada uno con un espacio #LISTA_NOTIFICACION="destino1@dominio.com destino2@dominio.com destino3@dominio.com" REMITENTE='verificador@dominio.com' SEPARADOR="$$-$$-$$-" # tamaño de la carpeta TAMANHO_ACTUAL=`du -h $DIRECTORIO_SALIDA` enviar_mail() { local DIRECCION_CORREO local REPORTE local ERRORES local FECHA_LINDA # codificamos el reporte en base64 y lo cargamos en una variable. esto va # a ir como un atado al mensaje. REPORTE=`base64 $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.pdf` # recuperamos las lineas del log en otra variable, estas no van a ir como # atado sino en el cuerpo del texto. ERRORES=`cat "$DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log"` # podemos filtrar las lineas, por ejemplo para ignorar advertencias o depuración. #ERRORES=`cat $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log | grep "Errores:"` # fecha en formato mas amigable FECHA_LINDA=`date +"%d/%m/%Y %H:%M"` # enviamos un mensaje por cada dirección de la lista de notificación. # también se podría enviar un solo mensaje con las direcciones en CC. for DIRECCION_CORREO in $DIRECCION_NOTIFICACION; do /usr/sbin/sendmail -f $REMITENTE -t <<EOF MIME-Version: 1.0 To: $DIRECCION_CORREO From: $REMINTENTE Subject: Verificación de consistencia - $FECHA_LINDA - $ERRORES Content-Type: multipart/mixed; boundary="$SEPARADOR" --$SEPARADOR Content-Type: text/plain; charset=UTF8; format=flowed content-transfer-encoding: 8bit $ERRORES Reporte generado al $FECHA_LINDA Archivo adjunto: $ARCHIVO_SALIDA.pdf Tamaño actual del directorio: $ACTUAL_SIZE --$SEPARADOR Content-Type: application/pdf; name="$ARCHIVO_SALIDA.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="$ARCHIVO_SALIDA.pdf" $REPORTE --$SEPARADOR Content-Type: text/plain; name="$ARCHIVO_SALIDA.log" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="$ARCHIVO_SALIDA.log" `cat $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log` EOF done } # generar el reporte HOY=`date +"%d/%m/%y"` java -cp $GXCLASSPATH achequeodesatendido "$HOY" "$HOY" "$DIRECTORIO_SALIDA/$ARCHIVO_SALIDA" $> "$DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log" # si se generó el archivo de salida, lo enviamos. if [ -f $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.pdf ]; then echo "Existe $ARCHIVO_SALIDA" enviar_mail fi
Analicemos el script.
#!/bin/bash # cambiamos al directorio base cd /opt/chequeodesatendido FECHA=`date +"%Y-%m-%d_%H-%M"` ARCHIVO_SALIDA="cr_$FECHA" DIRECTORIO_SALIDA="$PWD/reportes" GXCLASSPATH="Shared/.:Shared/gxclassp.jar:Shared/iText.jar:chequeodesatendido/chequeodesatendido_GXWS.jar" # a quien notificar LISTA_NOTIFICACION="destino1@dominio.com" # si tenemos mas de un destinatario, separar cada uno con un espacio #LISTA_NOTIFICACION="destino1@dominio.com destino2@dominio.com destino3@dominio.com" REMITENTE='verificador@dominio.com' SEPARADOR="$$-$$-$$-" # tamaño de la carpeta TAMANHO_ACTUAL=`du -h $DIRECTORIO_SALIDA`
Hasta acá solo son definiciones de variables que utilizaremos mas tarde. SEPARADOR es un texto arbitrario que definiremos para separar las secciones del mensaje, explicaré eso mas adelante. Como siempre a modo de ejemplo en la variable TAMANHO_ACTUAL recuperamos el espacio en disco ocupado por los reportes y la incluiremos en el cuerpo del mensaje.
A continuación tenemos la función que construye y envía el mensaje de correo.
enviar_mail() { local DIRECCION_CORREO local REPORTE local ERRORES local FECHA_LINDA # codificamos el reporte en base64 y lo cargamos en una variable. esto va # a ir como un atado al mensaje. REPORTE=`base64 $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.pdf` # recuperamos las lineas del log en otra variable, estas no van a ir como # atado sino en el cuerpo del texto. ERRORES=`cat "$DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log"` # podemos filtrar las lineas, por ejemplo para ignorar advertencias o depuración. #ERRORES=`cat $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log | grep "Errores:"` # fecha en formato mas amigable FECHA_LINDA=`date +"%d/%m/%Y %H:%M"` # enviamos un mensaje por cada dirección de la lista de notificación. # también se podría enviar un solo mensaje con las direcciones en CC. for DIRECCION_CORREO in $DIRECCION_NOTIFICACION; do /usr/sbin/sendmail -f $REMITENTE -t <<EOF MIME-Version: 1.0 To: $DIRECCION_CORREO From: $REMINTENTE Subject: Verificación de consistencia - $FECHA_LINDA - $ERRORES Content-Type: multipart/mixed; boundary="$SEPARADOR" --$SEPARADOR Content-Type: text/plain; charset=UTF8; format=flowed content-transfer-encoding: 8bit $ERRORES Reporte generado al $FECHA_LINDA Archivo adjunto: $ARCHIVO_SALIDA.pdf Tamaño actual del directorio: $ACTUAL_SIZE --$SEPARADOR Content-Type: application/pdf; name="$ARCHIVO_SALIDA.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="$ARCHIVO_SALIDA.pdf" $REPORTE --$SEPARADOR Content-Type: text/plain; name="$ARCHIVO_SALIDA.log" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="$ARCHIVO_SALIDA.log" `cat $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log` EOF done }
Como nuestro archivo de salida es un archivo binario (PDF) no lo podemos incluirlo directamente, el mensaje de correo solo puede estar constituido por text ASCII. Para conseguir esto codificamos el archivo en base64 y separamos el mensaje en secciones, para eso nos servirá la variable SEPARADOR. En la primera sección pondremos el cuerpo del mensaje, en las siguientes colocamos los archivos "atados".
Veamos esto con mas detalle:
En la linea 47 tenemos Content-Type: multipart/mixed; boundary="$SEPARADOR", que dice que el mensaje está formado por varias partes, de tipos mezclados y que el 'límite' entre las secciones será el texto de SEPARADOR.
En la linea 49 definimos el límite de la primera sección, notese que todos los límites empiezan con dos signos menos seguidos: "--",
En las siguientes lineas tenemos:
Content-Type: text/plain; charset=UTF8; format=flowed content-transfer-encoding: 8bit
Define la sección como texto plano, utilizando set de caracteres UTF8 y que la codificación de la transferencia será de 8bits (http://www.freesoft.org/CIE/RFC/1521/5.htm).
Agregamos al texto del cuerpo algunas de los datos que habíamos colectado, ERRORES y TAMANHO_ACTUAL. En la linea 60 se define el límite de otra sección, esta vez el de nuestro archivo de salida binario. La cabecera de la sección está definida por:
Content-Type: application/pdf; name="$ARCHIVO_SALIDA.pdf" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="$ARCHIVO_SALIDA.pdf"
Definimos que el tipo de contenido va a ser application/pdf y el nombre del atado, se especifica que la codificación de transferencia será base64, que es un atado y el nombre de archivo sugerido al guardar. Y en la linea 65 colocamos el texto que goardamos en REPORTE.
Por último, en la linea 67 tenemos el límite de la última sección, seguido de la siguiente cabecera:
Content-Type: text/plain; name="$ARCHIVO_SALIDA.log" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="$ARCHIVO_SALIDA.log"
Como nuestro archivo de log está en formato texto, solo lo vamos a "volcar" a la sección con`cat $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log` y la cabecera especifica que es un atado.
Ahora nos encontramos con el código principal de nuestro script:
# generar el reporte HOY=`date +"%d/%m/%y"` java -cp $GXCLASSPATH achequeodesatendido "$HOY" "$HOY" "$DIRECTORIO_SALIDA/$ARCHIVO_SALIDA" $> "$DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.log" # si se generó el archivo de salida, lo enviamos. if [ -f $DIRECTORIO_SALIDA/$ARCHIVO_SALIDA.pdf ]; then echo "Existe $ARCHIVO_SALIDA" enviar_mail fi
A pesar de ser el código principal, no hay mucho que explicar aquí, formateamos la fecha actual de la forma que espera nuestro programa como parámetro, llamamos a nuestro programa y redirigimos la salida estandar al archivo de log.
Finalmente verificamos si el programa generó alguna salida y la enviamos por mail con la función que explicamos mas arriba.
Probamos nuestro script:
sh test.sh
Si todo fue bien, debemos de estar recibiendo un mail con nuestros archivos como atados.
Agendar para ejecución periódica
Tan solo nos falta programar una tarea con CRON para que se ejecute periódicamente nuestro autómata.
Ejecutamos crontab -e y agregamos la siguiente linea:
*/5 * * * * sh /opt/chequeodesatendido/run.sh
Guardamos la tarea (presionamos ESC, luego :w + ENTER, por último :q + ENTER para salir). A partir de ahora estaríamos recibiendo un correo electrónico cada 5 minutos con los resultados de nuestro programa como atado.
Bueno, hasta aquí esta segunda entrega de la serie.
Autómatas con Genexus Ev1 en Linux y Windows, y I
Bueno, hasta aquí esta segunda entrega de la serie.
Autómatas con Genexus Ev1 en Linux y Windows, y I