Echando código: ¿Como monitorear a NFS usando Java? (hablemos ONC RPC, I)

Manhattan
Muchas aplicaciones dependen de NFS para funcionar correctamente, como bloques uno encima de el otro. ¿Como asegurarse de que este servicio está trabajando como se debe?

Si no sabe que es NFS, entonces lease primero este tutorial y después vuelva aquí. También para este articulo yo asumo que usted ya ha escrito programas en Java con anterioridad y que sabe algunos conceptos básicos de redes.

Es una pregunta interesante, ya que NFS utiliza RPC como protocolo principal (más abajo están UDP o TCP pero eso es otra cosa); Así que quizas los más fácil es simular una transacción sintetica (como por ejemplo para monitorear una base de datos podemos hablar JDBC y preguntar por la metada directamente). Se me ocurre que pedir un listado de archivos en el directorio exportado puede ser una prueba decente (limitando el número de archivos a cierto número, por si el directorio es grande).

Usted se puede estar preguntando lo siguiente: ¿No es más eficiente preguntar estas cosas por SNMP (quizas extendiendo la configuración de el agente para que llame a los comandos nativos nfstat o showmount por ejemplo)? Quizas sí, después de todo RPC es un protoclo más pesado que SNMP. Pero por otro lado si usted no puede instalar demonios adicionales en la máquina o su organización no soporta SNMP, entonces ¿que alternativa le queda?

Después de mucho buscar, me consegui con una librería GPL llamada “Remote Tea“. Ya hay varias implementaciones (entre ellas un demonio de NFS) así que quizas esto es lo que estaba buscando.

Lo primero que hacemos es preparar a un servidor NFS de pruebas. Si usted utiliza Linux quizas pudiera hacer algo como esto (necesita ser root, para el ejemplo asumo que su red interna es 192.168.0.0/24 y que está compartiendo /usr/local/src.):

[root@localhost ~]# cat /etc/exports
/usr/local/src 127.0.0.1/255.0.0.0(ro) 192.168.0.0/255.255.255.0(ro)
[root@localhost ~]# /etc/init.d/nfs restart
Shutting down NFS mountd: [ OK ]
Shutting down NFS daemon: [ OK ]
Shutting down NFS quotas: [ OK ]
Shutting down NFS services: [ OK ]
Starting NFS services: [ OK ]
Starting NFS quotas: [ OK ]
Starting NFS daemon: [ OK ]
Starting NFS mountd: [ OK ]
[root@localhost ~]# showmount -e localhost
Export list for localhost:
/usr/local/src 192.168.0.0/255.255.255.0
[root@localhost ~]#

Y para estar completamente seguros (¿los demonios se registraron con RPC?):

[root@localhost ~]# rpcinfo -p localhost
program vers proto port
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
100024 1 udp 32829 status
100024 1 tcp 32771 status
100011 1 udp 912 rquotad
100011 2 udp 912 rquotad
100011 1 tcp 915 rquotad
100011 2 tcp 915 rquotad
100003 2 udp 2049 nfs
100003 3 udp 2049 nfs
100003 4 udp 2049 nfs
100003 2 tcp 2049 nfs
100003 3 tcp 2049 nfs
100003 4 tcp 2049 nfs
100021 1 udp 32839 nlockmgr
100021 3 udp 32839 nlockmgr
100021 4 udp 32839 nlockmgr
100021 1 tcp 32777 nlockmgr
100021 3 tcp 32777 nlockmgr
100021 4 tcp 32777 nlockmgr
100005 1 udp 924 mountd
100005 1 tcp 927 mountd
100005 2 udp 924 mountd
100005 2 tcp 927 mountd
100005 3 udp 924 mountd
100005 3 tcp 927 mountd

Note que rpcinfo nos da información muy importante acerca de el demonio que queremos contactar. En este caso es el número de el programa, la versión, el protocolo y el nombre. Anotelo en algún lado, ya que esto será requerido en cuanto nos intentemos conectar.

Para nuestro experimiento, vamos a asegurarnos que nos podemos conectar a nuestra propia máquina Linux sin restricciones de seguridad. Para ello el archivo ‘/etc/hosts.allow’ debe decir:

