La arquitectura basada en plugins de Opengnsys permite añadir nuevas funcionalidades de forma modular y sencilla. La mayoría de estas funcionalidades no se limitan a realizar tareas en el Servidor, sino que implican comunicarse con los propios clientes de Opengnsys. Por ejemplo, un plugin sencillo podría permitir apagar o encender dichos clientes, y otro algo más complejo gestionar el particionado del disco duro.
Para simplificar y estandarizar el trabajo de comunicación con los clientes, se crearon los trabajos o Jobs. Estos permiten ejecutar comandos en un cliente dado, y recibir una respuesta. Dichos comandos serán ejecutados con permisos de superusuario. La comunicación con los clientes se realiza mediante un socket cifrado y autenticado mediante SSL en ambos extremos: es decir, es segura, y esta seguridad es transparente al usuario. El cliente Opengnsys viene con una serie de comandos de administración e idealmente sólo sería necesario utilizar esos y no otros.
El plugin que vamos a realizar aquí nos permitirá saber cuanto tiempo lleva encendida una máquina. Para ello crearemos una acción que se listará en el panel de acciones al mostrar un ordenador. Al hacer clic en la acción, crearemos un job que ejecutará el comando "uptime" en el cliente y mostrará una pantalla diciendo "Esperando respuesta..." en el cliente, y finalmente cuando se reciba una respuesta, se procesará y se mostrará el Uptime en pantalla.
Lo primero que debemos hacer es crear el directorio plugins/uptime, donde residirá el nuevo plugin. Ahí crearemos el fichero plugin.conf que declara información básica del plugin y de la acción antes mencionada:
#!python
[action/get_uptime]
description = Retrieves uptime from the client
human_name = Get Uptime
appear_in_main_panel = No
También es necesario definir el fichero !init!.py:
#!python
'''
Jobs plugin example
'''
from ..pluginbase import PluginBase
from view import UptimeView
class Plugin(PluginBase):
'''
'''
def enable(self):
self.actions_for_url = ('navigator/computer/(.*)', 'get_uptime')
self.urls = ('self.get_action_url('get_uptime')', UptimeView)
La vista asociada a la acción get_uptime será la encargada de crear el job, actualizar periódicamente la página mostrando el mensaje de "Esperando respuesta" hasta que el cliente responda, cuando la página dejará de ser recargada y mostrará el uptime, el fichero es view.py:
#!python
import web
import datetime
from jobs import GetUptimeJob
from decorators import pi18n
class UptimeView:
@pi18n
def GET(self, computer_name):
computer = web.ctx.orm.query(Computer).filter(Computer.name == computer_name).first()
job = self.get_job(computer)
if job.status == 'FINISHED':
if job.last_modified_date + datetime.timedelta(minutes = 2) > datetime.datetime.now():
# New job needed
job = GetUptimeJob()
job.send(computer)
web.ctx.header("Refresh", "2; url=%s", web.ctx.fullpath)
return web.ctx.render.plugins.uptime.view()
else:
# Job finished: nice!
return web.ctx.render.plugins.uptime.view(job)
if job.status 'ERROR':
# New job needed, previous one gave an error
job = GetUptimeJob()
job.send(computer)
web.ctx.header("Refresh", "2; url=%s", web.ctx.fullpath)
return web.ctx.render.plugins.uptime.view()
def get_job(self, computer):
'''
Returns any current GetUptimeJob related to the given computer
'''
return web.ctx.orm.query(Job).filter(Job.computer_id == computer.id).\
filter(Job.class_name == GetUptimeJob.__name__).first()
La función get_job realiza una consulta a la base de datos que obtiene si hay un job de nuestro tipo para el ordenador dado. Esto lo hace filtrando por !name!, que caracterizan a nuestro Job como veremos más adelante.
Por otra parte, la función GET obtiene el model del ordenador solicitado, y obtiene el job anteriormente mencionado. En caso de que el job hubiese terminado, se utilizará si se terminó hace como mucho dos minutos, o en caso contrario se volverá a solicitar el uptime. Si el job dio error, también volvemos a solicitar el uptime. Utilizamos web.ctx.header para recargar la página cada dos segundos mientras se muestra el mensaje de "Esperando respuesta" al usuario.
Finalmente siempre llamamos al template que mostrará al usuario el estado de la solicitud. Este template muestra el mensaje "Esperando respuesta" siempre que no le pasemos un job que contenga la información sobre el uptime, y reside en templates/view.html dentro del directorio de nuestro plugin:
#!python
$def with (job = None)
$var title = _("Uptime")
$var hierarchy = []
$code:
def show_uptime():
print _("%s has been up for %s") % (job.computer.name,\
job.client_message)
<div class="uptime">
$if job == None:
$_("Waiting response..")
$else:
$show_uptime()
</div>
Nuestro job va a ser bien sencillo. Sólo necesitamos que envíe el comando "uptime" y que procese la salida de dicho comando. La salida es del tipo " 16:18:53 up 3:11, 1 user, load average: 0.92, 0.64, 0.50", pero queremos quedarnos con "3:11". El fichero de nuestro job es 'job.py:
Importante: todos los jobs de un plugins deben crearse en el fichero jobs.py. Además has de saber que cuando un plugin es desactivado todos los jobs que dicho plugin creó son eliminados de la base de datos.
#!python
from import unicode_literals
from clientjob.model import Job
from decorators import pi18n
class GetUptimeJob(Job):
def __init__(self):
Job.__init__(self, 'uptime')
@pi18n
def get_user_message(self):
if self.status != 'FINISHED':
return Job.get_user_message(self)
return _('Uptime for %s is %s') %\
(self.computer.name, self.client_message)
def update(self):
if self.status != 'FINISHED':
return
# get the uptime
self.client_message = self.client_message.split(' ')[4] +\
' ' + self.client_message.split(' ')[5]
Para crear nuestro propio job tenemos que tener en cuenta lo siguiente: