Como obtener el UNIX UID desde Java: Jugando con JNI

Java

Este es uno de esos experimientos que sale por la necesidad, ya que recientemente alguien en mi compañia me preguntó como hacer algo parecido y le dije que usando JNI. Sin embargo cuando me preguntó si alguna vez lo había hecho y respondí que no, y no quedó muy impresionado.

Así que me decidí a tomar cartas en el asunto, y decidí escribir un pequeño programa que obtiene el UNIX PID y el PPID de un programa en Java, para ver como es el asunto. Como ustedes recordarán, el PID (Program Id) de un programa en UNIX no es más que un identificador único que una aplicación tiene en la tabla de procesos del sistema operativo cuando es ejecutada. El Parent Program Id no es más que el PID del programa que llamó a la aplicación actual.

Java no sabe nada de eso ya que es una caracteristica propia del sistema operativo en donde corre el programa, por lo cual usamos un poco de JNI para obtener el valor.

Para más detalles de como funciona la llamada nativa, solamente hagan lo siguiente:

[josevnz@localhost test]$ man getpid

Existen muy buenos tutoriales en la red, entre ellos un libro completo y otro procedimiento que detalla pasos especificos con el sistema operativo Linux. Mi intención no es escribir un tutorial sino mostrarles algunas piezas de código que considero interesantes.

Terminado este preambulo, vamos a escribir el código; lo primero es declarar una clase en Java la cual define dos métodos nativos, los cuales tendrán una implementación en C:

   1:package com.kodegeek.blog.unix;
2:
3:/**
4: * Native access to pid and ppid process information under UNIX.
5: * @author josevnz
6: * @version 0.1 - 09/04/2006
7: */
8:public final class UnixPid {
9:
10: static {
11: System.loadLibrary("unix");
12: }
13:
14: /**
15: * Class constructor
16: */
17: public UnixPid() {
18: super();
19: }
20:
21: /**
22: * Get the program UNIX id
23: * @return int
24: */
25: public native int getPid();
26:
27: /**
28: * get the program parent id
29: * @return int
30: */
31: public native int getPpId();
32:
33: /**
34: * Run the class from the command line. Test case
35: * @param args
36: * @throws Exception If the thread is interrupted
37: */
38: public static void main(String[] args) throws Exception {
39: UnixPid instance = new UnixPid();
40: System.out.println("PID: " + instance.getPid());
41: System.out.println("PPID: " + instance.getPpId());
42: Thread.sleep(300);
43: }
44:}

Nada complicado, cargamos la librería compartida (Linea 11, .so) en una declaración estática para garantizar que esta lista antes que cualquiera de los métodos sea llamado. Los métodos nativos (lineas 25 y 31) se declaran aqui.

Después vienen un par de pasos más o menos automaticos:

  • Compilar el código en Java
  • Crear el archivo .h de nuestra librería, usando javah en base al código compilado de Java
  • Implementar los métodos en C
  • Compilar el código en C, creando una librería compartida
  • Poner la librería en la ruta del LD_LIBRARY_PATH
  • Correr el programa y celebrar

Dado que soy muy perezoso, me decidí a escribir una tarea en Ant que hace todo el trabajo. Les coloco el archivo con sólo los pedazos importantes:

   1:<?xml version="1.0" encoding="ISO-8859-1"?>
2:<project
3: name="Unix"
4: default="build"
5: basedir=".">
6: <description>Access to native facilities using Java and
JNI</description>
7: <property description="Global properties" file="build.properties"/>
8:
9: <property description="Load any environment variables into Ant"
environment="env"/>
10:.......
48:
49: <target
50: name="build"
51: depends="init"
52: description="Compile the Java and native source code">
53: <javac
54: srcdir="${src.java}/main"
55: destdir="${build}"
56: deprecation="true"
57: optimize="false"
58: debug="true">
59: <include name="com/kodegeek/blog/unix/**/*.java"/>
60: <classpath refid="path.classpath"/>
61: </javac>
62:
63: <copy
64: todir="${build}" overwrite="true">
65: <fileset dir="${properties}/main">
66: <include
name
="com/kodegeek/blog/unix/**/*.properties"/>
67: </fileset>
68: </copy>
69:
70: <javah
71: class="com.kodegeek.blog.unix.UnixPid"
72: force="yes"
73: outputfile="${build}/include/UnixPid.h">
74: <classpath refid="path.classpath"/>
75: </javah>
76:
77: <exec
78: executable="make"
79: failonerror="true">
80: <arg value="-f"/>
81: <arg file="Makefile"/>
82: <arg value="INCLUDES=${native.include}"/>
83: <arg value="JAVA_HOME=${java.home}"/>
84: <arg value="SHARED_UNIX=${native.shared}"/>
85: <arg value="SRC=${src.cpp}/${ant.project.name}"/>
86: <arg value="DIST=${dist}"/>
87: <arg value="all"/>
88: </exec>
89:
90: </target>
91:
92: ....
110:
111: <target
112: name="jar"
113: depends="build"
114: description="Pack the project sources for distribution">
115:
116: <manifest file="${jar.file.manifest}">
117: <section name="${ant.project.name}/">
118: <attribute name="Built-By" value="${user.name}"/>
119: <attribute name="Sealed" value="true"/>
120: </section>
121: <attribute name="Main-Class"
value
="com.kodegeek.blog.unix.UnixPid"/>
122: </manifest>
123:
124: <jar
125: jarfile="${jar.file}"
126: basedir="${build}"
127: description="build the jar file"
128: excludes="**/include/**"
129: manifest="${jar.file.manifest}">
130: </jar>
131:
132: <delete file="${jar.file.manifest}" quiet="true"/>
133: </target>
134:
135:...
174:
175:</project>

Cuando generamos los encabezados en C (UnixPid.h), obtenemos algo como esto, a partir de la clase de Java:

   1:/* DO NOT EDIT THIS FILE - it is machine generated */
2:#include <jni.h>
3:/* Header for class com_kodegeek_blog_unix_UnixPid */
4:
5:#ifndef _Included_com_kodegeek_blog_unix_UnixPid
6:#define _Included_com_kodegeek_blog_unix_UnixPid
7:#ifdef __cplusplus
8:extern "C" {
9:#endif
10:/*
11: * Class: com_kodegeek_blog_unix_UnixPid
12: * Method: getPid
13: * Signature: ()I
14: */
15:JNIEXPORT jint JNICALL Java_com_kodegeek_blog_unix_UnixPid_getPid
16: (JNIEnv *, jobject);
17:
18:/*
19: * Class: com_kodegeek_blog_unix_UnixPid
20: * Method: getPpId
21: * Signature: ()I
22: */
23:JNIEXPORT jint JNICALL Java_com_kodegeek_blog_unix_UnixPid_getPpId
24: (JNIEnv *, jobject);
25:
26:#ifdef __cplusplus
27:}
28:#endif
29:#endif

Sin embargo la parte realmente interesante es la conexión del código nativo con Java. Eso lo hacemos en el archivo .C en donde vamos a implementar las declaraciones de los metodos nativos (copiados del archivo UnixPid.h):

   1:#include <jni.h>
2:#include <unistd.h>
3:#include <sys/types.h>
4:#include "UnixPid.h"
5:
6:/**
7: * Provides native access to the PID access of the current
8: * Java process.
9: * man getpid, getppid - get process identification
10: * @author josevnz@kodegeek.com
11: */
12:
13:/*
14: * Class: com_kodegeek_blog_unix_UnixPid
15: * Method: getPid
16: * Signature: ()I
17: */
18:JNIEXPORT jint JNICALL Java_com_kodegeek_blog_unix_UnixPid_getPid
19: (JNIEnv *, jobject) {
20: jint pid = getpid();
21: return pid;
22:}
23:
24:/*
25: * Class: com_kodegeek_blog_unix_UnixPid
26: * Method: getPpId
27: * Signature: ()I
28: */
29:JNIEXPORT jint JNICALL Java_com_kodegeek_blog_unix_UnixPid_getPpId
30: (JNIEnv *, jobject) {
31: jint ppid = getppid();
32: return ppid;
33:}
34:

La parte complicada es el manejo de los tipos de java versus los tipos de C. Sin embargo como estas rutinas lo que retornan son enteros entonces no hay mucho rollo (son tipos primitivos, no apuntadores).

Me decidí escribir un archivo GNU Make para controlar la compilación del código nativo en C, ya que Make esta mucho mejor dotado que Ant para estas tareas. Lo único que hice fué pasarle parametros desde Ant (cosas obvias como la ubicación de los archivos ya que eso se controla desde allí):

   1:# Native portion of the FileType, UnixPid classes
