[PATCH v4] [WoK 0/5] 'reload' API implementation

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> v4: - fixed a '()' in test_api.py - changed the positioning of the notification message in i18n.py v3: - 'add_notification' is now being called before the reload command v2: - changed API name to 'reload' - added test_api tests This patch set implements a new WOK API called 'reload' under /config/reload. To test it: $ curl -k -u danielhb -H "Content-Type: application/json" -H "Accept: application/json" -X POST 'https://localhost:8001/config/reload' -d'{}' Enter host password for user 'danielhb': { "proxy_port":"8001", "websockets_port":"64667", "version":"2.3.0-55.git5c9127b", "auth":"pam", "server_root":"" } This will reload WoK and all its plug-ins. Daniel Henrique Barboza (5): reload API: doc changes reload API: control and model changes reload API: new file tests/test_config_model.py reload API: added rest API tests reload API: adding notification before reloading operation docs/API/config.md | 2 +- src/wok/control/config.py | 4 +++- src/wok/i18n.py | 2 ++ src/wok/model/config.py | 22 +++++++++++++++++++++- tests/test_api.py | 9 ++++++++- tests/test_config_model.py | 41 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 tests/test_config_model.py -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch adds the documentation of the new 'reload' API in docs/API/config.md. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- docs/API/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/API/config.md b/docs/API/config.md index 0c273e2..4ba455e 100644 --- a/docs/API/config.md +++ b/docs/API/config.md @@ -17,7 +17,7 @@ Contains information about the application environment and configuration. **Actions (POST):** -*No actions defined* +* reload: reloads WoK configuration. This process will drop all existing WoK connections, reloading WoK and all its enabled plug-ins. #### Examples GET /config -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> - added a new action handler called 'reload' in control/config.py - added a method 'reload' in model/config.py that calls 'cherrypy.engine.restart()'. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- src/wok/control/config.py | 4 +++- src/wok/model/config.py | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/wok/control/config.py b/src/wok/control/config.py index 338306c..62218f9 100644 --- a/src/wok/control/config.py +++ b/src/wok/control/config.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,8 @@ from wok.control.utils import UrlSubNode class Config(Resource): def __init__(self, model, id=None): super(Config, self).__init__(model, id) + self.uri_fmt = '/config/%s' + self.reload = self.generate_action_handler('reload') @property def data(self): diff --git a/src/wok/model/config.py b/src/wok/model/config.py index 7e8ae4f..57c5ad8 100644 --- a/src/wok/model/config.py +++ b/src/wok/model/config.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -17,6 +17,8 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +import cherrypy + from wok.config import config, get_version @@ -30,3 +32,6 @@ class ConfigModel(object): 'auth': config.get('authentication', 'method'), 'server_root': config.get('server', 'server_root'), 'version': get_version()} + + def reload(self, name): + cherrypy.engine.restart() -- 2.7.4

On 01/18/2017 06:55 PM, dhbarboza82@gmail.com wrote:
From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
- added a new action handler called 'reload' in control/config.py - added a method 'reload' in model/config.py that calls 'cherrypy.engine.restart()'.
Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- src/wok/control/config.py | 4 +++- src/wok/model/config.py | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/wok/control/config.py b/src/wok/control/config.py index 338306c..62218f9 100644 --- a/src/wok/control/config.py +++ b/src/wok/control/config.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,8 @@ from wok.control.utils import UrlSubNode class Config(Resource): def __init__(self, model, id=None): super(Config, self).__init__(model, id)
+ self.uri_fmt = '/config/%s'
AFAIU, the self.uri_fmt is only required when you have an resource name which is not the case of /config API Do you have any specific reason to set it? Also I'd say to you set self.admin_methods = [POST] so when my patch related to authorization get merged, the POST action will be protected for only sysadmins.
+ self.reload = self.generate_action_handler('reload')
@property def data(self): diff --git a/src/wok/model/config.py b/src/wok/model/config.py index 7e8ae4f..57c5ad8 100644 --- a/src/wok/model/config.py +++ b/src/wok/model/config.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -17,6 +17,8 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+import cherrypy + from wok.config import config, get_version
@@ -30,3 +32,6 @@ class ConfigModel(object): 'auth': config.get('authentication', 'method'), 'server_root': config.get('server', 'server_root'), 'version': get_version()} + + def reload(self, name): + cherrypy.engine.restart()