ALL:localhost.localdomain,127.0.0.1

Y el archivo ‘/etc/hosts.deny’:

ALL:ALL

Hay una limitación de seguridad con nuestro cliente. Como no lo vamos a correr como root sino como un usuario no privilegiado, el cliente no va a poder abrir puertos menores a 1024. Mountd no le va a permitir a usted conectarse desde un puerto inseguro (mayor que 1024):

Jul 20 22:55:15 localhost rpc.mountd: refused mount request from localhost.localdomain for /usr/local/src (/usr/local/src): illegal port 32791

La cura es fácil (/etc/exports, puede revisar los mensajes de autenticación exitosos con ‘tail -f /var/log/messages‘):

/usr/local/src 127.0.0.1/255.0.0.0(insecure,ro) 192.168.0.0/255.255.255.0(insecure,ro)

Una vez que el demonio de NFS está arriba y que vemos que funciona entonces podemos empezar a jugar con el cliente de monitoreo. Lo primero que tiene que hacer es desempacar el archivo zip que se encuentra en Source Forge, y ponga los archivos JAR en el ClassPath.

La pregunta es, para alguien que no sabe nada de ONC RPC (yo por ejemplo), ¿que tan dificil puede ser hacer un programa que haga ping, basandose sólo en los RFC?. Primero que nada vamos a hacer un “hola mundo“, el cual sólo va a tratar de conectarse al demonio apropiado de RPC (para ello vea las lineas que resalté en rojo en el paso anterior). El código es el siguiente (basado en los métodos descritos en el JavaDoc):

   1:package com.blogspot.elangelnegro.nfs;
2:
3:import java.net.InetAddress;
4:
5:import java.io.IOException;
6:
7:import org.acplt.oncrpc.OncRpcClient;
8:import org.acplt.oncrpc.OncRpcProgramNotRegisteredException;
9:import org.acplt.oncrpc.OncRpcException;
10:import org.acplt.oncrpc.OncRpcProtocols;
11:
12:public final class Ping {
13:
14: /**
15: * Error exit code
16: */
17: public static final int ERROR_EXIT_CODE=192;
18:
19: /**
20: * The RPC program ID of NFSD
21: */
22: public static final int RPC_PROGRAM_NFSD=100003;
23:
24: /**
25: * The RPC program version for NFSD
26: */
27: public static final int RPC_PROGRAM_NFSD_VERSION=4;
28:
29: public static void main(String [] args) throws Exception {
30: OncRpcClient client = null;
31: if ( ! ( (args != null) && (args[0] != null)) ) {
32: throw new IllegalArgumentException("Please specify the host where the NFS daemon is running!");
33: }
34: try {
35: client = OncRpcClient.newOncRpcClient(
36: InetAddress.getByName(args[0]),
37: RPC_PROGRAM_NFSD,
38: RPC_PROGRAM_NFSD_VERSION,
39: OncRpcProtocols.ONCRPC_TCP);
40: client.call(0, XdrVoid.XDR_VOID, XdrVoid.XDR_VOID);
41: } catch ( OncRpcProgramNotRegisteredException exp) {
42: System.out.println("ONC/RPC program server not found");
43: throw exp;
44: } catch (OncRpcException exp) {
45: System.out.println("Could not contact portmapper:");
46: exp.printStackTrace(System.out);
47: throw exp;
48: } catch (IOException exp) {
49: System.out.println("Could not contact portmapper:");
50: exp.printStackTrace(System.out);
51: throw exp;
52: } finally {
53: if (client != null) {
54: try {
55: client.close();
56: } catch (Exception ignore) {
57: // Do nothing
58: }
59: }
60: }
61: System.out.println("NFS daemon is registered with RPC");
62: }
63:
64:}

Compilamos el programa, lo corremos y si todo está bien deberiamos ver lo siguiente:

java com.blogspot.elangelnegro.nfs.Ping localhost
NFS daemon is registered with RPC