2:#
3:# Author: josevnz@kodegeek.com
4:#
5:# The following variables are defined from Ant:
6:# - SHARED_UNIX
7:# - INCLUDES
8:#
9:# Also this makefile is tailored to run on Linux
10:#
11:
12:CFLAGS=-c -I$(INCLUDES) -I$(JAVA_HOME)/../include
-I$(JAVA_HOME)/../include/linux -Wall -fPIC
13:LDFLAGS=-shared -static -lc
14:
15:all:
16: g++ $(CFLAGS) $(SRC)/UnixPid.C -o $(DIST)/UnixPid.o
17: g++ $(LDFLAGS) -o $(SHARED_UNIX) $(DIST)/*.o
18: rm -f $(DIST)/*.o

Una vez compilado el programa (todo lo hacemos desde Ant), lo corremos:

[josevnz@localhost kodegeek]$ export LD_LIBRARY_PATH=/home/josevnz/sf/kodegeek/dist/Unix
[josevnz@localhost kodegeek]$ java -jar /home/josevnz/sf/kodegeek/dist/Unix/Unix.jar
PID: 5737
PPID: 17896
[josevnz@localhost kodegeek]$

Ya para finalizar los dejo con un enlace a el código fuente completo, así como los binarios.

Buscar en Technorati: , , ,
Buscar en Blogalaxia: , , ,

Reconocimiento al talento: Radioaficionados en Mérida

Racimo de ideas
Un racimo de ideas, por pequeño que parezca, sigue siendo un racimo de ideas

Mi papá (José Vicente viejo) y Nestor (un amigo muy querido quien ya no está por desgracia con nosotros) siempre estuvieron experimentando, tratando de probar nuevos limites; Hoy en día todo el mundo habla de conexiones por inalambricas como cualquier cosa, pero hace sólo unos 15 años atrás era asunto de gente dedicada, la cual gastaba su dinero en repetidoras (una de ellas en el pico del aguila), compilando kernel especiales instalaciones Linux como Slackware y jugando con todo tipo de bandas de radio.

Yo he sido un radioaficionado de pacotilla, ya que si bien presenté miexamen cuando era mucho más joven (menor de edad y por si le interesa mis siglas son YV2-GEE), en cambio estos dos señores (y otros amigos más que mencionaré más adelante) si se dedicaron a esto mucho mas en serio, logrando resultados interesante.

Aqui les dejo un articulo por partes publicado en Mérida por mi papá hace unos años (no recuerdo el periodico), estoy seguro que despertará su interés y le dará una perspectiva de como un grupo de pioneros jugaron con la tecnología cuando nadie creia en ella, fué motivo del primer enlace Merida-Caracas, a traces de los nodos de La Aguada-El Aguila-Caracas (El Junquito):

Papá, si estas leyendo esto, ¿tienes por allí fotos de la aguada que quieras compartir? 🙂

Buscar en Technorati: , , ,
Buscar en Blogalaxia: , , ,

¿Los últimos días de Veneblogs?

blackberry
¿Le llegó la hora a Veneblogs?

Veneblogs está caido. Ha estado caido por lo menos la última semana y es que el blog tiene problemas existenciales. Afrael, el cerebro detrás del producto explica que Veneblogs debe evolucionar o morir.

Y es que el peso de su propio exito lo está aplastando. Otros sitios como Blogalaxia se comen el pastel mientras que Veneblogs ya por varios meses no ha agregado nueva funcionalidad y comenzó a poner banners (los cuales quizas no están pagando las cuentas).

Yo soy de los que cree que Veneblogs, en su forma actual, debe morir. Si, sin remordimientos ni pataleos. Sin prestar atención al clamor o llanto de los miles de parasitos que lo utilizan sin pagar un centavo pero exigen que el sitio web este arriba para poder hacerle ping mientras sus blogs (los cuales viven gratis sin pagar un centavo de hospedaje o dominio en DNS) continuan existiendo.

La idea de Veneblogs debe moverse en otra dirección. Como experimiento fué interesante, pero la realidad tiene cara dura y algunos cambios de rigor son necesarios:

  • Veneblogs debe ser global: Venezuela cuenta con apenas 25+ millones de personas, de los cuales quizas 2 millones son quienes tienen accesso a Internet. Es muy poca gente para asegurar un crecimiento sostenible, el nuevo blog debe ser atractivo a toda Latinoamerica, el mundo (Internet no conoce fronteras). Venezuela no debe desaparecer en este sabor, es sólo que ahora el directorio debe abrirle espacio al resto del mundo.
  • Cobrar por el servicio: El sistema de hacer ping no garantiza que la gente pagará por el servicio, pero ofrecer otros servicios (como hacer pings a otros directorios) entre otras cosas si. ¿El precio? grátis para las cosas más basicas, pero para lo que vale la pena hay que pagar. ¿No te gusta? No tengas un blog en Veneblogs y pon tu rancho grátis en otro lado, hay demasiados blogs de todos modos 🙂
  • Debe ser manejado como un negocio y no por un grupo de panas: El servicio ha sido criticado duramente ya que pareciera ser manejado por un grupo de panas. Por ser en este momento un servicio gratuito eso está bien, pero si quieren convertirlo en una fuente de ingresos entonces deben manejarlo como una empresa (si adios a los famosos Rumblogs y su polemica, al menos que se cobre por eso y deje de ser una fiesta de “panas”). Un plan de negocios, buscar inversores y establecer metas serias no le caeria mal. No me malentiendan: La camadería aún puede existir, es sólo que Veneblogs debe definir su personalidad.

Este sitio web es uno de los pocos que trato con cariño. Si bien yo he tenido paginas web desde al menos 1995 (con el Angel Negro en el sitio web de mi universidad) aún recuerdo como Ximena me invitó a formar parte de esta comunidad y lo interesante de todos sus participantes.

Sin embargo la hora de cambiar o quedarse en el aparato le llegó a Veneblogs. Yo apuesto a que lo convertiran en un negocio interesante.

Buscar en Technorati: ,
Buscar en Blogalaxia: ,

Echando código: ¿Monitoreando servicios RPC usando Java, ONC RPC y el protocolo Jabber? (II)

java rpc
El taxista se encargó de decirle a su novia, y esta regó el cuento por allí…

En una primera parte les comentaba como hablar con NFS y a Rstatd desde Java usando RPC. Ahora vamos a terminar la aplicación enviando mensajes usando Jabber.

El protocolo de Jabber es muy completo. Sin embargo con esas características viene la complejidad, así que decidí tomar un atajo y en vez de complicarme la vida viendo como trabaja el protocolo me decidí a usar las libreria Smack (JiveSoftware, OpenSource). Como este articulo no se trata de como instalar un servidor de Jabber entonces vamos a utilizar una cuenta de Google Talk la cual habla el protocolo abierto XMPP .

No me gusta guardar ni usuarios ni passwords en el código, y mucho menos si el código va a estar en Internet :), así que modificamos un poco el archivo build.xml para leer un nuevo archivo de propiedades el cual tendrá los parametros requeridos para esta prueba.

Bueno, y el código super sencillo para probar la parte de la mensajería:


–>

 

1:package com.kodegeek.blog.monitoring.rpc;   
2:   
3:import org.jivesoftware.smack.Chat;   
4:import org.jivesoftware.smack.XMPPConnection;   
5:   
6:import junit.framework.Assert;   
7:import junit.framework.TestCase;   
8:   
9:  
10:public class TestJabber extends TestCase {  
11:     
12:     
13:        protected void setUp() throws Exception {  
14:                super.setUp();  
15:        }  
16:  
17:        /**  
18:         * Test the basic functionality of the Smack API  
19:         */  
20:        public void testJabber() {  
21:                XMPPConnection conn = null;  
22:                Chat chat = null;  
23:             
24:                try {  
25:                        Assert.assertNotNull("Please setup the address for the Google talk server",System.getProperty("jabber.talk.server"));  
26:                        Assert.assertNotNull("Please setup the receiving user for the Google talk server",System.getProperty("jabber.talk.port"));  
27:                        Assert.assertNotNull("Please setup the send address for the Google talk server",System.getProperty("jabber.talk.send.user")); 
28:                        Assert.assertNotNull("Please setup the send password for the Google talk server",System.getProperty("jabber.talk.send.password"));  
29:                        Assert.assertNotNull("Please setup the receiving user for the Google talk server",System.getProperty("jabber.talk.rec.user"));  
30:                     
31:                        conn =  
32:                                new XMPPConnection(  
33:                                System.getProperty("jabber.talk.server"),  
34:                                Integer.parseInt(System.getProperty("jabber.talk.port")));  
35:                     
36:                        Assert.assertNotNull("XMPPConnection is null", conn);  
37:                        Assert.assertTrue("We could not connect to the server", conn.isConnected());  
38:                     
39:                        conn.login(  
40:                               System.getProperty("jabber.talk.send.user"),  
41:                               System.getProperty("jabber.talk.send.password"));  
42:                        Assert.assertTrue("Could not authenticate",conn.isAuthenticated());  
43:                     
44:                        chat = conn.createChat(System.getProperty("jabber.talk.rec.user"));  
45:                        Assert.assertNotNull("Jabber Chat is null", chat);  
46:                     
47:                        /**  
48:                         * This is VERY important. If you don wait a little bit then the message will not  
49:                         * be sent.  
50:                         */  
51:                        Thread.sleep(500);  
52:                        chat.sendMessage("Hey, this is a message from http://KodeGeek.com");  
53:  
54:                } catch (Throwable throwbl) {  
55:                        Assert.fail("Got an exception: " + throwbl.toString());  
56:                        throwbl.printStackTrace();  
57:                } finally {  
58:                        if (conn != null) {  
59:                                conn.close();  
60:                        }  
61:                }  
62:        }  
63:}

