]> git.ipfire.org Git - people/ms/westferry.git/commitdiff
Add handler that serves graphs from collecty
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 18 Oct 2015 12:01:09 +0000 (14:01 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 18 Oct 2015 12:01:09 +0000 (14:01 +0200)
This handler connects to collecty and generates graphs
of the system in various formats and resolutions.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
po/POTFILES.in
src/westferry/application.py
src/westferry/backend/__init__.py [new file with mode: 0644]
src/westferry/backend/base.py [new file with mode: 0644]
src/westferry/backend/graphs.py [new file with mode: 0644]
src/westferry/backend/main.py [new file with mode: 0644]
src/westferry/backend/system.py [new file with mode: 0644]
src/westferry/handlers/__init__.py
src/westferry/handlers/analytics.py [new file with mode: 0644]
src/westferry/handlers/base.py

index 8fa2863db8be201f41e47b6fe2e84c4d4c774a1f..6e9087687c4725b5cb92d138c1e6f1c134f136c2 100644 (file)
@@ -96,12 +96,18 @@ CLEANFILES += \
        src/westferry/constants.py
 
 westferry_backend_PYTHON = \
-       src/westferry/backend/__version__.py
+       src/westferry/backend/__init__.py \
+       src/westferry/backend/__version__.py \
+       src/westferry/backend/base.py \
+       src/westferry/backend/graphs.py \
+       src/westferry/backend/main.py \
+       src/westferry/backend/system.py
 
 westferry_backenddir = $(pythondir)/westferry/backend
 
 westferry_handlers_PYTHON = \
        src/westferry/handlers/__init__.py \
+       src/westferry/handlers/analytics.py \
        src/westferry/handlers/base.py \
        src/westferry/handlers/index.py
 
index 77f3c22575404abb08eb817acb6322770c895006..292abacccf2a3c5d372ec4bff2babf70d51940c9 100644 (file)
@@ -1,3 +1,4 @@
 src/westferry/backend/__version__.py
+src/westferry/handlers/analytics.py
 src/westferry/handlers/base.py
 src/westferry/__init__.py
index 06acd8c964c42f020041adfa5d86b1dd9de9ede7..a402848f8f981e204dcbe8e2fa4606672155fd60 100644 (file)
@@ -21,6 +21,7 @@
 
 import tornado.web
 
+from . import backend
 from . import handlers
 from . import ui
 
@@ -54,3 +55,10 @@ class WebApplication(tornado.web.Application):
 
                # Initialise the web application
                tornado.web.Application.__init__(self, handlers=h, **settings)
+
+       @property
+       def backend(self):
+               if not hasattr(self, "_backend"):
+                       self._backend = backend.Backend()
+
+               return self._backend
diff --git a/src/westferry/backend/__init__.py b/src/westferry/backend/__init__.py
new file mode 100644 (file)
index 0000000..cad0eb3
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/python3
+###############################################################################
+#                                                                             #
+# Westferry - The IPFire web user interface                                   #
+# Copyright (C) 2015 IPFire development team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+from .main import Backend
diff --git a/src/westferry/backend/base.py b/src/westferry/backend/base.py
new file mode 100644 (file)
index 0000000..3ebf2d9
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/python3
+###############################################################################
+#                                                                             #
+# Westferry - The IPFire web user interface                                   #
+# Copyright (C) 2015 IPFire development team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+class BaseBackend(object):
+       def __init__(self, backend):
+               self.backend = backend
diff --git a/src/westferry/backend/graphs.py b/src/westferry/backend/graphs.py
new file mode 100644 (file)
index 0000000..1e24aee
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/python3
+###############################################################################
+#                                                                             #
+# Westferry - The IPFire web user interface                                   #
+# Copyright (C) 2015 IPFire development team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+import collecty.client
+
+from . import base
+
+class GraphsBackend(base.BaseBackend):
+       @property
+       def collecty(self):
+               """
+                       Returns a CollectyClient object which is created
+                       when it is needed.
+               """
+               if not hasattr(self, "_collecty"):
+                       self._collecty = collecty.client.CollectyClient()
+
+               return self._collecty
+
+       def generate_graph(self, template_name, **kwargs):
+               assert self.template_exists(template_name)
+
+               # Remove all keys with value None
+               # dbus cannot marshall None and when None is set, we assume
+               # that the default is selected, so we can simply remove the
+               # setting.
+               for key in kwargs.copy():
+                       if kwargs[key] is None:
+                               del kwargs[key]
+
+               return self.collecty.generate_graph(template_name, **kwargs)
+
+       def template_exists(self, template_name):
+               """
+                       Returns True if a template with the given name exists
+               """
+               return template_name in self.collecty.list_templates()
diff --git a/src/westferry/backend/main.py b/src/westferry/backend/main.py
new file mode 100644 (file)
index 0000000..fa05a13
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/python3
+###############################################################################
+#                                                                             #
+# Westferry - The IPFire web user interface                                   #
+# Copyright (C) 2015 IPFire development team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+from .__version__ import VERSION
+
+from . import graphs
+from . import system
+
+class Backend(object):
+       version = VERSION
+
+       def __init__(self):
+               self.graphs = graphs.GraphsBackend(self)
+               self.system = system.SystemBackend(self)
diff --git a/src/westferry/backend/system.py b/src/westferry/backend/system.py
new file mode 100644 (file)
index 0000000..085c359
--- /dev/null
@@ -0,0 +1,32 @@
+#!/usr/bin/python3
+###############################################################################
+#                                                                             #
+# Westferry - The IPFire web user interface                                   #
+# Copyright (C) 2015 IPFire development team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+import socket
+
+from . import base
+
+class SystemBackend(base.BaseBackend):
+       @property
+       def hostname(self):
+               """
+                       Returns the hostname of this system
+               """
+               return socket.gethostname()
index a934bbd1f50883f9021009d4dcddc37ada72f3cf..bd3ac0b667baa6b57a0fd95cc4f002ff427754d3 100644 (file)
@@ -20,6 +20,7 @@
 ###############################################################################
 
 from . import base
+from . import analytics
 from . import index
 
 def get_handlers():
diff --git a/src/westferry/handlers/analytics.py b/src/westferry/handlers/analytics.py
new file mode 100644 (file)
index 0000000..488d0ac
--- /dev/null
@@ -0,0 +1,72 @@
+#!/usr/bin/python3
+###############################################################################
+#                                                                             #
+# Westferry - The IPFire web user interface                                   #
+# Copyright (C) 2015 IPFire development team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+import datetime
+import collecty.client
+import mimetypes
+import tornado.web
+
+from . import base
+
+class GraphExportHandler(base.BaseHandler):
+       VALID_INTERVALS = ("hour", "day", "month", "week", "year")
+       DEFAULT_INTERVAL = "day"
+
+       SUPPORTED_FORMATS = ("pdf", "png", "svg")
+
+       url = r"/graph/([\w\-]+)(?:/([\w\d]+))?.(%s)" % "|".join(SUPPORTED_FORMATS)
+
+       def get(self, template_name, object_id, format):
+               # Get the requested dimensions of the image
+               height = self.get_argument_int("height", None)
+               width  = self.get_argument_int("width", None)
+
+               # Get the requested interval
+               interval = self.get_argument("interval", self.DEFAULT_INTERVAL)
+               if interval and not interval in self.VALID_INTERVALS:
+                       raise tornado.web.HTTPError(400, _("Invalid interval: %s") % interval)
+
+               # Generate the graph image
+               g = self.backend.graphs.generate_graph(template_name, object_id=object_id,
+                       format=format.upper(), height=height, width=width, interval=interval)
+
+               # Set the HTTP headers
+               self._make_headers(format, template_name, object_id)
+
+               # Deliver the content
+               self.finish(g)
+
+       def _make_headers(self, extension, template_name, object_id):
+               # Determine the mime type
+               mimetype = mimetypes.types_map.get(".%s" % extension, "application/octet-stream")
+               self.set_header("Content-Type", mimetype)
+
+               # Add the timestamp when this graph was generated
+               now = datetime.datetime.now()
+
+               # Put together the filename (for downloads)
+               filename = [self.backend.system.hostname, template_name, object_id, now.isoformat()]
+               filename = "%s.%s" % ("-".join((e for e in filename if e)), extension)
+
+               if extension == "pdf":
+                       self.set_header("Content-Disposition", "attachment; filename=%s" % filename)
+               else:
+                       self.set_header("Content-Disposition", "inline; filename=%s" % filename)
index e3d2461bfdd43bd11baa842c4b7630bdbb858ae1..9027bf4052ba2ee9eb0f94c4279e55a873a4141c 100644 (file)
@@ -44,3 +44,22 @@ class HandlerRegistration(type):
 
 class BaseHandler(tornado.web.RequestHandler, metaclass=HandlerRegistration):
        url = None
+
+       @property
+       def backend(self):
+               """
+                       Shortcut to access the backend
+               """
+               return self.application.backend
+
+       def get_argument_int(self, name, *args, **kwargs):
+               val = self.get_argument(name, *args, **kwargs)
+
+               if val is None:
+                       return
+
+               try:
+                       return int(val)
+               except ValueError:
+                       raise tornado.web.HTTPError(400,
+                               _("Invalid type for '%s', expected integer") % name)