Pero, ¿Y se puede hacer algo más interesante, como leer que archivos hay en el directorio que está siendo exportado usando NFS?. No hay almuerzo grátis así que hacemos una pausa y nos leemos los RFC relacionados (RFC1831 y RFC1094).

Haciendo un resumen ultra violento, nos encontramos que:

  1. Primero debemos hablar con el protocolo mount el cual nos va a dar el punto de partida para poder conectarnos a NFS. Vea el apendice A del RFC 1094 para más detalles.
  2. Una vez obtenido los valores con Mount, es entonces que usamos NFS.

No se asuste, las analogías con como usted utiliza mount son identicas; Mount se encarga de lidiar con problemas de permisología, autenticación, etc y luego es con NFS que usted puede empezar a trabajar con sus archivos, pero una vez que el directorio está montado.

Si estamos utilizando un servidor bajo Linux, quizas lo más fácil es utilizar el compilador de archivos X el cual nos dará las clases de Java necesarias (les muestro un pequeño wrapper, usted haga los cambios necesarios):

#!/bin/bash
# Check the IBM RedBook: http://www.redbooks.ibm.com/redpapers/pdfs/redp3882.pdf
# Author: josevnz@users.sourceforge.net
# Blog: El Angel Negro – http://elangelnegro.blogspot.com
#
CLASSPATH=/home/josevnz/jars/jrpcgen.jar:/home/josevnz/jars/oncrpc.jar:/home/josevnz/jars/portmap.jar:.
DESTDIR=/home/josevnz/java/NFSPing/src/com/blogspot/elangelnegro/nfs/client/
mkdir -p $DESTDIR && rm -f $DESTDIR/* && cd /usr/include/rpcsvc && for stub in nfs_prot.x mount.x ; do
/usr/java/jdk1.5.0_03/bin/java -jar /home/josevnz/jars/jrpcgen.jar -p com.blogspot.elangelnegro.nfs.client -withcallinfo -d $DESTDIR $stub
done

Esto va a generar un montón de clases en Java, las cuales van a ser utilizadas por nuestra aplicación. Busque por aquellas que dicen “client*.java” ya que con ellas llamaremos a nuestro servidor RPC. Lo otro que notará en el código es que cada uno de los métodos remotos descritos en el RFC tiene su contraparte en las clases clientes de Java. Por ejemplo, esto es lo que tengo en mi directorio después de correr el script.

[josevnz@localhost ~]$ cd java/NFSPing/src/com/blogspot/elangelnegro/nfs/client/[josevnz@localhost
client]$ ls
attrstat.java groupnode.java nfsstat.java
createargs.java groups.java nfstime.java
dirlist.java linkargs.java readargs.java
diropargs.java mountbody.java readdirargs.java
diropokres.java mountClient.java readdirres.java
diropres.java mount.java readlinkres.java
dirpath.java mountlist.java readokres.java
entry.java mountServerStub.java readres.java
exportnode.java name.java renameargs.java
exports.java nfscookie.java sattrargs.java
fattr.java nfs_fh.java sattr.java
fhandle.java nfspath.java statfsokres.java
fhstatus.java nfs_protClient.java statfsres.java
filename.java nfs_prot.java symlinkargs.java
ftype.java nfs_protServerStub.java writeargs.java
[josevnz@localhost client]$

Bueno, espero que esta pequeño articulo le haya resultado útil y entretenido. Conseguí un tutorial muy bueno de ONC RPC y la gente de IBM muestra más de como usar Remote Tea con sus servidores.

En una segunda entrega les mostraré el código cliente de NFSPing, así como un enlace para que se baje el código.

Etiquetas en Technorrati:

2 thoughts on “Echando código: ¿Como monitorear a NFS usando Java? (hablemos ONC RPC, I)

  1. Si, es muy intuitivo. Lo único que no me gustó es que el soporte se ve muy limitado (inclusive con los grupos de discusión) asi que no queda otra que estudiar y leer bastante.

    Lo otro que me encanta es que se puede hacer herramientas portables de monitoreo, en sitios en donde SNMP no puede llegar.

    ¿Para que has usado tu ONC RPC?

Comments are closed.