Junio
2006
TcosMonitor, herramienta para monitorizar redes de clientes ligeros
Muchos de los que visitais mi blog ya conoceis de la existencia de iTALC, una aplicación «Gran Hermano» para monitorizar redes mediante el protocolo RFB/VNC.
Esta herramienta está muy muy bien, pero tiene ciertas carencias:
La idea consiste en lo siguiente, el terminal es un pc normal y corriente en el que se pueden ejecutar aplicaciones bajo demanda (bastante pocas), como puede ser reiniciar, apagar, mostrar uso de memoria, reiniciar entorno gráfico, bloquear pantalla, etc... iTALC puede hacer muchas de estas cosas pero para ello debemos tener abierta una conexión RFB permanente.
TcosMonitor consiste en dos pequeñas aplicaciones (con sus scripts «hooks-addons» lanzadores) que hacen dos servidores, un servidor httpd que ya viene incluido en busybox, y un nuevo servidor tcosxmlrpc que he programado yo en C (xmlrpc-c).
Con la coletilla XML-RPC ya os podeis imaginar por donde van los tiros, es sencillamente genial, una aplicación cliente python (con 3 líneas sobra) se conecta con el servidor y le pasa los parámetros que necesitemos a un método del servidor, tcoxmlrpc los procesa y devuelve un resultado (en caso de devolver algo).
Por ejemplo, cosas que ya tengo programadas, hay una clase en tcosxmlrpc que se llama tcos.exe que recibe como parámetro un string con el nombre de la aplicación a ejecutar (o la órden entera de la línea de comandos), la guarda en un archivo en el terminal y otra aplicación lee esa «cola de tareas» para ir procesándola de una en una. Ejemplo simple:
Como veis con el import son 3 líneas para decirle al terminal que se reinicien las X. Esta parte de código se ejecuta desde el equipo que usemos como monitor del aula (normalmente el servidor de terminales)
En el terminal hay corriendo un servidor XML-RPC (basado en abyss) que ejecuta lo siguiente:
Esto es parte de tcosxmlrpc.c que recibe como parámetro un string y se lo pasa a la funcion job_exe para que escriba en el archivo de colas de procesos una nueva entrada. La explicación de hacer esta chapuza es que en la mayoría de los casos quiero que la petición corra en segundo plano y ni con system() ni con popen() ni con fork() lo he sabido hacer, y mira que he probado cosas....
Ejemplo de funcionamiento:
Salida de un client.py de ejemplo:
Salida de depuración de tcosxmlrpc:
Todo esto está muy bien pero resulta que hay que ponerlo de alguna manera que sea sencillo de manejar, y que mejor que hacer un GUI en pygtk???
¿he dicho alguna vez que python mola?
He aquí una captura de lo puede llegar a ser TcosMonitor (la interfaz aún no funciona y los datos que aparecen son simulados)