Aqui pueden ver como trabaja, una foto vale más que mil palabras:

jabbertest
Mandando mensajes a Jabber desde JUnit. En este caso una cuenta está en Jabber.org y la otra en talk.google.com

Si revizan el código fuente verán que tuve que poner un pequeño hack. Sin embargo no es un gran problema y la librería hace lo que promete.

Como siempre el código fuente y los binarios están disponibles para que jueguen con ellos. Espero esto les de algunas ideas de como monitorear sus servidores. En una última entrega les mostraré como poner todo junto.

Buscar en Technorati: , , , , ,
Buscar en Blogalaxia: , , , , ,

Echando código: ¿Monitoreando servicios RPC usando Java, ONC RPC y el protocolo Jabber? (I)

Java + ONRPC
La sabiduria de los taxistas

¿Que diria usted si yo le dijera que es posible hacer un sistema de monitoreo usando Java, ONCR RPC y el protocolo Jabber? Es mucho más sencillo de lo que usted cree y es algo que siempre quise hacer en la compañia en la cual trabajaba anteriormente (en la actual estoy trabajando similar, pero mucho más sofisticado :D) y nunca tuve tiempo de hacer.

Pero bueno, demasiada habladera de paja, veamos que hay que poner en orden:

  1. Asumimos que los servicios que queremos monitorear se basan en ONRC RPC. Ejemplo de ellos son NIS, NFS, Rusers, Rquota y en nuestro caso Rstatd que aunque es muchisimo más limitado que SNMP está presente en muchos servidores, corriendo de grátis 🙂
  2. ONRC RPC tiene unos archivos que describen como usar los servicios remoto, llamados ‘stubs’. Si alguna vez ha utilizado RMI el concepto le será familiar. Pero hay un problema, los ‘stubs’ son muy similares a el lenguaje C, por lo que necesitamos una herramienta que nos sirva como puente. Para ello usamos el compilador de remote tea: jrpcgen.jar.
  3. Una vez obtenidos las interfaces y clientes en Java entonces las compilamos y nos valemos de las librerias de comunicación provistas por remote tea (onrpc.jar).
  4. De allí armamos los programas que van a hacer la consulta por medio de RPC. Luego nos preocupamos de como enviar los datos usando Jabber.

Lo primero que hay que hacer es generar las interfaces. El precompilador jrpcgen no tiene una tarea de Ant, sin embargo nosotros nos valemos de un macro con el cual preparamos las fuentes. Note que primero limpiamos los archivos ‘.x’ utilizando al precompilador cpp y es allí cuando podemos usar a jrpcgen.

El macro en Ant es muy sencillo:

–>

 

62:        <!-- Special macro to enable the RPC stub generation -->
63:        <macrodef name="rpcgen">
64:                <attribute name="xfile"/>
65:                <attribute name="clientJavaFile"/>
66:                <sequential>
67:                        <!-- Preprocess the 'x' files -->
68:                        <exec
69:                                executable="/usr/bin/cpp">
70:                                <arg line="${rpc.include.local}/@{xfile}.x"/>
71:                                <arg line="${rpc.include.local}/@{xfile}.cpp"/>
72:                        </exec>
73:                        <!-- Cleanup remaining artifacts -->
74:                        <replaceregexp 
75:                                file="${rpc.include.local}/@{xfile}.cpp"
76:                            match="^#"
77:                            replace="//"
78:                            byline="true"/>
79:                        <!-- generate the Java classes -->
80:                        <java
81:                                classname="org.acplt.oncrpc.apps.jrpcgen.jrpcgen"
82:                                dir="${rpc.include.local}"
83:                                fork="true">
84:                                <classpath refid="path.classpath"/>
85:                                <arg value="-p"/>
86:                                <arg value="${package.tree}"/>
87:                                <arg value="-nobackup"/>
88:                                <arg value="-noserver"/>
89:                                <arg value="-verbose"/>
90:                                <arg value="-withcallinfo"/>
91:                                <arg value="-bean"/>
92:                                <arg value="-c"/>
93:                                <arg value="@{clientJavaFile}"/>
94:                                <arg value="-d"/>
95:                                <arg value="${stub}"/>
96:                                <arg value="@{xfile}.cpp"/>
97:                        </java>
98:                </sequential>
99:        </macrodef>

