Source code for gavo.web.adminrender

"""
A renderer to do RD-based maintenance.
"""

#c Copyright 2008-2023, the GAVO project <gavo@ari.uni-heidelberg.de>
#c
#c This program is free software, covered by the GNU GPL.  See the
#c COPYING file in the source distribution.


import sys
import traceback

from twisted.web import template
from twisted.web.template import tags as T

from gavo import base
from gavo import formal
from gavo import stc
from gavo import svcs
from gavo.web import common
from gavo.web import grend


[docs]class AdminRenderer(formal.ResourceWithForm, grend.CustomTemplateMixin, grend.ServiceBasedPage): """A renderer allowing to block and/or reload services. This renderer could really be attached to any service since it does not call it, but it usually lives on //services/overview. It will always require authentication. It takes the id of the RD to administer from the path segments following the renderer name. By virtue of builtin vanity, you can reach the admin renderer at /seffe, and thus you can access /seffe/foo/q to administer the foo/q RD. """ name = "admin" customTemplate = svcs.loadSystemTemplate("admin.html") clientRD = None # set below when RD loading failed. reloadExc = None reloadTB = None
[docs] def form_setDowntime(self, request): form = formal.Form() form.addField("scheduled", formal.String(), label="Schedule downtime for", description="Note that this is purely informative. The server" " will not take down the services at this point in time." " Leave empty to cancel. This will also be cleared on a" " reload.") form.addAction(self.setDowntime, label="Ok") form.data = { "scheduled": base.getMetaText(self.clientRD, "_scheduledDowntime")} return form
[docs] def setDowntime(self, request, form, data): scheduleFor = data.get("scheduled") if scheduleFor is None: self.clientRD.delMeta("_scheduledDowntime") else: try: stc.parseISODT(scheduleFor) # check syntax self.clientRD.setMeta("_scheduledDowntime", scheduleFor) except stc.STCLiteralError: # bad date syntax raise base.ui.logOldExc( formal.FieldError("Doesn't look like ISO", "scheduleFor"))
[docs] def form_adminOps(self, request): form = formal.Form() if hasattr(self.clientRD, "currently_blocked"): label = "Unblock" else: label = "Block" form.addAction(self.toggleBlock, label=label, name="block") form.addAction(self.reloadRD, label="Reload RD", name="submit") return form
[docs] def toggleBlock(self, request, form, data): if hasattr(self.clientRD, "currently_blocked"): delattr(self.clientRD, "currently_blocked") else: self.clientRD.currently_blocked = True
[docs] def reloadRD(self, request, form, data): base.caches.clearForName(self.clientRD.sourceId)
[docs] def data_blockstatus(self, request, tag): if hasattr(self.clientRD, "currently_blocked"): return "blocked" return "not blocked"
[docs] def data_services(self, request, tag): """returns a sequence of service items belonging to clientRD, sorted by id. """ return sorted(self.clientRD.services, key=lambda svc: svc.id)
[docs] @template.renderer def rdId(self, request, tag): return tag[self.clientRD.sourceId]
[docs] @template.renderer def ifexc(self, request, tag): """render children if there was an exception during RD load. """ if self.reloadExc is None: return "" else: return tag
[docs] @template.renderer def exc(self, request, tag): return tag[repr(self.reloadExc)]
[docs] @template.renderer def traceback(self, request, tag): return tag[self.reloadTB]
[docs] def render(self, request): # naked renderer means admin services itself if self.clientRD is None: self.clientRD = base.caches.getRD("__system__/services") return common.runAuthenticated(request, "admin", super(AdminRenderer, self).render, request)
def _extractDamageInfo(self): """called when reload of RD failed; leaves exc. info in some attributes. """ type, value = sys.exc_info()[:2] self.reloadExc = value self.reloadTB = traceback.format_exc() # the getChild here is actually the constructor, as it were -- # each request gets a new AdminRender by web.root
[docs] def getChild(self, name, request): segments = request.popSegments(name) rdId = "/".join(segments) try: self.clientRD = base.caches.getRD(rdId) if hasattr(self.clientRD, "getRealRD"): self.clientRD = self.clientRD.getRealRD() self.metaCarrier = self.clientRD self.macroPackage = self.clientRD except base.RDNotFound: raise base.ui.logOldExc( svcs.UnknownURI("No such resource descriptor: %s"%rdId)) except Exception: # RD is botched. Clear cache and give an error base.caches.clearForName(rdId) self._extractDamageInfo() return self
defaultLoader = common.doctypedStan( T.html[ T.head[ T.title["Missing Template"]], T.body[ T.p["Admin services are only available with a admin.html template"]] ])