La parte inferior es para mostrar información y acciones del terminal (cpu, ram, swap, particiones, procesos, versión de tcos, personalizar imagen de arranque de tcos, abrir una sessión VNC o iTALC con el cliente, posiblemente una captura de pantalla del terminal en el momento que se genere, y lo que se me vaya ocurriendo)
Se me ocurre que puede ser una aplicación killer-app para aquellos ciber-café que funcionen como thin clients....
Esta herramienta está muy muy bien, pero tiene ciertas carencias:
- No es capaz de obtener información del sistema operativo destino.
- NO fue diseñada para redes PXES/LTSP/TCOS. (aunque con un parche es posible al 50%)
- Consume una cantidad enorme de ancho de banda y cpu (probado con 24 terminales).
- No es personalizable (al menos sin tener un buen nivel de C++)
- El desarrollador parece haber abandonado/dejado de lado el proyecto (las actualizaciones del CVS tienen varios meses)
La idea consiste en lo siguiente, el terminal es un pc normal y corriente en el que se pueden ejecutar aplicaciones bajo demanda (bastante pocas), como puede ser reiniciar, apagar, mostrar uso de memoria, reiniciar entorno gráfico, bloquear pantalla, etc... iTALC puede hacer muchas de estas cosas pero para ello debemos tener abierta una conexión RFB permanente.
TcosMonitor consiste en dos pequeñas aplicaciones (con sus scripts «hooks-addons» lanzadores) que hacen dos servidores, un servidor httpd que ya viene incluido en busybox, y un nuevo servidor tcosxmlrpc que he programado yo en C (xmlrpc-c).
Con la coletilla XML-RPC ya os podeis imaginar por donde van los tiros, es sencillamente genial, una aplicación cliente python (con 3 líneas sobra) se conecta con el servidor y le pasa los parámetros que necesitemos a un método del servidor, tcoxmlrpc los procesa y devuelve un resultado (en caso de devolver algo).
Por ejemplo, cosas que ya tengo programadas, hay una clase en tcosxmlrpc que se llama tcos.exe que recibe como parámetro un string con el nombre de la aplicación a ejecutar (o la órden entera de la línea de comandos), la guarda en un archivo en el terminal y otra aplicación lee esa «cola de tareas» para ir procesándola de una en una. Ejemplo simple:
#!/usr/bin/env python
import xmlrpclib
server = xmlrpclib.Server("http://192.168.0.101:8080/RPC2")
result = server.tcos.exe("killall Xorg ; startremotex")
Como veis con el import son 3 líneas para decirle al terminal que se reinicien las X. Esta parte de código se ejecuta desde el equipo que usemos como monitor del aula (normalmente el servidor de terminales)
En el terminal hay corriendo un servidor XML-RPC (basado en abyss) que ejecuta lo siguiente:
static xmlrpc_value *
tcos_exe(xmlrpc_env *env, xmlrpc_value *in, void *ud)
{
char *s;
size_t *len;
xmlrpc_parse_value(env, in, "(s#)", &s, &len);
if (env->fault_occurred)
return xmlrpc_build_value(env, "s", "params error");;
job_exe(s);
return xmlrpc_build_value(env, "s", s);
}
[...]
void job_exe( char *cmd )
{
FILE *fp;
char job[200];
sprintf(&job, "echo "%s" >> %s", cmd, JOB_FILE);
fp=popen(job, "r");
}
Esto es parte de tcosxmlrpc.c que recibe como parámetro un string y se lo pasa a la funcion job_exe para que escriba en el archivo de colas de procesos una nueva entrada. La explicación de hacer esta chapuza es que en la mayoría de los casos quiero que la petición corra en segundo plano y ni con system() ni con popen() ni con fork() lo he sabido hacer, y mira que he probado cosas....
Ejemplo de funcionamiento:
Salida de un client.py de ejemplo:
Exec return=startlocalx
time to get exec 0.022885
PYTHON::Evolution status is=1
PYTHON::time to get status 0.064822
PYTHON::Apache2 status is=1
PYTHON::time to get status 0.079125
PYTHON::app-no-runnning status is=0
PYTHON::time to get status 0.071517
PYTHON::update_system_info status is=[1]
PYTHON::time to get status 0.034349
PYTHON::version is=['0.0.2']
PYTHON::time to get version 0.006734
Salida de depuración de tcosxmlrpc:
Estas pruebas estan hechas en local, es decir, arrancando el servidor y el cliente en la misma máquina de ahí que los tiempos sean mínimos, cuando las máquinas son distintas apenas ningún proceso supera los 0,5 segundos...
tcosxmlrpc::tcos_exe() Init
tcosxmlrpc::tcos_exe s="startlocalx"
xmlrpc::job_exe() exec=> "echo "startlocalx" >> /tmp/tcosxmlrpc.dat"
tcosxmlrpc::tcos_status() Init
tcosxmlrpc::tcos_status() pidof evolution
tcosxmlrpc::tcos_status() exec cmd="pidof evolution| grep [1234567890] | wc -l"
tcosxmlrpc::tcos_status() reading from fp pointer
tcosxmlrpc::tcos_status() ret value=1
tcosxmlrpc::tcos_status() Init
tcosxmlrpc::tcos_status() pidof apache2
tcosxmlrpc::tcos_status() exec cmd="pidof apache2| grep [1234567890] | wc -l"
tcosxmlrpc::tcos_status() reading from fp pointer
tcosxmlrpc::tcos_status() ret value=1
tcosxmlrpc::tcos_status() Init
tcosxmlrpc::tcos_status() pidof app-no-runnning
tcosxmlrpc::tcos_status() exec cmd="pidof app-no-runnning| grep [1234567890] | wc -l"
tcosxmlrpc::tcos_status() reading from fp pointer
tcosxmlrpc::tcos_status() ret value=0
tcosxmlrpc::update_system_info() job=webserver.sh update
xmlrpc::job_exe() exec=> "echo "webserver.sh update" >> /tmp/tcosxmlrpc.dat"
tcosxmlrpc::tcos_version() 0.0.2
Todo esto está muy bien pero resulta que hay que ponerlo de alguna manera que sea sencillo de manejar, y que mejor que hacer un GUI en pygtk???
¿he dicho alguna vez que python mola?
He aquí una captura de lo puede llegar a ser TcosMonitor (la interfaz aún no funciona y los datos que aparecen son simulados)

La parte inferior es para mostrar información y acciones del terminal (cpu, ram, swap, particiones, procesos, versión de tcos, personalizar imagen de arranque de tcos, abrir una sessión VNC o iTALC con el cliente, posiblemente una captura de pantalla del terminal en el momento que se genere, y lo que se me vaya ocurriendo)
Se me ocurre que puede ser una aplicación killer-app para aquellos ciber-café que funcionen como thin clients....
Muy interesante pero muy preocupante :P
La autentificaión? cualquier podría conectarse al servidor rpc y ejecutar lo que quisiera.
La función job_exe es insegura, ya que si envías una cadena mayor que 200 bytes sobreescribirás algo que no debes. En vez de usar sprintf, usa snprintf que permite indicar de cuanto es la cadena. Por otro lado puedes poner la cadena más larga que no pasa nada.
Otra cosa que no entiendo es para qué tienes que usar un servidor escrito en C para ejecutar un comando de sistema cuando puedes poner un servidor python (muy simple) con un popen.
Lo de la autenticación ya lo había pensado pero no se muy bien como hacerlo ya que aunque la librería que estoy usando soporta autenticación la contraseña tendría que ponerla en texto plano dentro del .c y con un simple «strings tcosxmlrpc» se puede sacar.
El motivo de haberlo hecho en C es porque esto va en un terminal y por tema de recursos me puedo permitir un binario y 4 librerías que ocupan 200Kb y no meter python y un huevo de cosas... ya me gustaría hacer el servidor en python (odio C).
Lo de job_exe tienes razón... lo arreglaré y subiré el tamaño del string job.
Creo haber entendido que la máquina "gestora" se conecta al cliente que quiere y ejecuta en él lo que quiere... ¿Para eso no es más fácil (y seguro) usar SSH?
Haciéndolo como lo tienes montado ya, podrías realizarlo dándole la vuelta: puedes hacer que cada cliente se conecte con el servidor cada cierto tiempo... para ver si tiene algo que ejecutar. La ventaja de esto sería que te evitas el autentificado, y puedes usar certificados y https en el servidor, para asegurar la transmisión de datos.
La autentificación no es para nada "difícil".
Existen funciones en el API de linux para encriptar claves y comprobar los usuarios del sistema. Eso sí, la transmisión deberías hacerla encriptada usando un sistema de certificados o clave pública/privada. cryptlib te aporta todo eso de una forma más o menos sencilla.
Mi opinión es que las mandes en texto plano al comienzo, después ya implementarás un sistema más robusto.
La verdad es que con C lo has resulto bastante bien y si tienes esa limitación... Ya sabes que si tienes algún problema con C por aquí estoy :);
No soy muy experto en estos temas, pero no has considerado utilizar SNMP, tengo entendido que es el standar en equipos de telecomunciaciones y servidores....
realmente no se si aplica para tu caso, solo es un dato que no se si conoces
Hola,
estoy usando xmlrpc-c v.1.01 para poder ejecutarlo en Windows. El caso es que al incorporar un struct para ser devuelto por el servidor me da problemas. Consigo enviar cualquier tipo de dato salvo structs. Sabes cómo hay que utilizarlo para que funcione con structs? Esta función me falla:
estructura_enviada = xmlrpc_build_value(&env,"{s:d,s:d}","min",2,"max",3 );
Gracias,
1 saludo!
DAVID.
Parece que no eres el único porque una búsqueda por google aparecen más problemas como el tuyo.
Yo no he usado structs en mi tcosxmlrpc (enteros, cadenas funcionan bien)