Una vez definido llamarlo es muy sencillo (note que primero generamos el código Java de las interfaces y luego más delante compilamos el código de la aplicación junto con el de las interfaces):

–>

 

101:        <target
102:                name="rpcstub"
103:                depends="init"
104:                description="Create the RPC Java stub objects">
105:                <copy
106:                        todir="${rpc.include.local}"
107:                        overwrite="true">
108:                        <fileset dir="${rpc.include.dir}">
109:                                <include name="*.x"/>
110:                                <include name="*.h"/>
111:                        </fileset>
112:                </copy>
113:                <rpcgen xfile="rstat" clientJavaFile="RstatClient"/>
114:                <rpcgen xfile="mount" clientJavaFile="MountClient"/>
115:                <rpcgen xfile="nfs_prot" clientJavaFile="NfsProtClient"/>
116:        </target>

La compilación no depende de la generación de las interfaces ya que estas se guardan en CVS y si por algunas razón cambian es entonces que volverán a ser creadas. Es decir, una vez creadas las interfaces solamente nos tenemos que preocupar por compilar:

–>

 

118:        <target 
119:                name="build"
120:                depends="init"
121:                description="Compile the Java source code">
122:                <!-- Compile the stub -->
123:                <javac 
124:                                srcdir="${stub}" 
125:                                destdir="${build}" 
126:                                deprecation="true" 
127:                                optimize="false"
128:                                debug="true">
129:                                <include name="**/*.java"/>
130:                                <classpath refid="path.classpath"/>
131:                </javac>
132:                <!-- Compile the app -->
133:                <javac 
134:                        srcdir="${src}/main" 
135:                        destdir="${build}"
136:                        deprecation="true" 
137:                        optimize="false" 
138:                        debug="true">
139:                        <include name="${package.path}/**/*.java"/>
140:                        <classpath refid="path.classpath"/>
141:                </javac>
142:                <copy 
143:                        todir="${build}" 
144:                        overwrite="true">
145:                        <fileset dir="${properties}/main">
146:                                <include name="${package.path}/**/*.properties"/>
147:                        </fileset>
148:                </copy>
149:                <copy
150:                        todir="${build}" overwrite="true">
151:                        <fileset dir=".">
152:                                        <include name="log4j.properties"/>
153:                        </fileset>
154:                </copy>
155:        </target>

El siguiente paso es preparar las pruebas de unidad con Junit. Lo primero que hacemos es decirle a ant que es lo que queremos ejecutar y en que orden (si no está familiarizado con Junit, le recomiendo que busque una de las tantas referencias que hay en Internet):

–>

 

205:        <target 
206:                name="test" 
207:                depends="build"
208:                description="Unit tests">
209:                <echo>Running unit tests</echo>
210:                <javac 
211:                        srcdir="${src}/test"
212:                        destdir="${test}" 
213:                        includes="${package.path}/**/Test*" 
214:                        deprecation="true"
215:                        optimize="false"
216:                        debug="true">
217:                        <classpath refid="path.test"/>
218:                </javac>
219:
220:                <junit
221:                        fork="yes" 
222:                        printsummary="on"
223:                        maxmemory="300m">
224:                        <classpath refid="path.test"/>
225:                        <formatter type="xml" />
226:                        <formatter type="plain" />
227:                        <!--
228:                        - As root, set the following property on the /etc/exports file:
229:                        /usr/local/src 127.0.0.1/255.0.0.0(insecure,ro)
230:                        - Then:
231:                        /etc/init.d/nfs start                   
232:                        -->
233:                        <sysproperty 
234:                                key="test.nfs.dir" 
235:                                value="/usr/local/src"/>
236:
237:                        <sysproperty 
238:                                key="test.nfs.server"
239:                                value="localhost"/>
240:               
241:                        <sysproperty 
242:                                key="test.rstat.server" 
243:                                value="localhost"/>
244:               
245:                        <!-- Wait 35 seconds -->
246:                        <sysproperty 
247:                                key="test.rstat.wait" 
248:                                value="35000"/>
249:               
250:                        <test
251:                                name="${testcase}" 
252:                                todir="${test}" 
253:                                if="testcase"/>
254:
255:                        <batchtest
256:                                todir="${test}"
257:                                unless="testcase">
258:                                <fileset
259:                                        dir="${test}"
260:                                        includes="**/Test*.class"/>
261:                        </batchtest>   
262:                </junit>
263:       
264:                <junitreport todir="${test}">
265:                        <fileset dir="${test}">
266:                                <include name="TEST-*.xml"/>
267:                        </fileset>
268:                        <report format="frames" todir="${test}"/>
269:                </junitreport>
270:        </target>

Es entonces cuando podremos utilizar las clases cliente. Me gusta probar las cosas antes de ponerlas juntas, así que escribí algunas pruebas de unidad (Unit tests) con JUnit vemos que tan bien o mal están las clases generadas:

–>

 