On 01/19/2017 11:31 AM, Aline Manera wrote:
On 01/18/2017 06:55 PM, dhbarboza82@gmail.com wrote:
From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
- added a new action handler called 'reload' in control/config.py - added a method 'reload' in model/config.py that calls 'cherrypy.engine.restart()'.
Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- src/wok/control/config.py | 4 +++- src/wok/model/config.py | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/wok/control/config.py b/src/wok/control/config.py index 338306c..62218f9 100644 --- a/src/wok/control/config.py +++ b/src/wok/control/config.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,8 @@ from wok.control.utils import UrlSubNode class Config(Resource): def __init__(self, model, id=None): super(Config, self).__init__(model, id)
+ self.uri_fmt = '/config/%s'
AFAIU, the self.uri_fmt is only required when you have an resource name which is not the case of /config API
Do you have any specific reason to set it?
I have the impression that the 'reload' action will not work if I don't specify uri_fmt - at least this is why I remember noticing when I first wrote it . I'll try removing it and if it works as intended I'll resend v5 without it.
Also I'd say to you set self.admin_methods = [POST] so when my patch related to authorization get merged, the POST action will be protected for only sysadmins.
I'll see if setting self.admin_methods = [POST] without the 'True' argument in the @URLSubnode will not impact the current behavior (because setting to 'True' then the whole API is locked by authentication). If no harm is done I'll add it in v5. Daniel
+ self.reload = self.generate_action_handler('reload')
@property def data(self): diff --git a/src/wok/model/config.py b/src/wok/model/config.py index 7e8ae4f..57c5ad8 100644 --- a/src/wok/model/config.py +++ b/src/wok/model/config.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -17,6 +17,8 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+import cherrypy + from wok.config import config, get_version
@@ -30,3 +32,6 @@ class ConfigModel(object): 'auth': config.get('authentication', 'method'), 'server_root': config.get('server', 'server_root'), 'version': get_version()} + + def reload(self, name): + cherrypy.engine.restart()
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

