hobo/hobo/environment/models.py

173 lines
5.9 KiB
Python

import datetime
import urllib2
import json
from django.conf import settings
from django.db import models
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from .utils import Zone, get_installed_services_dict
class Variable(models.Model):
name = models.CharField(max_length=100, verbose_name=_('name'))
value = models.TextField(verbose_name=_('value'),
blank=True,
help_text=_('start with [ or { for a JSON document'))
service_type = models.ForeignKey(ContentType, null=True)
service_pk = models.PositiveIntegerField(null=True)
service = generic.GenericForeignKey('service_type', 'service_pk')
last_update_timestamp = models.DateTimeField(auto_now=True, null=True)
@property
def json(self):
if self.value and self.value[0] in '{[':
return json.loads(self.value)
return self.value
def clean(self):
if self.value and self.value[0] in '{[':
try:
json.loads(self.value)
except ValueError:
raise ValidationError('invalid JSON document')
class ServiceBase(models.Model):
class Meta:
abstract = True
title = models.CharField(_('Title'), max_length=50)
slug = models.SlugField()
base_url = models.CharField(_('Base URL'), max_length=200)
secret_key = models.CharField(_('Secret Key'), max_length=60)
template_name = models.CharField(_('Template'), max_length=60, blank=True)
last_operational_check_timestamp = models.DateTimeField(null=True)
last_operational_success_timestamp = models.DateTimeField(null=True)
last_update_timestamp = models.DateTimeField(auto_now=True, null=True)
variables = generic.GenericRelation(Variable,
content_type_field='service_type', object_id_field='service_pk')
def is_operational(self):
return (self.last_operational_success_timestamp is not None and
self.last_operational_success_timestamp == self.last_operational_check_timestamp)
def check_operational(self):
once_now = now()
self.last_operational_check_timestamp = once_now
try:
fd = urllib2.urlopen(self.base_url, timeout=10)
fd.close()
self.last_operational_success_timestamp = once_now
except (urllib2.URLError, urllib2.HTTPError):
pass
self.save(update_fields=('last_operational_check_timestamp', 'last_operational_success_timestamp'))
def wants_frequent_checks(self):
# decides if a "being deployed..." spinner should be displayed (and
# automatically hidden) next to the service.
if self.last_operational_success_timestamp is not None:
# if the service has been marked as operational, we don't need a
# spinner at all.
return False
if self.last_operational_check_timestamp is None:
# if the service has never been checked, sure we wants a spinner.
return True
two_minutes = datetime.timedelta(minutes=2)
# monitor actively for two minutes max.
return (self.last_operational_check_timestamp - self.last_update_timestamp) < two_minutes
def as_dict(self):
as_dict = dict([(x, y) for (x, y) in self.__dict__.items()
if type(y) in (int, str, unicode)])
as_dict['service-id'] = self.Extra.service_id
as_dict['variables'] = dict(((v.name, v.json) for v in self.variables.all()))
if self.get_saml_sp_metadata_url():
as_dict['saml-sp-metadata-url'] = self.get_saml_sp_metadata_url()
return as_dict
@property
def name(self):
return self.title
def save(self, *args, **kwargs):
is_new = (self.id is None)
super(ServiceBase, self).save(*args, **kwargs)
if is_new and settings.SERVICE_EXTRA_VARIABLES:
for variable in settings.SERVICE_EXTRA_VARIABLES.get(self.Extra.service_id, []):
v = Variable()
v.name = variable
v.service = self
v.save()
def get_saml_sp_metadata_url(self):
return None
class Authentic(ServiceBase):
class Meta:
verbose_name = _('Authentic Identity Provider')
verbose_name_plural = _('Authentic Identity Providers')
class Extra:
service_id = 'authentic'
def get_admin_zones(self):
return [
Zone(_('User Management'), 'users', self.base_url + '/manage/users/'),
Zone(_('Role Management'), 'roles', self.base_url + '/manage/roles/'),
]
class Wcs(ServiceBase):
class Meta:
verbose_name = _('w.c.s. Web Forms')
verbose_name_plural = _('.w.c.s. Web Forms')
class Extra:
service_id = 'wcs'
def get_admin_zones(self):
return [
Zone(self.title, 'webforms', self.base_url + '/admin/'),
]
def get_saml_sp_metadata_url(self):
return self.base_url + '/saml/metadata'
class Passerelle(ServiceBase):
class Meta:
verbose_name = _('Passerelle')
verbose_name_plural = _('Passerelle')
class Extra:
service_id = 'passerelle'
def get_admin_zones(self):
return [
Zone(self.title, 'webservices', self.base_url + '/manage/')
]
AVAILABLE_SERVICES = [Authentic, Wcs, Passerelle]
@receiver(post_save)
def notify_agents(sender, instance, **kwargs):
if not sender in [Variable]+AVAILABLE_SERVICES:
return
try:
from hobo.agent.celery import deploy
except ImportError:
return
deploy.apply_async((get_installed_services_dict(),) , queue='broadcast_tasks')