1:package com.kodegeek.blog.monitoring.rpc;
2:
3:import java.net.InetAddress;
4:import java.util.ResourceBundle;
5:
6:import junit.framework.Assert;
7:import junit.framework.TestCase;
8:
9:import org.acplt.oncrpc.OncRpcClientAuthUnix;
10:import org.acplt.oncrpc.OncRpcProtocols;
11:
12:public class TestRpcStubs extends TestCase {
13:
14:        /**
15:         * Default max timeout value, in miliseconds  
16:         */  
17:        public static final int MAX_TIMEOUT = 1000*60;  
18:   
19:        private static ResourceBundle NFS_BUNDLE;  
20:        private static ResourceBundle RSTAT_BUNDLE;  
21:   
22:        {  
23:                NFS_BUNDLE = ResourceBundle.getBundle(NfsPing.class.getName());  
24:                RSTAT_BUNDLE = ResourceBundle.getBundle(RstatPing.class.getName());  
25:        }  
26:   
27:        protected void setUp() throws Exception {  
28:                super.setUp();  
29:                System.out.println("Make sure all the services are running with '/usr/sbin/rpcinfo -p'");  
30:        }  
31:   
32:        /**  
33:         * Simple test for the NFS client, using the generated RPC stubs directly  
34:         *  
35:         */  
36:        public void testNfs() {  
37:                MountClient mount = null;  
38:                exports exportsList = null;  
39:                fhstatus fhStatus = null;  
40:                OncRpcClientAuthUnix authUnix = null;  41:                try {  42:                        authUnix = new OncRpcClientAuthUnix(  43:                                        System.getProperty("test.nfs.server"),  44:                                        Integer.parseInt(NFS_BUNDLE.getString("NfsPing.user.id")),  45:                                        Integer.parseInt(NFS_BUNDLE.getString("NfsPing.user.group"))  46:                        );  47:                        Assert.assertNotNull("Auth Unix is null", authUnix);  48:                        // Get the list of exported directories  49:                        mount = new MountClient(  50:                                        InetAddress.getByName(System.getProperty("test.nfs.server")),  51:                                        OncRpcProtocols.ONCRPC_TCP);  52:                        Assert.assertNotNull("Mount is null", mount);  53:                        exportsList = mount.MOUNTPROC_EXPORT_1();  54:                        Assert.assertNotNull("Export list is null", exportsList);  55:                        exportnode node = exportsList.value;  56:                        Assert.assertNotNull("No nodes are being exported", node);  57:                        while (node != null) {  58:                                Object [] nodeForm = new Object[1];  59:                                nodeForm[0] = node.ex_dir.value;  60:                                System.out.printf(  61:                                                NFS_BUNDLE.getString("NfsPing.msg.exportedFs"), nodeForm  62:                                );  63:                           64:                                mount.getClient().setAuth(authUnix);  65:                                mount.getClient().setTimeout(MAX_TIMEOUT);  66:                           67:                                fhStatus = mount.MOUNTPROC_MNT_1(new dirpath(System.getProperty("test.nfs.dir")));  68:                                if (fhStatus == null) {  69:                                        Assert.fail("unable to get fhStatus for: " +System.getProperty("test.nfs.dir"));  70:                                }  71:                                // Get the next node  72:                                node = node.ex_next.value;  73:                        }  74:                } catch (Throwable throwbl) {  75:                        Assert.fail("Got an exception: " + throwbl.toString());  76:                        throwbl.printStackTrace();  77:                } finally {  78:                        // Empty for now  79:                }  80:        }  81:  82:        /**  83:         * Simple test for Rstat, using the generated RPC stubs directly  84:         * Timestamps are separated into seconds (standard UNIX time) and  85:         * microseconds. The availability of a current timestamp allows proper  86:         * calculation of the interval between measurements without worrying  87:         * about network latency.  88:         *   89:         * Most values are counters. To get the real numbers you have to  90:         * fetch() samples regularly and divide the counter increments  91:         * by the time interval between the samples.  92:         *  93:         * The cpu_time array holds the ticks spent in the various CPU states  94:         * (averaged over all CPUs). If you know the regular tick rate of the target  95:         * system you may calculate the number of CPUs from the sum of C<cpu_time>  96:         * increments and the time interval between the samples. Most often you  97:         * will be interested in the percentage of CPU states only.  98:         */  99:        public void testRstat() { 100:                OncRpcClientAuthUnix authUnix = null; 101:                RstatClient rstat = null; 102:                statstime stats = null; 103:                statstime stats2 = null; 104:                try { 105:                        authUnix = new OncRpcClientAuthUnix( 106:                                        System.getProperty("test.rstat.server"), 107:                                        Integer.parseInt(RSTAT_BUNDLE.getString("RstatPing.user.id")), 108:                                        Integer.parseInt(RSTAT_BUNDLE.getString("RstatPing.user.group")) 109:                        ); 110:                        Assert.assertNotNull("Auth Unix is null", authUnix); 111:                  112:                        rstat = new RstatClient( 113:                                        InetAddress.getByName(System.getProperty("test.rstat.server")), 114:                                        OncRpcProtocols.ONCRPC_UDP 115:                                        ); 116:                        Assert.assertNotNull("Rstat is null", rstat); 117:                        rstat.getClient().setAuth(authUnix); 118:                        rstat.getClient().setTimeout(MAX_TIMEOUT); 119:                        stats = rstat.RSTATPROC_STATS_3(); 120:                        Assert.assertNotNull("statsswtch stats is null", stats); 121:                  122:                        // Now wait a little bit before taking the next snapshot 123:                        long wait = Long.parseLong(System.getProperty("test.rstat.wait")); 124:                        Thread.sleep(wait); 125:                  126:                        // Get another snapshot 127:                        stats2 = rstat.RSTATPROC_STATS_3(); 128:                  129:                        long timeElaps =  stats2.getCurtime().tv_sec -stats.getCurtime().tv_sec; 130:                  131:                        Object [] statColl = new Object[23]; 132:                        statColl[0] = new Long((stats2.if_collisions -stats.if_collisions)/ timeElaps); 133:                        statColl[1] = new Long((stats2.if_ierrors -stats.if_ierrors) /timeElaps); 134:                        statColl[2] = new Long((stats2.if_ipackets -stats.if_ipackets) /timeElaps); 135:                        statColl[3] = new Long((stats2.if_oerrors -stats.if_oerrors) /timeElaps); 136:                        statColl[4] = new Long((stats2.if_opackets -stats.if_opackets) /timeElaps); 137:                        statColl[5] = new Long((stats2.v_intr -stats.v_intr) /timeElaps); 138:                        statColl[6] = new Long((stats2.v_pgpgin -stats.v_pgpgin) /timeElaps); 139:                        statColl[7] = new Long((stats2.v_pgpgout -stats.v_pgpgout) /timeElaps); 140:                        statColl[8] = new Long((stats2.v_pswpin -stats.v_pswpin) /timeElaps); 141:                        statColl[9] = new Long((stats2.v_pswpout -stats.v_pswpout) /timeElaps); 142:                        statColl[10] = new Long((stats2.v_swtch -stats.v_swtch) /timeElaps); 143:                        statColl[11] = new Double(stats2.getAvenrun(0) / 256.0); 144:                        statColl[12] = new Double(stats2.getAvenrun(1) / 256.0); 145:                        statColl[13] = new Double(stats2.getAvenrun(2) / 256.0); 146:                        statColl[14] = new Long((stats2.getCp_time(0) -stats.getCp_time(0))/ timeElaps); 147:                        statColl[15] = new Long((stats2.getCp_time(1) -stats.getCp_time(1)) / timeElaps); 148:                        statColl[16] = new Long((stats2.getCp_time(2) -stats.getCp_time(2)) / timeElaps); 149:                        statColl[17] = new Long((stats2.getCp_time(3) -stats.getCp_time(3))/ timeElaps); 150:                        statColl[18] = new Long((stats2.getDk_xfer(0) -stats.getDk_xfer(0))/ timeElaps); 151:                        statColl[19] = new Long((stats2.getDk_xfer(1) -stats.getDk_xfer(1)) / timeElaps); 152:                        statColl[20] = new Long((stats2.getDk_xfer(2) -stats.getDk_xfer(2)) / timeElaps); 153:                        statColl[21] = new Long((stats2.getDk_xfer(3) -stats.getDk_xfer(3)) / timeElaps); 154:                        statColl[22] = new Long(stats2.getBoottime().tv_sec); 155:                  156:                        StringBuffer info = new StringBuffer(); 157:                        info.append("Rstat unit test\n"); 158:                        info.append("Time elapsed between measures (seconds): " +timeElaps + "\n"); 159:                        info.append("if_collisions=%s\n"); 160:                        info.append("if_ierrors=%s\n"); 161:                        info.append("if_ipackets=%s\n"); 162:                        info.append("if_oerrors=%s\n"); 163:                        info.append("if_opackets=%s\n"); 164:                        info.append("v_intr=%s\n"); 165:                        info.append("v_pgpgin=%s\n"); 166:                        info.append("v_pgpgout=%s\n"); 167:                        info.append("v_pswpin=%s\n"); 168:                        info.append("v_pswpout=%s\n"); 169:                        info.append("v_swtch=%s\n"); 170:                        info.append("Avenrun (CPU load) 0=%s\n"); 171:                        info.append("Avenrun (CPU load) 1=%s\n"); 172:                        info.append("Avenrun (CPU load) 2=%s\n"); 173:                        info.append("CP_time 0 Usr=%s\n"); 174:                        info.append("CP_time 1 System=%s\n"); 175:                        info.append("CP_time 2 Wio=%s\n"); 176:                        info.append("CP_time 3 Idle=%s\n"); 177:                        info.append("Dk_xfer 0=%s\n"); 178:                        info.append("Dk_xfer 1=%s\n"); 179:                        info.append("Dk_xfer 2=%s\n"); 180:                        info.append("Dk_xfer 3=%s\n"); 181:                        info.append("Raw uptime in seconds=%s\n"); 182:                  183:                        // Spit the results out 184:                        System.out.printf( 185:                                        info.toString(), 186:                                        statColl 187:                                        ); 188:                } catch (Throwable throwbl) { 
189:                        Assert.fail("Got an exception: " + throwbl.toString()); 
190:                        throwbl.printStackTrace(); 
191:                } finally { 1
92:                        // Empty for now 
193:                } 
194:        } 
195:}

