5. solución adoptadabibing.us.es/proyectos/abreproy/12097/fichero/10... · como parte de la...
Post on 18-Jun-2020
3 Views
Preview:
TRANSCRIPT
51
5. Solución adoptada
En este apartado mostraremos la última etapa del diseño y la implementación
final de nuestro sistema. Partiremos de una idea conceptual, en la que se hará uso de
los datos expuestos en los apartados anteriores para realizar un diseño más detallado
del sistema, entrando en bastante pormenores. A continuación se verá que cada
servicio contará con una infraestuctura común a todos ellos, tanto en el servidor como
en los clientes y en la instalación y configuración. Después se enumerarán y explicarán
en detalle algunos de los servicios desarrollados haciendo uso de este sistema, cada
uno tendrá unas peculiaridades distintas que lo hacen digno de mención. Por último
repasaremos los requisitos que expusimos en apartados previos y veremos cuáles y
cómo hemos sido capaces de satisfaces. Si quedara alguna sin cubrir también
explicaríamos porqué se ha sacrificado y qué se ha hecho para mitigar esa falta en el
sistema.
5.1. Idea conceptual
En los apartados anteriores hemos definido los pilares básicos sobre los que se
basará nuestro sistema, a saber: paradigma cliente-servidor, uso del protocolo xml-rpc,
empleo de python en los servidores y php para los clientes web. Estas decisiones si
bien nos muestran un camino a seguir dejan aún muchas características por definir, de
eallas nos ocuparemos en esta sección.
Deberemos resolver, entre otros, los siguientes problemas: ¿cómo ofrece al
usuario los servicios un servidor que exporta más de un procedimiento?, ¿cómo
podemos almacenar y configurar los servicios de forma sencilla y eficiente?,
¿queremos interactividad en nuestro sistema?, ¿cómo solucionamos los posibles
problemas de seguridad que el sistema puede exponer?, ¿qué hacemos con las
peticiones concurrentes a un mismo procedimiento?, ¿cómo respondemos al usuario
en caso de procedimientos que tomen un gran tiempo de ejecución? Intentemos
contestar a estas preguntas una a una.
• ¿Cómo ofrece al usuario los servicios un servidor que exporta más de
un procedimiento?
• ¿Cómo podemos almacenar y configurar los servicios de forma sencilla
y eficiente?
52
• ¿Queremos interactividad en nuestro sistema?
• ¿Cómo solucionamos los posibles problemas de seguridad que el
sistema puede exponer?
• ¿Qué hacemos con las peticiones concurrentes a un mismo
procedimiento?,
• ¿Cómo respondemos al usuario en caso de procedimientos que tomen
un gran tiempo de ejecución?
5.2. Estructura compartida
Por estructura compartida entendemos todos aquellos módulos, ficheros o
funciones que son comunes a los distintos servicios, los que en puridad componen el
sistema cdcrpc. Ya hemos comentado previamente que nuestro sistema operará bajo
el paradigma cliente-servidor, por lo tanto la mayor parte tanto del cliente como del
servidor serán comunes a todos los servicios, diferenciándose simplemente en la parte
que implementa el propio servicio en la parte del servidor y en la parte en la que se
muestran los datos y se pide la interacción del operador en la parte del cliente, que
habrá de adaptarse a las peculiaridades de cada servicio. Asímismo se generará una
infraestructura que facilite la instalación del sistema y unos ficheros de configuración
comunes que permitan indicar claramente y de forma unívoca qué servicios corren en
cada instancia del sistema y en qué condiciones.
5.2.1. Servidor
La infraestructura común en el lado del servidor está formada por varios
ficheros, cada uno de los cuáles se encarga de realizar una función determinada dentro
del sistema, además también se utilizan varios ficheros auxiliares que descargar de
tareas habituales a los principales.
Los distintos ficheros y sus funciones resumidas son:
53
• Cdcrpc.py
Implementa el corazón del superdemonio
(metaservidor).
• Commonfuncs.py
Funciones de uso común, tanto en el
metaservidor como en los distintos servicios.
• Compruebapid.py
Otorga la funcionalidad de detectar una
ejecución previa del superdemonio.
• Cidr.py
Decodifica la notación CIDR para redes1
Cdcrpc.py
Aquí reside propiamente dicho el corazón del sistema de procedimientos
remotos que se ha diseñado. Entre otras se encargará de las siguientes tareas:
comprobar que solo hay una ejecución del metaservidor (con la ayuda de
compruebapid), lectura y carga de la configuración, demonización del proceso y
levantamiento de los distintos servicios.
Hemos dicho previamente que se pretende que un mismo servidor pueda
exportar más de un procedimento, esto lo conseguiremos por una doble vertiente: por
una parte realizando un mapeo de puertos según el servicio. Es decir, servicios bien
diferenciados serán accesibles en distintos puertos de la misma máquina, un poco al
estilo del servidor xinetd de los sistemas unix. Xinetd es un demonio (más adelante
explicaremos en qué consiste exactamente un demonio y en qué se diferencia de un
proceso normal) que se dedica a administrar la conectividad basada en internet,
contiene mecanismos de control de acceso, y de configuración mapeo de puertos. Así
pues tendremos los distintos servicios ofertándose en diversos puertos, la segunda
vertiente hace uso de las características particulares del protocolo xmlrpc, un mismo
servicio puede ofrecer más de una funcionalidad sin más que asignarle un nombre
distinto a cada uno. Podremos tener por tanto el servico RAE en el puerto 33 con las
funcionalidades fija, limpia y da_esplendor y el servicio Cocina en el puerto 44 con las
funcionalidades plancha, horno y microondas.
Como parte de la gestión de seguridad del sistema, los distintos servicios no
están ofertados a todos los equipos, solo ciertas direcciones ip podrán hacer uso de un
1 Esta librería está basada en la original desarrollada por Brandon Sterne en 2007 y publicada bajo
licencia BSD
54
servicio concreto, implementándose así un control de acceso a los diferentes
procedimientos, de esta tarea también se encarga el core del sistema, cdcrpc.py
En la ilustración anterior podemos ver, de manera muy esquematizada, el
desarrollo del proceso de cdcrpc, concretamente lo que ocurre cuando el servicio se
levanta, ya que el estado normal del mismo será estar a la escucha de los distintas
Ilustración 13: Desarrollo proceso cdcrpc.
55
peticiones. Aunque en el diagrama anterior pueda parecer todo un proceso muy lineal
veremos que no lo es tanto. Veámoslo con más detenimiento:
• Llamada cpcrpc.py
Esta es la llamada al script, puede realizarse de dos maneras distintas, bien
pasándole al script una serie de parámetros en la misma línea de llamada bien
facilitándole la ruta de un archivo de configuración. Si se invoca el script sin
ninguna opción intentará encontrar un fichero de configuración en
/etc/cdcrpc/cdcrpc.conf. Qué y cómo se puede configurar mediante un fichero
tiene su propia sección más adelante, detengámonos un momento en las
distintas opciones que el sistema admite:
Opción corta Opción larga Efecto -m <modulepath> --modupath
<modulepath> Ruta donde se encuentran los módulos/servicios.
-e <encoding> --encoding <encoding>
Codificación que se usará en el intercambio de datos.
-s <server> --server <server> Ip que usará el servidor de procedimientos.
-a <allowips> --allowips <allowips>
Ips que podrán acceder a los servicios, separadas por un espacio.
-p <ports> --ports <ports> Puertos donde se lanzarán los servicios, separados por un espacio.
-c <configuration file>
--configfile <configurationfile>
Ruta del fichero de configuración.
-k <servicios> --servicios <servicios>
Servicios/módulos que se quieren iniciar, deben encontrarse en
56
modupath.
-l <fichero de logs>
--logs <fichero de logs>
Ruta del fichero de logs.
-h --help Muestra la ayuda y el uso de las opciones
NOTA: Las opciones –k –p deben usarse consecutivamente para cada servicio, deben coincidir en número.
Una vez leídas las distintas opciones o debidamente parseado del fichero de
configuración sus varlores su guardan en variables internas y se aplican durante
el resto de la ejecución del servicio.
• Comprueba ejecución previa
Aquí se comprueba que la la ejecución que se inicia sea la única del
metaservidor, para ello hace uso de compruebapid.py, por lo que lo veremos el
proceso con detalle un poco más adelante.
• Carga configuración
Previamente hemos explicado las distintas opciones en líena de comando que
el script admite y su significado, así como puesto de manifiesto la posibildad de
emplear un fichero de configuración para definir las características de nuestro
sistema. Realmente en el flujo del programa, tal y como hemos indicado en el
diagrama, esta tarea se realiza después de comprobar que la ejecución del
metaservidor es única.
• Demoniza el proceso
Aunque en un uso cotidiano y para el usuario poco avezado un demonio resulte
equivalente a ejecutar un proceso en segundo plano, nada más lejos de la
realidad. Hay dos diferencias fundamentales, un proceso siempre tiene
asociado quién lo llamó (el tty en entornos unix) y sus salidas van a algún sitio
(normalmente a las salidas estándar, stdout y stderr). En cambio un demonio
carece de esas dos caracterísitcas, no tiene quién lo llamó, el se llamó a si
mismo y, a la vez, sus salidas no van a ningún sitio. A primero vista esto puede
parecer un sin sentido, ¿qué ganamos no sabiendo quién invocó a un proceso y
haciendo totalmente inservibles sus salidas?. Muy simple, aislamiento del
57
entorno, el propio demonio es su entorno y depende de él y solo de él para
poder ejecutarse correctamente. Recordemos que la esencia de un demonio es
estar corriendo continuamente independientemente del resto de programas y
con total fiabilidad.
Para lograr este comportamiento emplearemos una técnica que se denomina
“doble fork mágico”. Un fork no es más que invocar a un proceso desde el
nuestro, el proceso invocado recibe el nombre de hijo y el que invoca el
nombre de padre. Una vez sabido esto podemos explicar el concepto del doble
fork mágico, este consiste en crear un fork de nuestro proceso, desde el hijo
matamos al proceso padre y continuamos corriendo en el hijo. Ahora desde
éste creamos otro fork, ahora el hijo pasa a ser el padre de su propio hijo,
operamos igual, el hijo mata al padre y continua corriendo él; es decir, el
proceso continua en el nieto después de haber matado a las dos generaciones
anteriores. Este método aparte de independizar a los procesos del entorno nos
ayuda a prevenir la aparición de procesos zombies, a que el segundo hijo es
huérfano, asumiendo su control el proceso init, pero se debe tener en cuena
que el primer hijo era un session-leader sin un terminal que lo controlara y era
posible para él adquirir un terminal sin más que abrir uno en el futuro. Sin
embargo el segundo fork garantiza que el hijo no sea un session-leader,
previniendo que el proceso adquier un terminal en el futuro.
Además de eso en esta etapa redirigimos las salidas a /dev/null, es decir, a
ninguna parte, las anulamos, haciendo esto conseguimos prevenir algún error
esporádico que pudiera darse debido a una sobrecarga de buffer debida a una
salida por consola excesiva, es también un requisito indispensable antes de
poder realizar el doble fork mágico.
Por último los otros aspectos que se fijan aquí son asignarle un usuario al script
(y consecuentemente a todo el sistema) para que se ejecute con él, así como
asignarle un directorio actual que no tiene por qué coincidir con en el que se
esté ejecutando.
• Levanta servicios exportados
Por último se levantan los servicios propiamente dichos, para ello abre un hilo
para cada servicio en el cual se invoca al método initServer que debe estar
presente en cada servicio para iniciar el procedimiento que se exporta. Un hilo
no es más que un proceso ligero que comparte ciertos recursos con los otros,
en este contexto y teniendo en cuenta las peculiaridades del lenguaje de
programación y del inérprete python resulta lo más interesante utilizar
58
distintos hilos para los servir las diversas peticiones que puedan llegar a los
diferentes servicios. Esta técnica es utilizada habitualmente cuando se trabaja
en entornos cliente-servidor en el lado del servidor, tal y como nosotros
hacemos.
• Recepción de una petición
Hemos comentado previamente que cada servicio diferenciado se ejecuta en
un hilo de ejecución separado tras ser lanzado por el metaservidor cdcrpc.py,
esto garantiza que se puedan atender diferentes peticiones a distintos servicios
simultáneamente ya que, además, estos están a la escucha en distintos
puertos. Además cada vez que un servicio recibe una petición ocurre lo
siguiente:
1. El sistema abre un nuevo hilo para atender esa petición, esta
característica esta explicada en el siguiente apartado donde hablamos
de las funciones comunes (commonfuncs.py). Volviendo
inmediatamente el hilo padre a estar a la escucha para responder las
peticiones que pudieran llegarle.
2. Se comprueba que la petición recibida proviene de una de las ips
autorizadas, si no es así se aborta la ejecución y termina aquí el proceso,
en caso de estar autorizada se continúa con el procedimiento.
3. El hilo que se ha abierto se encarga de ejecutar el procedimiento
remoto y enviar la respuesta al cliente.
4. Tras enviar la respuesta al cliente el hilo encargad de ejecutar el
procedimiento ha dejado de ser útil y muere automáticamente,
liberando todos los recursos que hubiera utilizado.
En la siguiente figura podemos observar este comportamiento en un diagrama.
59
Ilustración 14: Multihilo y multiinstancia en el metaservidor.
Commonfuncs.py
En este fichero residen las funciones comunes usadas por todos o, al menos,
por varios servicios. Al ejecutarse estos en un entorno similar se le plantean unas
necesidades muy parecidas en multitud de ocasiones; intentamos resolverlas aplicano
el conocido principio de diseño DRY “Don’t repeat yourself!”, no te repitas. Este
principio lo que viene a remarcarnos es la importancia que tiene en el diseño y en la
programación actuales la necesidad de modularizar suficientemente el código y las
funcionalidades que se ofrecen. Usando este principio agrupamos en este fichero
muchas funciones de uso muy común, lo cual nos permitirá también reducir
considerablemente las líneas y el tamaño de nuestros servicios, a la vez que aumentar
60
radicalmente su legibilidad. Además en este fichero se integrarán varias funciones
auxiliares necesarias para la correcta implementación del protocolo xmlrpc y que
extienden sus características dotándole de nuevas funcionalidades hasta convertirlo en
el sistema cdcrpc.
Se encuentran en este fichero las siguientes funciones:
• Logs
La necesidad de esta función se le hace patente al autor de este proyecto
durante el trabajo que llevó a cabo previamente a este proyecto con un gestor
de logs remoto. En el mismo se hizo notar y se evidenció la necesidad
imperiosa de que cada aplicación, especialmente aquellas que son diseñadas
para su uso en una propia empresa o institución (como es el caso de cdcrpc)
usé un mecanismo de registro de eventos estandarizado y fácilmente
entendible por el administrador.
Esta función distingue entre sistemas Windows y basados en Unix. En el primer
caso no se puede asegurar que el sistema cuente con alguna funcionalidad
estándar de log, y el uso del interfaz que Microsoft proporciona para tal tarea
no está extendido hasta el punto de poder considerarse universal, por lo tanto
en sistemas Windows lo que se hará es simplemente escribir los mensaje de
logs que se reciban en un fichero que también se le pasa como parámetro a la
función. Por otra parte cuando el sistema en el que se ejecuta está basado en
Unix, entonces el sistema usa el estándar syslog que se encuentra por defecto
en todos estos sistemas y es un estándar universalmente reconocido y
ampliamente usado. Este sistema tiene la ventaja de que todos los logs se
pueden configurar conjuntamente mediante el gestor de logs, además nos da la
opción de enviar los registros a un repositorio remoto donde se almacenarán y
serán fácilmente consultables por medio de un interfaz web. Aemás de usar
syslog en los sistemas Unix también se escribe el correspondiente fichero de
logs en la ubicación que se le pase como parámetro a la función. Los distintos
grupos para agrupar conceptos similares son:
• auth: registra los intentos de accesos por distintas vías al
sistema.
61
• authpriv: similar al anterior.
• cron: registra las ejecuciones y resultador del programador
de tareas.
• daemon: parar los logs de los distintos demonios del sistema.
• ftp: para conexiones ftp (en desuso).
• kern: los logs del kernel (incluye a iptables).
• lpr: logs de los sistemas de impresión.
• mail: logs de los sistemas de correo.
• news: logs de los sistemas de noticias.
• security: registros de sistemas de seguridad y auditoría (no
incluye iptables)
• syslog: los logs del propio gestor de logs.
• user: para programas creadas por el usuario.
• uucp: para copias remotas en unix sobre sistemas telefónicos
62
(en desuso).
“local0” hasta
“local7”:
libres, para que el usuario las use como quiera.
Después de ver las distintas facilities que nos ofrece el sistema de logs, se ha
decidido registrar las incidencias de éste con la facilidad LOCAL3.
La última característica de la funcionalidad de logs del sistema es que en
función de un parámetro que se la pasa permite la salida de la ejecución
devolviendo un error al entorno, por tanto intentaremos usar siempre que sea
posible la utilidad de logs que se ha implementado tanto para registrar los
eventos de la ejecución como para interrumpir el flujo normal de ésta en caso
de un error crítico, además de esta forma el desarrollador debe
obligatoriamente incorporar una cadena descriptiva que indique la causa de la
anormal terminación del programa.
A continuación mostramos la definición de la función:
• MySimpleXMLRequestHandler
Realmente lo que hacemos aquí es sobreescribir la clase de la implementación
estándar en python de xmlrpc para incorporarle algunas de nuestras
características. Con ese objetivo sobreescribimos dos de los métodos del
manejador: __initi__ y log_request.
En __init__, sobreescribimos el método original añadiéndole dos nuevos
parámetros, la dirección del fichero de logs que se usará para registrar los
distintos eventos y la lista de ips permitidas a hacer uso del servicio que se
exporta remotamente, ambos toman valores vacíos por defecto para permitir
la retrocompatibilidad con llamadas que se pudieran dar al método original.
Además en este iniciador comprobamos si la ip que realiza la consulta está
dentro de la lista de ips que tienen autorizado el uso del procedimiento
remoto, si es así continúa la ejecución normal del servicio tras registrar la
petición, en caso de tratarse de una ip no autorizada, se registro el intento de
def log(string_log, salida, prioridad, logfile):
63
acceso como un intento de violación de seguridad y se deniega el acceso
ignorando la petición.
El otro método que se sobreescribe del manejador original es log_request, el
cual modificamos para integrar la funcionalidad de logs propia antes explicada,
enviar los logs a syslog y diferenciar los archivos de logs según se trate de un
servicio u otro.
• AsyncXMLRPCServer
Esta es otra clase que creamos sobreescribiendo la clase SimpleXMLRPCServer,
clase en la cual se define por defecto en python un servidor xmlrpc. Esta clase
SimpleXMLRPCServer, hace uso a su vez de la clase SokcetServer para iniciar y
mantener las conexiones a bajo nivel. Nosotros forzaremos en lugar de esa
clase el uso de SocketServer.ThreadingMixIn, la cual lanza un nuevo hilo para
atender cada petición distinta, consiguiendo de esta manera que el servidor
este siempre disponible para cualquier número de peticiones y nunca se quede
bloqueado.
• inicia
Esta es la función a la que cada servicio invoca para iniciar su servidor xmlrpc,
se encarga de discriminar la versión instalada de la librería xmlrpc, si esta es
muy antigua al tratarse de un sistema antiguo donde se va a instalar el servicio
exportado se deberán sacrificar algunas características para que el sistema
funcione correctamente, en concreto no podremos definir la codificaciónn
según nuestro criterio como si hacemos en las versiones más modernos.
Es también aquí donde se le pasan los datos y parámetros necesarios a las
clases que hemos visto previamente, también se encargar de liberar el cerrojo
que se usa para la correcta sincronización entre hilos al iniciar los distintos
servicios. Por último es aquí el punto donde se pone realmente al servidor
class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): … def __init__(self, request, client_address, server, logfile=None, ips=[]): … def log_request(self, code='-', size='-'): …
class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
64
xmlrpc a la escucha, previamente habrá que haberle indicado qué clase es la
que contiene los métodos que se quieren exportar.
• leeconf
Esta es una función que lee ficheros de configuración en texto plano y nos
devuelve el valor de la variable que estemos buscando, deberemos
proporcionale los siguientes parámetros para una correcta ejecución:
line: se la pasa la linea que se esta procesando
param:
parametro de comienzo de la linea del fichero de configuracion
que identifica cada parametro distinto
variable: el valor que tomara el parametro en esa linea en concreto
lugar:
el lugar en el que se buscara el valor del parameto en la linea,
también entiende direcciones en formato cidr gracias al módulo
cidr.p
• invoca
Esta función nos perite la ejecución de comandos del sistema, dada la
naturaleza habitual de los procedimientos importados su importancia dentro
del sistema cdcrpc será vital. En principio solo se proporciona una versión
operativa en Linux, aunque sería fácilmente extendible a otros sistemas sin más
que tener en cuenta las peculiaridades de las llamadas a comandos en cada uno
de ellos.
Para ejecutar un comando lo que esta función hace es abrir un subproceso
bloqueante del hilo en ejecución (es decir el hilo esperará hasta que este
subproceso responda o bien exceda un tiempo de ejecución predeterminado).
De este subproceso se captura tanto la salida estándar como la salida de
errores, que serán las variables que se devolverán tras la invocación de la
def inicia(host, Port, cerrojo, codificacion, ExportClass, filelog, allowips):
def leeconf(line, param, variable, lugar):
65
función. Por compatibilidad con sistemas antiguos (versiones de Python
inferiores a la 2.5) el sistema es capaz de detectar que el uso de subprocesos no
está permitida y ejecutar automáticamente el modo “legacy” el cual ofrece
básicamente la misma funcionalidad aunque con una implementación más
sensible a errores en tiempo de ejecución.
Es importante notar que el si el resultado de la llamada a esta función se espera
que tarde un tiempo muy largo en ser devuelto se puede exceder un timeout y
que el sistema devuelva un error cuando no ha sido así, por lo tanto no debería
usarse sin medidas complementarias para comandos que se espera que tarden
más tiempo en responder que el que un uso interactivo nos sugeriría que es
razonable. Como requisito adicional simplemente decir que el comando debe
ser escrito de la misma manera que un administrador lo introduciría en un
terminal, sin ninguna otra modificación.
• utf8
Esta función simplemente toma una cadena codificada en iso-8859-1 (o iso-
8859-15) y devuelve la misma cadena codificada en utf8.
• Mandamail
Envía un correo a una cuenta determinada, y un mensaje y asunto también a
elección del desarrollador. Permite el uso de tildes y caracteres del conjunto
iso-8859-15, hace uso del servidor smtp de la etsi.
Por último comentar como respuesta a la pregunta que nos hacíamos al
comienzo de este apartado que el sistema implementado ofrece un mecanismo
de petición-respuesta, heredado del protocolo usado (xmlrpc), que a su vez lo
hereda del protocolo de transporte HTTP, esto impide un uso interactivo del
mismo de una manera sencilla. Sería posible implemetarlo modificando las
clases que definen los servidores xmlrpc y su manejador (que ya modificamos
para incluir la característica de multihilo y gestión de acceso), pero
def invoca(comando):
def utf8(str):
def mandamail(cuenta, mensaje, asunto):
66
incrementaría notablemente la complejidad del sistema y se escapa del
objetivo para el que el mismo se ha diseñado. Por el momento creemos que en
aquellas acciones que requieran interactividad o una respuesta por parte del
servidor que tome un tiempo prolongado existen mejores alternativas que nos
permiten no desvirtuar el objetivo de este sistema.
Compruebapid.py
En este fichero nos ocupamos de la gestión de procesos, por su propia
concepción, solo puede haber un proceso cdcrpc corriendo simultáneamente en el
sistema, este proceso puede encargarse de levantar y gestionar cuantos servicios se
quiera y con las más variadas funciones, pero no tiene sentido que pueda haber más
de una instancia de un metaservidor corriendo simultáneamente en la misma
máquina.
En el caso de ejecutar servicios inestables o en modo “beta” puede darse el
caso de que, tras una ejecución fallida o un levantamiento incorrecto de los mismos el
propio proceso metaservidor se quede en un estado zombi. Esto no es un problema de
consistencia ya que solo se da cuando, por algún error en el código, el servicio que se
está diseñando devuelve un error al levantarse. Si esto ocurre es habitual que el
sistema linux marque el puerto en el que se intentó usar el servicio como usado y que
no permita su uso por una instancia posterior del mismo. Para evitar este tipo de
problemas y asegurarnos que siempre hay una única instancia del metaservidor
corriendo se crea compruebapid.py.
La forma de actuar de esta función es conceptualmente bien sencilla. En los
entornos Unix cada programa en ejecución recibe un identificador de programa pid
(Program Identifier), este pid es único en cada instante en ese sistema, por lo que
permite identificar unívocamente a un proceso. Una vez que el proceso finaliza su
ejecución el pid se libera para que pueda ser usado por otro programa. Una técnica
habitual para gestionar procesos e instancias de los mismos en entornos Unix es la
siguiente: cada proceso define un fichero .pid que será simplemente un fichero de
texto donde el programa guardará el pid que se le asigne al empezar a ejecutarse.
Ahora bien, antes de guardarlo el programa leerá ese mismo fichero e intentará matar
al proceso que tenga ese pid (tras comprobar que se corresponde con nuestro proceso
y no con otro que el sistema hubiera reasignado), siempre y cuando éste esté activo;
tras esto se actualiza el fichero .pid con el nuevo valor del identificador del proceso
que se corresponde con la ejecución actual.
67
Ilustración 15: Comportamiento compruebapid.
68
Cidr.py
Este es el último y más sencillo de los scripts que compone el núcleo del
sistema cdcrpc, su función es simplemente permitir el uso de la notación CIDR para
direcciones ip en el archivo de configuración. Como previamente hemos indicado está
basado en un código ya existente de Brandon Sterne, licenciado en el año 2007 bajo
licencia BSD, por lo que es totalmente compatible con nuestro sistema. Se ha adaptado
el mismo para que devuelva los datos de la forma que el sistema cdcrpc espera para
poder usarlos.
Lo que hace es simplemente tomar un bloque en notación CIDR y devolver un
array con todas las ips que pertenecen a este bloque, con el fin de que esta puedan ser
usadas para la gestión de acceso que se ha implementado.
5.2.2. Infraestructura mínima en los servicios
Uno de los requisitos de nuestro sistema es que los desarrolladores de servicios
pudieran abstraerse totalmente del entorno o aplicación (en este caso cdcrpc) que se
usa para exportarlos remotamente. Lamentablemente esto no es más que un ideal al
que tender y los desarrolladores de los distintos servicios van a tener que seguir
algunas pautas para que estos puedan hacer uso de la funcionalidad que ofrece cdcrpc.
La primera de ellas ya vimos que tiene que ver con el lenguaje de
programación, los diversos servicios deben ser implementados en python o bien hacer
uso de “interfaces” que los llamen escritas en este lenguaje. Aparte de esa
impondremos otras dos restricciones, aunque serán tan pequeñas que son fácilmente
abstraibles por el desarrollador, éstas son:
Ilustración 16: Comportamiento cidr.
69
• Solo exportamos diversos métodos de una misma clase (normalmente
llamamos a esta clase Exportando, aunque esto no es obligatorio. Ya dijimos en
un principio que xmlrpc es un protocolo sencillo y que solo permite la
invocación a métodos, que en este contexto podrían traducirse como
unívocamente como funciones o funcionalidades, nunca de objetos ni de otras
estructuras más esotéricas.
• El desarrollador debe incluir dos línea siempre al final del fichero donde
implementa el servicio. Estas dos líneas son:
En ellas lo que se hace es definir un método initServer (que será externo a la
clase Exportando y por tanto no se ofrecerá como servicio) que el cual llama el script
encargado del metaservidor (cdcrpc.py) en el momento del inicio para levantar el
servidor, no debemos preocuparnos de los parámetros que este método define ya
que, como hemos visto, son suministrados todos ellos por el metaservidor en el
momento en que se realiza la llamada.
Así, si bien no hemos cumplido el ideal de la transparencia absoluta si que
hemos conseguido que el implementar un servicio cdcrpc sea par aun desarrollador
novel en el sistema sencillo y se limite a aplicar una simple receta, implementar todas
las funcionalidades que se pretendar exportar como métodos de una clase común y
copiar dos líneas, que son siempre iguales independientemente del servicio, al final de
su fichero.
5.2.3. Cliente
En la parte de los cliente hemos de distinguir dos grandes escenarios: los
clientes en línea de comandos que se usan para la depuración y desarrollo de los
servicios y cuando esto son ejecutados automáticamente sin necesidad de la
intervención de un operador (como el caso de la gestión automática de inventario) y
los cliente web, pensados para permitir una interacción con el operador sencilla y
amigable. Los primeros al no tener grandes requerimientos de presentación (ninguno
en algún caso) son notablemente más sencillos de implementar; los segundos son más
complejos por dos motivos: debemos tener en cuenta qué datos o información
def initServer(host, Port, cerrojo, encoding, allowips): commonfunc.inicia(host, Port, cerrojo, encoding, Exportando, ficherologs, allowips)
70
recuperar para presentársela al usuario y, además, la implementación de xmlrpc en
php si bien robusta y completa no es tan extremadamente sencilla de usar como lo es
la de python.
La forma de crear un cliente en línea de comandos es muy simple y elegante
simplemente habremos de definir lo siguiente:
• Una url donde acceder al servicio, es la dirección ip donde se ofrece el
servicio seguida del puerto en el que éste está a la escucha, por ejemplo
• Después deberemos crear un objeto xmlrpcclib (un cliente xmlrpc), al
que le pasaremos como parámetros del constructor la url anteriormente
definida y la codificación que hayamos escogido para realizar nuestra
transferencia, en nuestro caso será habitualmente iso-8859-1.
Previamente hemos de haber importado el módulo xmlrpc en python,
xmlrpclib.
• Sobre ese objeto cliente que acabamos de crear invocamos el método
remoto que queramos ejecutar, suministrándole, obviamente, los
parámetros necesarios.
Con estas sencilla tres línea hemos construíod un cliente cdcrpc en línea
de comandos.
Como comentamos en la sección referente a php, para implementar los clientes
web usaremos la implementación de xmlrpc de PEAR. Si bien es cierto que
actualmente esta no es la implementación más sencilla de usar disponible para php, en
el momento de iniciar el desarrollo de este proyecto eras la implementación más
madura y estable de las disponibles, queda para futura versiones del sistema su
sustitución por alguna implementación más reciente. Lo primero que deberemos hacer
es intalar PEAR en nuestro sistema usando el gestor de paquetes de nuestra
distribución y después, usando la propia funcionalidad que PEAR nos ofrece instalar el
módulo de xmlrpc.
url="http://192.168.160.245:11112/"
s = xmlrpclib.ServerProxy(url, encoding=codificacion)
resp1, resp2 = s.serviciodeprueba(param1, param2)
71
Cada clase que vaya a hacer uso de la funcionalidad de xmlrp deberá incluir la
clase RPC.php.
Ademá de la inclusión de esta clase se han desarrollado un conjunto de
funciones que solucionan situaciones comunes que se daban al usar los cliente cdcrpc
desarrollados en php. La mñas normal de estas situaciones es aquella en la que se el
servicio responde con dos parámetros (normalmente tras ejecutar alguna orden en el
sistema), siendo el primero de ellos la respuesta que se mostraría por la salidad
estándar y el segundo la que se mostraría por la salida de error. Por convención
cuando alguno de estos dos parámetros se encuentra vacío se devuelve la cadena
‘NONE’.
En el cliente php se recibe un único parámetor (digamos $resp) que contiene
varios elementos diferenciables por claves, el primero de ellos es $resp-
>faultcode(), el cual nos indica con un código numérico si se ha producido algún
problema en la acción achacable a la comunicación (no a las propias tareas que el
servidor ejecute en cada caso). Las otra claves interesantes son $resp-
>faultstring() que contiene una descripción del problema que se ha producido
entendible por humanos y $resp->value() que contiene los valores devueltos por el
servidor cdcrpc en caso de éxito. El caso es que además en $resp->value() la
implementación en php de xmlrpc que usamos solo captura un parámetro de entrada,
siendo éste un vector con tantos elementos como parámetros devolviera realmente el
servidor, en nuestro caso un array con dos elementos (el primero la salida estándar y
el segundo la salida de error) cada uno de los cuales puede a su vez ser otro vector.
Esto será en caso de éxito en la comunicación, es decir que no se hubiera producido
ningún fallo en la comunicación, el servidor estuviera disponible, etc…, el sistema
indica indica esto con un valor 0 correspondiente a la clave $resp->faultcode().
5.2.4. Instalación
El sistema cdcrpc si bien no es complejo si que hace uso de las convenciones
habituales en los sistemas Unix, posee un archivo de configuración que se espera que
pear install XML_RPC
o bien
php pyrus.phar install pear/XML_RPC
72
esté en el directorio /etc y un script de inicio que se espera que esté en /etc/init.d
y al que se enlazará simbólicamente desde el directorio correspondiente a nuestro
nivel de ejecución (/etc/rc2.d normalmente). Además tanto el fichero de
configuración como el script de inicio esperan que el código a ejecutar se encuentre en
un determinado lugar (/home/centro/scripts/cdcrpc por defecto) para que todo el
sistema funcione correctamente.
El fichero de instalación se ha implementado solamente para sistemas Unix
(podría adaptarse a Windows, pero no existe la necesidad de utilizar tantos servidores
cdcrpc en esta plataforma como para justificar su desarrollo), únicamentte debemos
tomar dos precauciones: colocar los servicios diseñados en el directorio módulos justo
en el mismo nivel donde se encuentre el instalador y el resto de archivos del sistema
cdcrpc; la segunda precaución que debemos tomar es modificar el archivo de
configuración, que explicaremos más adelante, para que tenga las características que
nosotros queramos, si se nos olvida, siempre podremos modificarlo en su ubicación
por defecto posteriormente sin ningún tipo de problemas.
El fucionamiento del script es bastante simple, primero intenta crear el
directorio donde se espera que estén los scripts /home/centro/scripts/cdcrpc,
después copia tanto los ficheros de la infraestructura común como de los servicios a
ese directorio. Tras esto procede a copiar el fichero de configuración y el script de
inicio a sus ubicaciones por defecto y otorgarles los permisos oportunos. Por último
crea los enlaces simbólicos correspondientes a los niveles de ejecución más habituales
(/etc/rc2.d, /etc/rc3.d, /etc/rc5.d) con una prioridad baja (S98) para darle
tiempo al sistema a levantar previamente toda la infraestructura de red. Tras haber
realizado todas estas tareas con éxito procede a levantar el metaservidor y,
consecuentemente, los servicios que se hubieran configurado.
73
Ilustración 17: Esquema funcionamiento del instalador.
74
5.2.5. Configuración
Para conformar el fichero de configuración se ha optado por uno de los
formatos más clásicos existente, un simple fichero de texto plano (cdcrpc.conf) en el
cual se encuentran una serie de elementos en la forma CLAVE = VALOR. Esto es así
para contribuir al objetivo de que el sistema sea realmente sencillo de usar, asumimos
la convención de los ficheros de configuración clásicos en entornos Unix, con los que la
inmensa mayoría de los desarrolladores deben estar acostumbrados.
El fichero de configuración que se proporciona con la instalación contiene
(tamnién al estilo Unix) una serie de comentarios que pretenden hacer que sea
autoexplicativo, es decir, se pueda usar y configurar sin necesidad de consultar
ninguna otra documentación. Los parámetros que se deben definir son:
• MODULEPATH: nos indica la ruta absoluta donde se encuentran los
scripts que implementan los distintos procedimientos.
• LOGS: ubicación (también absoluta) del fichero de logs que registrará los
eventos del sistema.
• ENCODING: la codificación que se usará en el intercambio de
información entre el cliente y el servidor por defecto.
• MYIP: dirección ip en la que el servidor está a la escucha, por motivos de
política este debe ser un valor único, aún cuando el equipo en el que el
servidor corra tenga varios interfaces.
• ALLOWIP: ip que tiene autorizado el acceso, cada ip distinta debe ir en
una entrada del tipo ALLOWIP = xxx.xxx.xxx.xxx independiente, se puede
usar la notación CIDR para permitir el acceso a bloques enteros de
direcciones.
• SERVICE: indica el puerto en el que se iniciará cada módulo, así como,
opcionalmente el uid de usuario bajo en que éste correrá. El nombre del
módulo es el nombre del archivo python que lo implementa quitándole
la extensión .py.
75
• VERBOSE: si está a ON el sistema no se demonizará y mostrará salidas
para depuración en el terminal desde el que se le llame, este modo no
es estable para entornos en producción, por lo que en estos debe
establecerse a OFF
A continuación podemos observar un ejemplo de fichero de configuración
donde se observa su carácter autoexplicativo.
5.2.6. Script de inicio
Es habitual en los sistemas Unix cuando se quiere que un programa se ejecute
como un demonio desarrollar para el mismo lo que se llama un script de inicio. La
existencia y necesidad de estos ficheros está relacionada con las particulares
características de los demonios que hemos explicado anteriormente. Un script de
#################################################################### #Archivo de configuracion del metaservidor xml, indica que puertos # #están activos, que modulos se cargan (uno a uno), y, opcionalmente# #el uid de usuario con el que ejecutar ese modulo. # #################################################################### #RUTA PARA LOS MODULOS PROPIOS #MODULEPATH = /ruta/a/mis/modulos MODULEPATH = /home/centro/scripts/cdcrpc #FICHERO DE LOGS LOGS = /var/log/cdcrpc #CODIFICACION EN EL ENVIO XMLRPC ENCODING = iso-8859-15 #MI IP, PARA CASO CON VARIOS INTERFACES, ELEGIR SOLO UNA MYIP = 192.168.160.xxx #MYIP = localhost #IPS PERMITIDAS ALLOWIP = 192.168.160.xxx ALLOWIP = 127.0.0.1 ALLOWIP = 172.16.3.xxx ALLOWIP = 172.16.3.xxx ALLOWIP = 172.16.3.xxx ALLOWIP = 172.16.3.xx ALLOWIP = 193.147.160.xxx #SERVICE = PUERTO MODULO [UID] #SERVICE = 10222 modulo 1253 #SERVICE = 7777 serverrpc SERVICE = 11111 sisgelect #SERVICE = 9999 servernohay #OFF -> SIN SALIDA, ON -> MODO DEBUG VERBOSE = OFF
76
inicio no es ni más ni menos que un fichero en bash (o en otro intérprete de órdenes
Shell). Debe situarse necesarimente en el directorio /etc/init.d y poseer permisos
de ejecución. Se invoca de la siguiente manera:
donde orden es alguna de las siguientes:
• Start: permite iniciar el funcionamiento del demonio (se debe implementar
obligatoriamente).
• Stop: permite detener el funcionamiento del demonio (se debe implementar
obligatoriamente).
• Restart: permite detener una instancia del demonio y, acto seguido, iniciar otra
(implementación opcional).
• Status: devuelve si el servicio se está ejecutando actualmente o no (implementación
opcional).
En nuestro caso hemos implementado las cuatro órdenes ya que pueden
resultar de gran utilidad en algún momento. Otro de las características importantes de
los scripts de inicio es que permiten (tras crear un enlace simbólico en el nivel de inicio
correspondiente tal y como explicamos cuando tratamos el instalador), que el
demonio se inicie automáticamente cada vez que el sistema Unix arranque. Este hecho
por sí solo ya justificaría la creación de este script de inicio, además de las
funcionalidades que hemos visto antes.
5.3. Servicios
En este epígrafe comentaremos y detallaremos brevemente algunas de las
utilidades y servicios que se han implementado aprovechando la infraestructura que el
sistema cdcrpc provee y que son, por tanto, parte integrante de este proyecto.
5.3.1. Sistema gestión eléctrica
El Centro de cálculo cuenta con un sistema de alimentación ininterrumpida
consistente en uno SAIS que dan servicio cada uno a un rack de servidores,
previniendo a los equipos alojados en esos racks contra posibles cortes de corriente y
picos de tensión. Estos SAIs si bien son profesionales y proveen una capacidad más que
aceptable presentan un problema, solo son capaces de sostener las necesidades
service nombre_del_script orden
77
energéticas de los equipos en ausencia de corriente por un tiempo bastante corto (30
minutos como máximo). Para gestionar esto se diseña un sistema que continuamente
monitoriza el estado del SAI (en concreto si goza de alimentación eléctrica y el nivel de
batería restante), este trabajo, en el que también colaboré, si bien muy interesante es
ajeno al propoósito de este proyecto.
En cambio se hace necesario poder acceder a la información acerca del estado
de los SAIs en tiempo real de una forma sencilla, con este propósito se desarrolla un
servicio cdcrpc que ofrece las siguientes funcionalidades:
• Consulta las variables del SAI: En concreto nos permite conocer el
estado de la carga restante en la batería, la frecuencia y el voltaje de
salida de la corriente, la capacidad del SAI que está siendo usada, el
estado del SAI (si está conectado a la corriente, en bypass o
alimentando a los equipos a través de sus baterías), el tiempo que llevan
en uso las baterías, el estado de la batería y si es necesario el cambio de
estas. Entre estas variables son especialmente importantes y útiles la
capacidad del SAI en uso, que nos da una idea de cuántos equipos más
puede soportar y de cuán rápida va a ser la descarga de la misma; otra
variable que merece ser destacada es el estado de las baterías, ya que el
propio SAI no emite ninguna alerta cuando éstas empiezan a
malfuncionar y a través del interfaz web que se ha diseñado se puede
consultar muy fácilmente.
• Apagar todos los equipos: Esta funcionalidad nos puede resultar
especialmente útil para desconectar los servidores ante un corte de
corriente programado por motivos de mantenimiento o mejora de las
infraestructuras, solo se permite apagar todos los equipos y no cada uno
individualmente por motivos de seguridad.
• Encender todos los equipos: Es la otra cara de la moneda de la
funcionalidad anterior, tras un corte de corriente puede resultar muy
útil y cómodo encender todos los equipos desde el interfaz web.
• Configurar armario: Permite indicarle al sistema qué equipos son los
que tiene que monitorizar y sobre cuáles se ejercen las acciones
anteriores, todo a través del propio interfaz web ubicado en el SIG.
78
5.3.2. Cambia Rembo
Este servicio es muy sencillo, el servidor cdcrpc lo único que hace es invocar a
un script sh diseñado previamente que se encarga de reiniciar el servicio de Rembo y el
servidor dhcp de los servidores encargados de gestionar las imágenes de las salas del
Centro de Cálculo. Este es un claro ejemplo de una de las funcionalidades que se
tenían en mente cuando se diseñó el sistema cdcrpc, permitir el acceso mediante un
interfaz web sencillo a operadores sin privilegios mientras el acceso al resto de
funciones y opciones de la máquina sigue vetado por seguridad.
Ilustración 18: Interfaz web del sistema de gestión eléctrica.
79
Ilustración 19: Interfaz web cambiarembo.
5.3.3. Monitorización de red
Probablemente este sea una de los servicios más complejos implementados
hasta el momento, su origen proviene de un sistema de monitorización de red ya
existente basado en la herramienta mrtg, dicho sistema que estaba aislado en un
equipo y constituía una herramienta completamente aparte del resto de los que
disponía el Centro de Cálculo se integra en el SIG y en ese momento se plantea
extenderlo y adaptarlo a las necesidades peculiares del centro. Debido a la política de
asignación y uso de direcciones ip en la ETSI es común que sea necesario conocer qué
mac o dirección física está asociada a un puerto de un conmutador o switch de acceso
en un momento dado, también puede resultar muchas veces muy interesante y
necesario realizar esta búsqueda en el sentido contrario, partir de una dirección física y
encontrar entonces a qué puerto de qué conmutador se encuentra asocidada.
Estas búsquedas se realizan mediante una serie de consultas SNMP (Simple
Network Management Protocol) enlazadas, es particularmente interesante el caso de
la búsqueda de a qué puerto se encuentra asociada una dirección mac, ya que en este
caso lo que se hace es buscar todas las macs que se encuentran asociadas a todos los
puerteos de todos los switchs de la ETSI y, para cada switch, se procede a buscar si la
80
mac buscada coincide con alguna de las que se devuelven. Para agilizar este proceso
(puede haber del orden de 40-50 switchs en toda la escuela), se recurre a una
implementación multihilo, abriendo un hilo distinto para cada switch en el cual se irán
realizando las sucesivas consultas SNMP. Para mantener los hilos sincronizados se usa
un mecanismo de espera en el hilo principal que se mantiene en stand-by hasta que
todos los hilos hijos han terminado, para comprobar finalmente si la mac que se busca
está asociada a algún puerto se crea un fichero que pasa a ser consultado por el hilo
principal tras la finalización de todos los hijos, este fichero habrá sido creado por el
hijo que haya encontrado la mac y contiene la dirección del switch y el puerto en el
que la mac está asociada. Si este fichero no existe es que la mac no está en ese
momento asociada a ningún puerto de todos los disponibles en la ETSI, para prevenir
falsos positivos en futuras ejecuciones el hilo principal borra este fichero una vez que
lo ha leído.
Además también se aprovecha el desarrollo de esta funcionalidad para
extender la información ofrecida por la herramienta mrtg y mostrar al realizar las
consultas sobre un conmutador la mac que debería tener asociada cada puerto
(obtenida de una base de datos) enfrentada a la que realmente tiene (obtenida
mediante el uso del servicio cdcrpc). A continuación podemos ver un ejemplo:
Ilustración 20: Interfaz web del sistema de monitorización de red.
81
Ilustración 21: Macs en uso en un conmutador.
5.3.4. Operaciones sobre pantallas informativas
La ETSI cuenta con un gran número de pantallas informativas y con un sistema
diseñado e implementado ad hoc con el fin de gestionar los recursos que en ellas se
82
muestran (screanman, objeto de otro proyecto por parte de Luis Orellana en el ámbito
del Centro de Cálculo). Este sistema es autónomo y no requiere (o no debería requerir)
intervención externa para su correcto funcionamiento, de todas formas se le ha
dotado con una serie de servicios cdcrpc que faciliten la gestión y mantenimiento del
sistema screanman sin necesidad de acceder a los equipos que lo contienen ni conocer
las interioridades del sistema. El interfaz web que da acceso a los servicios que se
ofrecen consta de las siguientes funcionalidades:
Ilustración 22: Interfaz web operaciones sobre pantallas informativas.
• Lanzar screnman: El sistema screanman se ejecuta periódicamente con
el fin de comprobar si se han producido cambios en las programaciones
a mostrar en las pantallas, general los nuevos contenidos y refrescar la
información si fuera necesario. El tiempo entre sucesivas ejecuciones
del sistema no es excesivo, pero en ciertas ocaciones puede ser
conveniente no tener que esperara ese tiempo y lanzar directamente el
sistema tras modificar las programaciones a mostrar, con ese objetivo
es con el que se ofrece este servicio.
• Resetear screanman: En ciertas ocasiones y ante eventos imprevistos y
fuera de nuestro control (caída prolongada de la corriente eléctrica,
picos de tensión, …) se han detectado muy raros cuelgues del sistema
screanman, así como congelación de la información mostrada en las
83
pantallas. Con la implantación del sistema de gestión eléctrica detallado
previamente estas incidencias se han reducido sustancialmente hasta
casa desaparecer, aún así en ciertas ocasiones puede ser necesario
realizar un reseteo completo del sistema para que este regenere
completamente los contenidos a mostrar. Esta opción nos lo permite de
una manera sencilla.
• Diagnosis pantallas: La gestión del sistema de cartelería electrónica de
la ETSI es compleja debido a la multiplicidad de actores implicados en la
misma: el Servicio de Medios Audiovisuales (encargado del correcto
funcionamiento y configuración de las pantallas propiamente dichas), el
Gabinete de Comunicaciones (encargado de la generación de los
contenidos y la gestión de las programaciones) y el propio Centro de
Cálculo (encargado de la gestión del sistema y de los decodificadores,
así como de la red). Por ello se ha diseñado un servicio que permite
diagnosticar simplemente apretando un botón cualquier incidencia que
se pudiera producir en el sistema de cartelería electrónica, permitiendo
localizar el problema de una forma rápida y detectar al responsable del
mismo para una rápida solución.
84
Ilustración 23: Interfaz web diagnosis de pantallas.
85
5.3.5. Mensajería
En el antiguo sistema de mensajería (correo) electrónica de la ETSI se
implementan una serie de servicios que permiten la gestión de todas las operaciones
habituales (creación de cuentas, cambio de fecha de expiración, cambio de contraseña,
cierre de cuentas) a través de un formulario web y por parte de cualquier operador, lo
que supuso un gran avance respecto a la situación anterior en la que cualquier
operación sobre una cuenta de correo debía hacerse por un especialista directamente
sobre la línea de comandos del servidor. Este fue el primer servicio cdcrpc que se
implementó y que demostró toda la potencia y funcionalidad del sistema. No obstante
el sistema de mensajería electrónica ha sido renovado recientemente basándose en
una suite completa (Zimbra) y ha requerido la creación de nuevos módulos cdcrpc
para seguir ofrecinedo las mismas funcionalidades que ya había, en breve
comentaremos estos servicios.
5.3.6. Gestión automática de inventario hardware
En la línea de las recomendaciones ITIL el Centro de Cálculo se está preparando
para dar los primeros pasos en su aproximación a un inventario completo. En este
contexto se pretende inventariar todo el hardware del que se hace uso (ya
comentamos en apartados anteriores que consta de varias decenas de servidores, casi
cien equipos de aulas de docencia y varios centenares de equipos en las propias salas
del Centro de Cálculo destinados a prácticas tuteladas y por libre). En este sentido se
implementa un complejo sistema de inventario hardware que hace uso, para la
transmisión de la información, de la infraestructura ofrecida por cdcrpc. Este sistema
tiene la peculiaridad de que los clientes deben trabajar indistintamente en sistemas
tipo Linux y Windows, así como permitir el envío de una gran cantidad de datos (todos
los referentes al hardware y software del equipo que lo aloje).
Explicaremos brevemente el funcionamiento de este servicio:
• Hardware:
1. El servicio recopila todos los datos hardware de un equipo
haciendo uso de la utilidad dmidecode y los almacena en un
fichero de texto plano.
2. Se calculo el hash del “hardware”, es decir, del fichero de texto
plano que contiene los elementos del equipo.
86
3. Usando un cliente cdcrpc se envía este hash a un servidor cdcrpc
para compararlo con el que había almacenado en una base de
datos.
4. Si este hash es el mismo que se correspondía a ese equipo el
proceso termina aquí
5. Si el hash es distinto o nuevo, en el equipo cuyo hardware está
siendo revisado se activa otro cliente cdcrpc que envía el fichero
con todos los datos de hardware al servidor cdcrpc.
6. El servidor cdcrpc se encarga de comprobar los datos del fichero
de hardware y actulizar la base de datos con los cambios que se
hayan producido, calculando hash individuales para cada
elemento hardware que figura en el fichero.
De esta forma se logra mantener actualizado sin ningún esfuerzo todos los
datos relativos a casi medio millar de equipos que son responsabilidad del Centro de
Cálculo.
Ilustración 24: Esquema de funcionamiento gestión automática de inventario software.
87
De manera totalmente análoga funciona el sistema de inventario de software,
solo que con un fichero de software. Su ejecución se produce justo después de la del
sistema de hardware y permite tener conocimiento en todo momento de todos los
programas que están instalados en cada máquina responsabilidad del Centro de
Cálculo.
5.3.7. Nuevos módulos
Uno de los requerimientos del sistema cdcrpc era que fuera muy sencillo de
utilizar para los operadores pero, también, que fuera enormemente simple el
desarrollo de nuevos módulos por parte de personas ajenas al desarrollador original
del sistema. Este objetivo parece cumplido puesto que varios compañeros (tanto
becarios como personal del CdC) han realizado varios módulos que se apoyan en el
sistema cdcrpc para mejorar a aportar soluciones a sus sistemas, algunos de ellos son:
• Monitoreo de la temperatura de los servidores.
• Comprobación de servicios en servidores.
• Gestión de equipos en alta disponibilidad
Mención expresa merecen los servicios asociados al servicio de mensajería
electrónica de la ETSI, este servicio ha sido renovado y actualizado hace muy poco
tiempo, requiriendo de la actualización de todos los módulos cdcrpc que se habían
desarrollado para el sistema previo con el fin de adaptarlo al nuevo sistema de
mensajería. El compañero Víctor Ponferrada (autor de la renovación del sistema de
correo de la ETSI, el cual constituye su proyecto fin de carrera), se ha encargado de
desarrollar e integrar estos módulos, tomando ideas cuando era conveniente de los
que se encontraban implementads para el sistema anterior. Algunas de las
funcionalidades que este sistema ofrece son:
• Creación de cuentas de mensajería.
• Eliminación de cuentas.
88
• Consulta de cuentas.
• Creación de alias.
• Eliminación de alias.
• Consulta de alias.
• Bloqueo de cuentas.
• Desbloqueo de cuentas.
• Consulta del estado de una cuenta.
• Cierre de cuentas.
• Cambio de contraseña.
Actualmente se encuentran bajo desarrollo varios módulos más que hacen uso
de las funcionalidades que cdcrpc ofrece para abstraerse de la red.
5.4. Implantación y puesta en funcionamiento
La implantación y puesto en funcionamiento de este proyecto se ha realizado
en distintas etapas a lo largo de, aproximadamente, unos 9 meses. La modularidad del
mismo ha propiciado que el periodo de implantación haya sido dilatado en el tiempo,
debido a que se han ido diseñando nuevos módulos conforme se detectaban nuevas
necesidades en el servicio.
89
El orden en el que se han ido implantando los distintos módulos que se
comentan en el apartado anterior ha sido el siguiente:
• Mensajería.
• Cambia Rembo.
• Sistema de gestión eléctrica.
• Monitorización de pantallas informativas.
• Monitorización de red.
• Gestión automática de inventario.
Unos de los principales problemas que me encontré en la puesto en
funcionamiento del sistema era que el metaservidor y todas las funciones comunes
que forman parte del núcleo del sistema se diseñaron pensando en una versión de
python igual o superior a la 2.5, que era la más antigua que traía el sistema Debian
(usado en la mayoría de los servidores). Sin embargo en la implantación del primer
servicio que se fue a poner en producción, el de mensajería instantánea, el equipo
corría un sistema operativo más antiguo que solo disponía de la versión 2.3 del
intérprete de python, sin posibilidad de actualizaciónn al tratarse de un servicio crítico
y por políticas de seguridad. Esta característica supuso el rediseño de algunas partes de
la infraestructura común que hacía uso de características de python más avanzadas,
especialmente las relativas a la gestión de subprocesos.
En la implantación de los distintos servicios, especialmente el de mensajería
electrónica y cambia rembo se debía realizar una interacción intensa con el sistema,
usando en ambos casos scripts que habían sido diseñados previamente y que podrían
calificarse como “legacy code”. Careciendo estos de una documentación extensa y
teniendo que recurrir en ocasiones a la ingeniería inversa para conseguir integrar esos
scripts en el comportamiento del sistema y exportarlos correctamente.
El caso de los módulos de gestión eléctrica y operaciones sobre pantallas
informativas es completamente distinto, ya que se trata de nuevos servicios en cuyo
diseño e implementación participé y que, desde un principio, se diseñaron pensando
en la posibilidad de ser exportados remotamente para su uso o gestión a través de un
90
interfaz web. Esta diseño hizo que la implementación de sus respectivos módulos fuera
más sencilla y elegante.
El módulo de monitorización de red supuso todo un reto, ya que consistía en
integrar un subsistema de monitoreo existente (mrtg), y a la par, ofrecer una serie de
funcionalidades de consulta avanzadas en un entorno de red en el que solo se contaba
con permisos de usuario, no de gestor. La solución pasó por un estudio intenso de
SNMP y la lectura de multitud de paper de las grandes compañías de
telecomunicaciones (Cisco especialmente), hasta hallar la forma en la que se podían
conseguir los datos que queríamos dadas nuestras limitaciones. Además aquí nos
encontramos con el problema de que queríamos (en ocasiones) monitorizar toda la red
(en torno a unos 60 equipos de red) en un tiempo prudencial. El primer enfoque fue la
consulta secuencial de los equipos, teniendo en cuenta que cada equipo puede tardar
en responder un tiempo cercano al minuto nos dimos cuenta en seguida de que esa
aproximación no era posible. Además había que lidia con la posibilidad de que un
equipo estuviera indisponible por cualquier motivo, por lo que nuestro programa no se
podía quedar eternamente a la espera de la respuesta de ese equipo. Por suerte el
timeout predefinido parecía tener un valor razonable, sin embargo si varios de estos
equipos se encontraban indisponibles, el tiempo de ejecución total del módulo
alcanzaba unos valores prohibitivos. Finalmente se optó por una implementación
multiproceso en la que se realiza una sincronización a través de un token, pasando de
un tiempo de ejecución de ~60*tiempo_consulta_equipo en la implementación
monohilo ,a un tiempo de ~2*tiempo_consulta_equipo en la implementación
multihilo.
El caso de la gestión automática de inventarios es un muy buen ejemplo de lo
que puede llegar a aportar el sistema cdcrpc bien usado. El sistema contempla mucho
más que su módulo cdcrpc y su explicación completa y detallada daría para otro
proyecto fin de carrera. Es un sistema complejo, maduro y que hace uso de varias
tecnologías aunadas con un objetivo común: conseguir algo similar a lo que las
recomendaciones ITIL recogen como base de datos de inventario. Aquí se necesitaba
de un sistema que transmitiera datos (también archivos en este caso) a traves de la red
en unas ocasiones y bajo unas condiciones muy precisas, el uso de cdcrpc permitió
olvidarse completamente de que el programa funcionaba en diversas máquina y
abstraerse de la complejidad que la red brindaba al escenario, mostrando la potencia
del sistema.
91
A continuación realizamos una estimación del coste que habría tenido el
desarrollo de este sistema a precio de mercado. Utilizaremos para ello el método
Cocomo. Veamos primero el número de líneas de código de cada subsistema:
• Núcleo del sistema
Fichero LDC
cdcrpc.py 312
cidr.py 107
commonfunc.py 378
compruebapid.py 114
instalacdcrpc 91
cdcrpc.conf 45
cdcrpc.init 88
TOTAL 1135
• Gestión automática de inventario
Fichero LDC
confclient.conf 8
confserver.conf 12
disk.py 144
net.py 197
procesaDBserver 1648
servicemod.py 80
sws2.py 786
sws2server.py 469
TOTAL 3344
• Sistema gestión eléctrica
Fichero LDC
sisgelect.py 259
TOTAL 259
• Operaciones sobre pantallas informativas
Fichero LDC
fileconf.py 79
screanman.py 481
TOTAL 560
• Cambia Rembo
Fichero LDC
cambiarembo.py 56
92
TOTAL 56
• Monitorización de red
Fichero LDC
macpuerto 560
buscamac 412
TOTAL 972
Dando un total de 6844 líneas de código o, aproximadamente 6.9K líneas.
Considerando el proyecto como orgánico obtenemos, usando el método Comoco antes
reseñado, un total de 18.24 personas/ mes; lo que implicaría que una persona debería
haber empleado 18.24 meses en terminar el trabajo que engloba este proyecto.
Tomando como referencia un salario anual para un desarrollador de 32.000 euros, el
coste estimado del proyecto sería de unos 50.000 euros.
5.5. Recuento de requisitos
A continuación realizaremos un breve recuento de los requisitos que nos
planteamos en un inicio, veremos cuáles hemos alcanzado, cuáles ha habido que
abandonar por el camino y cómo hemos logrado satisfacerlos. Recuperamos los
requisitos que expusimos en el epígrafe 2:
93
• Requisito: Debe poder desplegarse en distintas plataformas y sistemas
operativos sin necesidad de una adaptación previa, en concreto debe ser capaz
de ejecutarse al menos en los siguientes sistemas:
o Windows, a partir de Windows XP en adelante.
o Linux, cualquier núcleo moderno (al menos 2.6 en adelante),
independientemente de la distribución o el sabor elegido.
Cómo: La elección de python, al ser un lenguaje interpretado multiplataforma,
para la implementación de los servidores nos ayuda en gran medida, en
ocasiones que se requiere del uso de funciones propias del sistema operativo se
discrimina entre plataformas y se hace uso de la adecuada a la máquina en la
que se encuentre el sistema.
• Requisito: Para el usuario operador no debe ser necesaria la realización de
ninguna tarea adicional a la que realizaría si la aplicación corriera en local.
Cómo: Mediante el uso generalizado de interfaces web se consigue abstraer al
operador de toda la complejidad subyacente al procedimiento que ejecute,
limitándose la operativa en la mayoría de los casos a pulsar un botón o rellenar
un formulario con datos no técnicos.
• Requisito: El desarrollador debe ser capaz de exportar aplicaciones sin un
conocimiento profundo del sistema, lo ideal sería de forma transparente. Es
admisible que el desarrollador tenga que realizar alguna mínima adaptación de
su programa, pero esta no ha de exigirle en ningún caso más que la aplicación
de una simple “receta”, en absoluto realizar modificaciones de cierto alcance.
Cómo: Hemos observado que para exportar un servicio éste solo debe cumplir
dos condiciones; definir las funcionalidades como método de de una clase,
incluir algunos módulos al comienzo del fichero e incluir siempre las dos
mismas líneas al final del mismo.
• Requisito: El servicio debe ser fiable e inmune a los problemas de red.
Cómo: La mayor parte de esta tarea recae en el protocolo de comunicaciones y
procedimientos remotos escogido, xmlrpc, el cual implementa numerosos
mecanismos como hemos visto para hacer el intercambio de los datos que el
servicio requiera fiable e inmune a los problemas no severos de red.
• Requisito: Debe poder usarse con varios lenguajes de programación,
principalmente los siguientes, de uso común en la política del centro de
cálculo (aunque debe ser fácilmente extensible a otros):
o PHP, para la creación de interfaces de usuario mediante web.
94
o Python, para la creación tanto de clientes como servidores.
Cómo: El protocolo xmlrpc cuenta con implementaciones para todos los
lenguajes de programación de uso común. En los lenguajes mencionados se
han implementado funciones que resuelven situaciones comunes e
implementaciones de referencia del sistema cdcrpc que permiten su uso
sencillo.
• Requisito: El sistema debe ser capaz de exportar múltiples servicios en la
misma máquina, así como de enviar múltiples peticiones a distintos servicios
desde una misma máquina origen.
Cómo: Hemos visto que el sistema mapea distintos servicios en distintos
puertos, abriendo un hilo de ejecución distinto para cada servicio que no
interfiere con los demás. En el lado de las peticiones del cliente se puede
implementar también una arquitectura multihilo o, simplemente, enviar una
petición tras otra, el sistema es capaz de distinguirlas y tratar a cada una
individualmente.
• Requisito: Se debe implementar algún mecanismo que gestione la
concurrencia de peticiones, mediante cualquier procedimiento que se juzgue
adecuado.
Cómo: Se explicó en un apartado anterior que por cada petición que recibiera
un servicio, este creaba una instancia de la clase del servidor cdcrpc para
gestionarla, esta instancia está aislada en memoria de otra instancia de la
misma clase y varias pueden coexistir simultáneamente sin peligro alguno para
la integridad de los datos, por lo que se pueden atender cuantas peticiones
simultáneas se quiera sin más límites que los que imponga en hardware del
servidor.
• Requisito: No debe implicar riesgos de seguridad para las máquinas que lo
ejecuten.
Cómo: Esto se consigue de dos maneras, por un lado implementando una
política de acceso bastante restrictiva en la infraestructura común del servidor
(cdcrpc.py y archivo de configuración) y por otro lado mediante la decisión de
ofrecer los procedimientos remotos solo en una vlan interna al dmz y (en
teoría) segura.
• Requisito: Debe tener un consumo de recursos moderado.
Cómo: Los servidores son procesos durmientes la mayor parte del tiempo,
hasta que reciben una petición, por lo que su consumo de recursos es
despreciable normalmente. Por la naturaleza del protocolo (petición-respuesta,
95
no interactivo) la ejecución de los procedimientos exportados debe ser
bastante rápida, lo que también implica una ocupación racional de los recursos
de la máquina donde resida.
• Requisito: El consumo de ancho de banda también debe ser moderado.
Cómo: Si bien el empleo de xml para encapsular los datos en el transporte
supone una sobrecarga importante (sobre todo en el caso de datos binarios), la
propia naturaleza de los servicios a implementar aseguran que el consumo de
ancho de banda tiende a ser trivial.
• Requisito: Debe ser modular, la publicación de un nuevo procedimiento en una
máquina no debe afectar a aquellos que ya estuvieran en servicio en la misma.
Cómo: Hemos observador como los módulos que implementan distintos
servicios son completamente independientes tanto en concepción como en
ejecución. La publicación de un nuevo servicio en una máquina que ya
estuviera usando el sistema cdcrpc solo implicaría un reinicio del servicio
cdcrpc.
• Requisito: Su uso para la implementación de nuevos procedimientos por
personal que desconozca el servicio debe ser trivial, este es uno de los
requerimientos básicos.
Cómo: Mediante la creación de documentación adecuada y numerosos
ejemplos, la elección de un lenguaje de programación popular y simple y un
sistema que busca ante todo la simplicidad de implementación se consigue
este objetivo. La prueba empírica de la consecución del mismo es que varias
personas distintas han desarrollado módulos usando la infraestructura común
simplemente a través de la documentación disponible.
top related