[Kimchi-devel] [PATCH V3] [Wok] Implement Asynchronous Notifications backend

Lucio Correia luciojhc at linux.vnet.ibm.com
Fri Apr 1 19:46:44 UTC 2016


* There is no POST method: a notification is
added through add_notification() method.
* Notifications are always stored in Wok object store under
'notification' type, even if added by a plugin.
* Every time Wok is started, all notifications are erased,
since this is a UI feature, intended to be showed to the
user asynchronously, independent of which tab is opened.

Signed-off-by: Lucio Correia <luciojhc at linux.vnet.ibm.com>
---
 docs/API/notifications.md        | 36 ++++++++++++++++++++++++++
 src/wok/control/notifications.py | 37 ++++++++++++++++++++++++++
 src/wok/i18n.py                  |  3 +++
 src/wok/model/notifications.py   | 56 ++++++++++++++++++++++++++++++++++++++++
 src/wok/objectstore.py           | 36 ++++++++++++++++++++++++++
 src/wok/server.py                |  4 +++
 6 files changed, 172 insertions(+)
 create mode 100644 docs/API/notifications.md
 create mode 100644 src/wok/control/notifications.py
 create mode 100644 src/wok/model/notifications.py

Changes in V3:
 - applied code review suggestions

diff --git a/docs/API/notifications.md b/docs/API/notifications.md
new file mode 100644
index 0000000..85e8463
--- /dev/null
+++ b/docs/API/notifications.md
@@ -0,0 +1,36 @@
+## REST API Specification for Notifications
+
+### Collection: Notifications
+
+**URI:** /notifications
+
+**Methods:**
+
+* **GET**: Retrieve a summarized list of current Notifications
+
+#### Examples
+GET /notifications
+[{Notification1}, {Notification2}, ...]
+
+### Resource: Notification
+
+**URI:** /notifications/*:id*
+
+A notification represents an asynchronous warning message sent to the web UI.
+
+**Methods:**
+
+* **GET**: Retrieve the full description of the Notification
+    * code: message ID
+    * message: message text already translated
+    * timestamp: first time notification was emitted
+
+* **DELETE**: Delete the Notification
+
+#### Examples
+GET /notifications/KCHLIBVIRT0001W
+{
+ code: "KCHLIBVIRT0001W",
+ message: "KCHLIBVIRT0001W: Lack of storage space in guest vm-1",
+ timestamp: first time notification was emitted
+}
diff --git a/src/wok/control/notifications.py b/src/wok/control/notifications.py
new file mode 100644
index 0000000..37d45f2
--- /dev/null
+++ b/src/wok/control/notifications.py
@@ -0,0 +1,37 @@
+#
+# Project Wok
+#
+# Copyright IBM Corp, 2016
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+
+from wok.control.base import Collection, Resource
+from wok.control.utils import UrlSubNode
+
+
+ at UrlSubNode('notifications', True)
+class Notifications(Collection):
+    def __init__(self, model):
+        super(Notifications, self).__init__(model)
+        self.resource = Notification
+
+
+class Notification(Resource):
+    def __init__(self, model, id):
+        super(Notification, self).__init__(model, id)
+
+    @property
+    def data(self):
+        return self.info
diff --git a/src/wok/i18n.py b/src/wok/i18n.py
index e6087f4..5a2876f 100644
--- a/src/wok/i18n.py
+++ b/src/wok/i18n.py
@@ -45,6 +45,9 @@ messages = {
     "WOKLOG0001E": _("Invalid filter parameter. Filter parameters allowed: %(filters)s"),
     "WOKLOG0002E": _("Creation of log file failed: %(err)s"),
 
+    "WOKNOT0001E": _("Unable to find notification %(id)s"),
+    "WOKNOT0002E": _("Unable to delete notification %(id)s: %(message)s"),
+
     "WOKOBJST0001E": _("Unable to find %(item)s in datastore"),
 
     "WOKUTILS0001E": _("Unable to reach %(url)s. Make sure it is accessible and try again."),
diff --git a/src/wok/model/notifications.py b/src/wok/model/notifications.py
new file mode 100644
index 0000000..77184db
--- /dev/null
+++ b/src/wok/model/notifications.py
@@ -0,0 +1,56 @@
+#
+# Project Wok
+#
+# Copyright IBM Corp, 2016
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+
+from wok.exception import NotFoundError, OperationFailed
+from wok.message import WokMessage
+
+
+class NotificationsModel(object):
+    def __init__(self, **kargs):
+        self.objstore = kargs['objstore']
+
+    def get_list(self):
+        with self.objstore as session:
+            return session.get_list('notification')
+
+
+class NotificationModel(object):
+    def __init__(self, **kargs):
+        self.objstore = kargs['objstore']
+
+    def lookup(self, id):
+        with self.objstore as session:
+            notification = session.get('notification', str(id))
+
+            # use WokMessage to translate the notification
+            if notification:
+                timestamp = notification['timestamp']
+                plugin = notification.pop('_plugin_name', None)
+                message = WokMessage(id, notification, plugin).get_text()
+                return {"code": id, "message": message, "timestamp": timestamp}
+
+        raise NotFoundError("WOKNOT0001E", {'id': str(id)})
+
+    def delete(self, id):
+        try:
+            with self.objstore as session:
+                session.delete('notification', str(id))
+        except Exception as e:
+            raise OperationFailed("WOKNOT0002E", {'id': str(id),
+                                                  'msg': e.msg()})
diff --git a/src/wok/objectstore.py b/src/wok/objectstore.py
index 59354f3..ff3796c 100644
--- a/src/wok/objectstore.py
+++ b/src/wok/objectstore.py
@@ -23,6 +23,8 @@ import sqlite3
 import threading
 import traceback
 
+from datetime import datetime
+
 try:
     from collections import OrderedDict
 except ImportError:
@@ -144,3 +146,37 @@ class ObjectStore(object):
                 # exception again
                 wok_log.error(traceback.format_exc())
                 return False
+
+
+def add_notification(code, args={}, plugin_name=None):
+    if not code:
+        wok_log.error("Unable to add notification: invalid code '%(code)s'" %
+                      {'code': str(code)})
+        return
+
+    try:
+        with ObjectStore() as session:
+            notification = session.get('notification', code)
+    except NotFoundError:
+        notification = None
+
+    try:
+        # do not update timestamp if notification already exists
+        timestamp = datetime.now().isoformat() if notification is None else \
+            notification['timestamp']
+        args.update({"_plugin_name": plugin_name, "timestamp": timestamp})
+
+        with ObjectStore() as session:
+            session.store('notification', code, args)
+    except Exception as e:
+        wok_log.error("Unable to store notification: %s" % e.message)
+
+
+def clean_notifications():
+    try:
+        with ObjectStore() as session:
+            notifications = session.get_list('notification')
+            for item in notifications:
+                session.delete('notification', item)
+    except Exception as e:
+        wok_log.error("Unable to clean notifications: %s" % e.message)
diff --git a/src/wok/server.py b/src/wok/server.py
index 902d4bf..a329ed4 100644
--- a/src/wok/server.py
+++ b/src/wok/server.py
@@ -33,6 +33,7 @@ from wok.config import config as configParser
 from wok.config import paths, PluginConfig, WokConfig
 from wok.control import sub_nodes
 from wok.model import model
+from wok.objectstore import clean_notifications
 from wok.proxy import start_proxy, terminate_proxy
 from wok.reqlogger import RequestLogger
 from wok.root import WokRoot
@@ -106,6 +107,9 @@ class Server(object):
         if dev_env:
             cherrypy.log.screen = True
 
+        # clean object store notifications
+        clean_notifications()
+
         # close standard file handlers because we are going to use a
         # watchedfiled handler, otherwise we will have two file handlers
         # pointing to the same file, duplicating log enries
-- 
1.9.1




More information about the Kimchi-devel mailing list