El resultado de las pruebas de unidad es el siguiente:

Make sure all the services are running with '/usr/sbin/rpcinfo -p'Exported filesystem: /usr/local/srcMake sure all the services are running with'/usr/sbin/rpcinfo -p'Rstat unit testTime elapsed between measures (seconds): 37if_collisions=0if_ierrors=0if_ipackets=4if_oerrors=0if_opackets=4v_intr=1015v_pgpgin=0v_pgpgout=0v_pswpin=0v_pswpout=0v_swtch=775Avenrun (CPU load) 0=1.4296875Avenrun (CPU load) 1=0.94921875Avenrun (CPU load) 2=0.6875CP_time 0 Usr=29CP_time 1 System=0CP_time 2 Wio=2CP_time 3 Idle=61Dk_xfer 0=0Dk_xfer 1=0Dk_xfer 2=0Dk_xfer 3=0Raw uptime in seconds=1150929416

El siguiente paso es probar como enviar información usando el protocolo de Jabber, pero eso se los mostraré en un siguiente articulo 😉

El sistema no es de grado comercial; Uno de verdad debería estar en capacidad de monitorear varios servidores a la vez, y si debe escalar entonces quizas usar Jabber como presentación quizas no sea lo adecuado. Pero nadie niega que fué divertido 😉

Referencias:

Por ahora no pienso colocar el código para que se lo baje, aunque si lo puede revizar utilizando la interfaz web a CVS.

Buscar en Technorati: , , , , ,
Buscar en Blogalaxia: , , , , ,

Libertad de expresión y comics: Las guerras "civiles" de Marvel

marvel civil war
¡Algo terrible pasa en Stamford, CT!