On 01/19/2017 12:28 PM, Daniel Henrique Barboza wrote:
On 01/19/2017 11:31 AM, Aline Manera wrote:
On 01/18/2017 06:55 PM, dhbarboza82@gmail.com wrote:
From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
- added a new action handler called 'reload' in control/config.py - added a method 'reload' in model/config.py that calls 'cherrypy.engine.restart()'.
Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- src/wok/control/config.py | 4 +++- src/wok/model/config.py | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/wok/control/config.py b/src/wok/control/config.py index 338306c..62218f9 100644 --- a/src/wok/control/config.py +++ b/src/wok/control/config.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,8 @@ from wok.control.utils import UrlSubNode class Config(Resource): def __init__(self, model, id=None): super(Config, self).__init__(model, id)
+ self.uri_fmt = '/config/%s'
AFAIU, the self.uri_fmt is only required when you have an resource name which is not the case of /config API
Do you have any specific reason to set it?
I have the impression that the 'reload' action will not work if I don't specify uri_fmt - at least this is why I remember noticing when I first wrote it .
I'll try removing it and if it works as intended I'll resend v5 without it.
As I've imagined, the uri_fmt is required. Removing it causes WoK to throw a 500 Internal Error in line 104 of control/base.py: def generate_action_handler(self, action_name, action_args=None, destructive=False): def _render_element(self, ident): self._redirect(ident) uri_params = [] for arg in self.model_args: if arg is None: arg = '' uri_params.append(urllib2.quote(arg.encode('utf-8'), safe="")) raise internal_redirect(self.uri_fmt % tuple(uri_params)) return self._generate_action_handler_base(action_name, _render_element, destructive=destructive, action_args=action_args) As we can see above, generate_action_handler uses a _render_element internal function that raises an internal_redirect at self.uri_fmt % tuple(uri_params) . Removing 'uri_fmt' breaks this internal redirect.
Also I'd say to you set self.admin_methods = [POST] so when my patch related to authorization get merged, the POST action will be protected for only sysadmins.
I'll see if setting self.admin_methods = [POST] without the 'True' argument in the @URLSubnode will not impact the current behavior (because setting to 'True' then the whole API is locked by authentication). If no harm is done I'll add it in v5.
Daniel
Just checked that we can safely add self.admin_methods = ['POST'] without messing with the feature behavior. I'll resend v5 with this addition.
+ self.reload = self.generate_action_handler('reload')
@property def data(self): diff --git a/src/wok/model/config.py b/src/wok/model/config.py index 7e8ae4f..57c5ad8 100644 --- a/src/wok/model/config.py +++ b/src/wok/model/config.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -17,6 +17,8 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+import cherrypy + from wok.config import config, get_version
@@ -30,3 +32,6 @@ class ConfigModel(object): 'auth': config.get('authentication', 'method'), 'server_root': config.get('server', 'server_root'), 'version': get_version()} + + def reload(self, name): + cherrypy.engine.restart()
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> Created a new unit test file for model/config.py since the existing test_config.py is testing WokConfig. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- tests/test_config_model.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/test_config_model.py diff --git a/tests/test_config_model.py b/tests/test_config_model.py new file mode 100644 index 0000000..f8b0848 --- /dev/null +++ b/tests/test_config_model.py @@ -0,0 +1,41 @@ +# +# Project Wok +# +# Copyright IBM Corp, 2017 +# +# 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 + +import mock +import unittest + +from wok.model import model + + +class ConfigModelTests(unittest.TestCase): + + def test_config_lookup(self): + inst = model.Model() + config = inst.config_lookup('') + self.assertItemsEqual( + ['proxy_port', 'websockets_port', 'auth', + 'server_root', 'version'], + config.keys() + ) + + @mock.patch('cherrypy.engine.restart') + def test_config_reload(self, mock_restart): + inst = model.Model() + inst.config_reload('') + mock_restart.assert_called_once_with() -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch adds a new test in test_api to assert the function of the 'reload' API. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- tests/test_api.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test_api.py b/tests/test_api.py index 23c263d..1430bc1 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,7 +1,7 @@ # # Project Wok # -# Copyright IBM Corp, 2016 +# Copyright IBM Corp, 2016-2017 # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -18,6 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import json +import mock import time import unittest import utils @@ -102,3 +103,9 @@ class APITests(unittest.TestCase): self.assertEquals(204, resp.status) task = json.loads(self.request('/tasks/%s' % taskid).read()) self.assertEquals('killed', task['status']) + + @mock.patch('cherrypy.engine.restart') + def test_config_reload(self, mock_restart): + resp = self.request('/config/reload', '{}', 'POST') + self.assertEquals(200, resp.status) + mock_restart.assert_called_once_with() -- 2.7.4

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> This patch adds an add_notification call to warn the UI about the pending reload process. To allow the UI to actually see the notification before WoK restarts, a 2 seconds wait (value defined by the wok.NOTIFICATION_INTERVAL var in wok.main.js) is given before sending the cherrypy.engine.restart call. Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> --- src/wok/i18n.py | 2 ++ src/wok/model/config.py | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/wok/i18n.py b/src/wok/i18n.py index e454e31..dc101eb 100644 --- a/src/wok/i18n.py +++ b/src/wok/i18n.py @@ -55,6 +55,8 @@ messages = { "WOKUTILS0004E": _("Invalid data value '%(value)s'"), "WOKUTILS0005E": _("Invalid data unit '%(unit)s'"), + "WOKCONFIG0001I": _("WoK is going to restart. Existing WoK connections will be closed."), + # These messages (ending with L) are for user log purposes "WOKASYNC0001L": _("Successfully completed task '%(target_uri)s'"), "WOKASYNC0002L": _("Failed to complete task '%(target_uri)s'"), diff --git a/src/wok/model/config.py b/src/wok/model/config.py index 57c5ad8..b69f2dd 100644 --- a/src/wok/model/config.py +++ b/src/wok/model/config.py @@ -18,8 +18,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA import cherrypy +import time from wok.config import config, get_version +from wok.model.notifications import add_notification +from wok.utils import wok_log class ConfigModel(object): @@ -34,4 +37,16 @@ class ConfigModel(object): 'version': get_version()} def reload(self, name): + add_notification('WOKCONFIG0001I', plugin_name='/') + # If we proceed with the cherrypy.engine.restart() right after + # adding the notification, the server will reboot and the + # opened UIs will most likely not see the notification at all. The + # notification interval is set in wok.main.js as: + # + # wok.NOTIFICATION_INTERVAL = 2000 + # + # Inserting a time.sleep(2) here will ensure that all opened + # UI had the chance to see the reload notification. + wok_log.info('Reloading WoK in two seconds ...') + time.sleep(2) cherrypy.engine.restart() -- 2.7.4
participants (4)
-
Aline Manera
-
Daniel Henrique Barboza
-
Daniel Henrique Barboza
-
dhbarboza82@gmail.com