Imaginese el siguiente scenario en los Estados Unidos: los super heroes son una realidad. Wolverine, Spiderman y otros nos defienden de villanos igualmente poderosos. Un día un enfrentamiento entre ambos bandos produce una mortandad (niños incluidos) en nada menos y nada más que Stamford, CT.

A raiz de esos eventos, el gobierno Americano decide pasar una ley en la cual declaran a toda persona con super poderes un arma de destrucción masiva y por lo tanto deben ser identificados y controlados.

¿Tienen razón quienes opinan que nadie debe estar enmascarado y que si nada tienen que temer entonces porque ocultarse? Los policias, abogados y jueces no se ocultan y todos los días dan la cara pese a los peligros que eso asocia, todo porque la sociedad así lo quiere.

Por otro lado, alguien se acuerda de como los nazis catalogaron a todos los Judios, ¿para luego eliminarlos de manera sistematica?

civilwarI&II
Peter Parker revela su secreto al mundo, mientras que el Capitan America se convierte en un criminal (según el gobierno)

No hay respuestas fáciles y en esta serie de Marvel vemos como el hombre araña está dispuesto a develar su identidad junto con Ironman y otros super heroes, mientras que Wolverine (como era de esperarse) opina distinto.

Y para hacer más irresistible el asunto, Stamford CT es el detonante de todo el asunto.

Buscar en Technorati: , , , ,
Buscar en Blogalaxia: , , , ,

Felicitaciones, ¡usted es el visitante número 666 que viene a este blog!

666-kodegeek
666 de Summer Street, Stamford CT

“El también forzó a todo el mundo, grandes y pequeños, ricos y pobres, libres y esclavos, a recibir la marca en su mano derecha o en la frente, de manera que nadie pudiera comprar o vender al menos que tuviera la marca, el cual es el nombre de la bestia o el número de su nombre. Es una llamada de la sabiduría. Si tiene visión, dejenlo calcular el número de la bestia, el cual es un número de hombre. Su número es el 666

Hoy es el día con el número de la bestia. El número se hizo famoso gracias a las referencias que tiene en el Apocalipsis (si, usted sabe la parte más entretenida de la Biblia en donde se habla de como todos los pecadores vamos a llevar guayaba). Sin embargo no todas las referencias son tan serias, ya que cada uno tiene una intepretación diferente de el famoso numerito.


Flickr tiene un montón de referencias

¿Y quienes y como lo celebran el día de hoy (si, hay quienes lo celebran)?. La ultra conocida banda de Thrash Metal, Slayer (los cuales siempre han sido objeto de controversia por la letra de sus canciones y lo brutalmente agresivo de sus melodías) tienen un sitio oficial, “National Day of Slayer“. Hoy también sale una nueva versión de la pelicula “The Omen” (en Venezuela la conocimos como la profecia) en la cual Damian (el Anticristo) hace de las suyas.

Ya tengo grabada “Angel of Death” en mi Ipod para escucharla el día de hoy 🙂

CBGB NYC
Para mi el número no tiene ningún significado especial. ¿Y para usted?

Para mi este día debería ser el día de los politicos Venezolanos, en particular de quienes se han encargado de sembrar odio y división entre quienes tienen poco criterio para defenderse. Si, ustedes saben quienes son y por ello les rindo su merecido tributo.

Buscar en Technorati: , , , ,
Buscar en Blogalaxia: , , , ,

ULA Linux: La distribución de Linux de la Universidad de Los Andes

ULALinux

Bueno, este proyecto ya tiene tiempo pero por una u otra razón no lo había mencionado en el blog. La Universidad de Los Andes (ULA) está desarrollando una distribución de Linux, la cual ya está mostrando señales de vida.

De verdad felicitaciones por la iniciativa, de verdad esperamos poder jugar con la versión 1.0 pronto, pero por los momentos la beta está disponible.

Se la pueden bajar de aquí.

Buscar en Technorati: , ,
Buscar en Blogalaxia: , ,

Echando código: ¿Como hacer interfaces gráficas en Perl?

Perl

Escribí un articulo para “La Cara Oscura de El Sofware” acerca de como usar interfaces gráficas con Perl / Tk. Realmente entretenido y una de las cosas con las que he estado trabajando estos días.

Uno se da cuenta lo mucho que la web apesta cuando escribe aplicaciones de escritorio 😀

Buscar en Technorati: , , ,
Buscar en Blogalaxia: , , ,

Trucos UNIX: SSH y Bash van de la mano

Linux

Suponga que usted tiene el siguiente problema: Usted quiere conectarse remotamente a un servidor, utilizando (por supuesto) SSH. Cada vez que se conecta usted quiere que SSH lo deje en un directorio en particular (por ejemplo cd /home/josevnz/fotos) y además quiere que le imprima por pantalla en que directorio está.

¿Fácil no es así? Eso se logra con sólo editar el .bashrc (si su shell es Bash) y allí se ponen las instrucciones.

Ahora dejeme complicarle el problema aún más:

  • Usted solamente quiere que esto pase en algunas ocasiones, no todo el tiempo que se conecta al servidor.
  • Usted va a tener un grupo de directorios distintos con los cuales quiere hacer lo mismo

La solución es increiblemente sencilla: Llame a SSH en modo interactivo, corra cada uno de los comandos que quiere ejecutar encadenados con una expresión en Shell y al final llame a Bash en modo interactivo, reemplazando el proceso actual con Exec.

Si, suena más complicado de lo que es, los dejo con este útil comando el cual puede ser convertido en un script o hasta en un alias (cada una de las intrucciones que les día anteriormente corresponde a un color en el script con SSH):

ssh -t josevnz@myhost “cd $HOME/fotos &&amp; pwd && exec bash -login

¿Que otras cosas se le ocurren?

Buscar en Technorati: , , , ,
Buscar en Blogalaxia: , , , ,