
- Create kimchi.conf and config.py in plugin - Move kimchi specific config/API to plugin - Rename Kimchi{Config,Root} to Wok{Config,Root} - Create root.py in plugin with new KimchiRoot - Adjust tabs-ext.xml and do not load tabs.xml anymore - Drop login/logout functions from plugin API --- plugins/kimchi/__init__.py | 21 +++++++ plugins/kimchi/config.py.in | 74 ++++++++++++++++++++++++ plugins/kimchi/kimchi.conf | 67 +++++++++++++++++++++ plugins/kimchi/root.py | 57 ++++++++++++++++++ plugins/kimchi/ui/config/tab-ext.xml | 14 ++-- plugins/kimchi/ui/js/src/kimchi.api.js | 19 ------ src/wok/config.py.in | 99 -------------------------------- src/wok/root.py | 8 +- src/wok/server.py | 20 ++---- src/wok/utils.py | 2 +- ui/js/src/wok.main.js | 3 +- 11 files changed, 239 insertions(+), 145 deletions(-) create mode 100644 plugins/kimchi/__init__.py create mode 100644 plugins/kimchi/config.py.in create mode 100644 plugins/kimchi/kimchi.conf create mode 100644 plugins/kimchi/root.py diff --git a/plugins/kimchi/__init__.py b/plugins/kimchi/__init__.py new file mode 100644 index 0000000..9330044 --- /dev/null +++ b/plugins/kimchi/__init__.py @@ -0,0 +1,21 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# 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 root import KimchiRoot +__all__ = [KimchiRoot] diff --git a/plugins/kimchi/config.py.in b/plugins/kimchi/config.py.in new file mode 100644 index 0000000..fdf360a --- /dev/null +++ b/plugins/kimchi/config.py.in @@ -0,0 +1,74 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# 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 libvirt +import os +import platform +import threading + +from wok.config import PluginPaths +from wok.xmlutils.utils import xpath_get_text + +kimchiLock = threading.Lock() + +# Storage pool constant for read-only pool types +READONLY_POOL_TYPE = ['iscsi', 'scsi', 'mpath'] + + +def get_distros_store(): + return os.path.join(PluginPaths('kimchi').conf_dir, 'distros.d') + + +def get_debugreports_path(): + return os.path.join(PluginPaths('kimchi').state_dir, 'debugreports') + + +def get_screenshot_path(): + return os.path.join(PluginPaths('kimchi').state_dir, 'screenshots') + + +def find_qemu_binary(find_emulator=False): + try: + connect = libvirt.open(None) + except Exception, e: + raise Exception("Unable to get qemu binary location: %s" % e) + try: + xml = connect.getCapabilities() + + # On Little Endian system, the qemu binary is + # qemu-system-ppc64, not qemu-system-ppc64le as expected + arch = platform.machine() + if arch == "ppc64le": + arch = "ppc64" + + if find_emulator: + expr = "/capabilities/guest/arch[@name='%s']\ + /emulator" % arch + else: + expr = "/capabilities/guest/arch[@name='%s']\ + /domain[@type='kvm']/emulator" % arch + res = xpath_get_text(xml, expr) + location = res[0] + except Exception, e: + raise Exception("Unable to get qemu binary location: %s" % e) + finally: + connect.close() + return location + diff --git a/plugins/kimchi/kimchi.conf b/plugins/kimchi/kimchi.conf new file mode 100644 index 0000000..07ade54 --- /dev/null +++ b/plugins/kimchi/kimchi.conf @@ -0,0 +1,67 @@ +[wok] +enable = True +plugin_class = "KimchiRoot" +uri = "/plugins/kimchi" + +[/] +tools.trailing_slash.on = False +request.methods_with_bodies = ('POST', 'PUT') +tools.nocache.on = True +tools.proxy.on = True +tools.sessions.on = True +tools.sessions.name = 'wok' +tools.sessions.secure = True +tools.sessions.httponly = True +tools.sessions.locking = 'explicit' +tools.sessions.storage_type = 'ram' +tools.sessions.timeout = 10 +tools.wokauth.on = True + +[/novnc] +tools.staticdir.on = True +tools.staticdir.dir = wok.config.PluginPaths('kimchi').novnc_dir +tools.nocache.on = True +tools.wokauth.on = True + +[/spice_auto.html] +tools.staticfile.on = True +tools.staticfile.filename = wok.config.PluginPaths('kimchi').spice_file +tools.nocache.on = True +tools.wokauth.on = True + +[/spice-html5] +tools.staticdir.on = True +tools.staticdir.dir = wok.config.PluginPaths('kimchi').spice_dir +tools.nocache.on = True + +[/spice-html5/spice.css] +tools.staticfile.on = True +tools.staticfile.filename = wok.config.PluginPaths('kimchi').spice_css_file +tools.nocache.on = True + +[/data/screenshots] +tools.staticdir.on = True +tools.staticdir.dir = wok.config.PluginPaths('kimchi').state_dir + '/screenshots' +tools.nocache.on = False + +[/data/debugreports] +tools.staticdir.on = True +tools.staticdir.dir = wok.config.PluginPaths('kimchi').state_dir + '/debugreports' +tools.nocache.on = False +tools.wokauth.on = True +tools.staticdir.content_types = {'xz': 'application/x-xz'} + +[/favicon.ico] +tools.staticfile.on = True +tools.staticfile.filename = wok.config.PluginPaths('kimchi').ui_dir + '/images/logo.ico' + +[/robots.txt] +tools.staticfile.on = True +tools.staticfile.filename = wok.config.PluginPaths('kimchi').ui_dir + '/robots.txt' + +[/help] +tools.staticdir.on = True +tools.staticdir.dir = wok.config.PluginPaths('kimchi').ui_dir + '/pages/help' +tools.nocache.on = True +tools.staticdir.index = 'en_US/index.html' + diff --git a/plugins/kimchi/root.py b/plugins/kimchi/root.py new file mode 100644 index 0000000..c05a6cb --- /dev/null +++ b/plugins/kimchi/root.py @@ -0,0 +1,57 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2015 +# +# 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 json +import os + + +import config +from control import sub_nodes +from wok.i18n import messages +from wok.config import PluginPaths +from model import model as kimchiModel +from wok.root import WokRoot + + +class KimchiRoot(WokRoot): + def __init__(self, model=None, dev_env=False): + if not model: + self.model = kimchiModel.Model() + else: + self.model = model + super(KimchiRoot, self).__init__(self.model, dev_env) + + for ident, node in sub_nodes.items(): + setattr(self, ident, node(self.model)) + + self.api_schema = json.load(open(os.path.join(os.path.dirname( + os.path.abspath(__file__)), 'API.json'))) + self.paths = PluginPaths('kimchi') + self.domain = 'kimchi' + self.messages = messages + + make_dirs = [ + os.path.abspath(config.get_distros_store()), + os.path.abspath(config.get_debugreports_path()), + os.path.abspath(config.get_screenshot_path()) + ] + for directory in make_dirs: + if not os.path.isdir(directory): + os.makedirs(directory) + diff --git a/plugins/kimchi/ui/config/tab-ext.xml b/plugins/kimchi/ui/config/tab-ext.xml index f79684c..ee88c88 100644 --- a/plugins/kimchi/ui/config/tab-ext.xml +++ b/plugins/kimchi/ui/config/tab-ext.xml @@ -1,38 +1,38 @@ <?xml version="1.0" encoding="utf-8"?> -<tabs> +<tabs-ext> <tab> <access role="admin" mode="admin"/> <access role="user" mode="none"/> <title>Host</title> - <path>tabs/host.html</path> + <path>plugins/kimchi/host.html</path> </tab> <tab> <access role="admin" mode="admin"/> <access role="user" mode="byInstance"/> <title>Guests</title> - <path>tabs/guests.html</path> + <path>plugins/kimchi/guests.html</path> </tab> <tab> <access role="admin" mode="admin"/> <access role="user" mode="none"/> <title>Templates</title> - <path>tabs/templates.html</path> + <path>plugins/kimchi/templates.html</path> </tab> <tab> <access role="admin" mode="admin"/> <access role="user" mode="read-only"/> <title>Storage</title> - <path>tabs/storage.html</path> + <path>plugins/kimchi/storage.html</path> </tab> <tab> <access role="admin" mode="admin"/> <access role="user" mode="read-only"/> <title>Network</title> - <path>tabs/network.html</path> + <path>plugins/kimchi/network.html</path> </tab> -</tabs> +</tabs-ext> diff --git a/plugins/kimchi/ui/js/src/kimchi.api.js b/plugins/kimchi/ui/js/src/kimchi.api.js index a74d660..ba1b762 100644 --- a/plugins/kimchi/ui/js/src/kimchi.api.js +++ b/plugins/kimchi/ui/js/src/kimchi.api.js @@ -547,25 +547,6 @@ var kimchi = { }); }, - login : function(settings, suc, err) { - $.ajax({ - url : "login", - type : "POST", - contentType : "application/json", - data : JSON.stringify(settings), - dataType : "json" - }).done(suc).fail(err); - }, - - logout : function(suc, err) { - kimchi.requestJSON({ - url : 'logout', - type : 'POST', - contentType : "application/json", - dataType : "json" - }).done(suc).fail(err); - }, - deleteStoragePool : function(poolName, suc, err) { $.ajax({ url : 'plugins/kimchi/storagepools/' + encodeURIComponent(poolName), diff --git a/src/wok/config.py.in b/src/wok/config.py.in index 390ba3b..2951539 100644 --- a/src/wok/config.py.in +++ b/src/wok/config.py.in @@ -18,78 +18,27 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # -import libvirt import os -import platform -import threading from ConfigParser import SafeConfigParser -from kimchi.xmlutils.utils import xpath_get_text - __version__ = "@wokversion@" __release__ = "@wokrelease@" __with_spice__ = "@withspice@" DEFAULT_LOG_LEVEL = "debug" -kimchiLock = threading.Lock() - -# Storage pool constant for read-only pool types -READONLY_POOL_TYPE = ['iscsi', 'scsi', 'mpath'] - def get_object_store(): return os.path.join(paths.state_dir, 'objectstore') -def get_distros_store(): - return os.path.join(paths.conf_dir, 'distros.d') - - -def get_screenshot_path(): - return os.path.join(paths.state_dir, 'screenshots') - - -def get_debugreports_path(): - return os.path.join(paths.state_dir, 'debugreports') - - def get_version(): return "-".join([__version__, __release__]) -def find_qemu_binary(find_emulator=False): - try: - connect = libvirt.open(None) - except Exception, e: - raise Exception("Unable to get qemu binary location: %s" % e) - try: - xml = connect.getCapabilities() - - # On Little Endian system, the qemu binary is - # qemu-system-ppc64, not qemu-system-ppc64le as expected - arch = platform.machine() - if arch == "ppc64le": - arch = "ppc64" - - if find_emulator: - expr = "/capabilities/guest/arch[@name='%s']\ - /emulator" % arch - else: - expr = "/capabilities/guest/arch[@name='%s']\ - /domain[@type='kvm']/emulator" % arch - res = xpath_get_text(xml, expr) - location = res[0] - except Exception, e: - raise Exception("Unable to get qemu binary location: %s" % e) - finally: - connect.close() - return location - - class Paths(object): def __init__(self): @@ -214,57 +163,9 @@ class WokConfig(dict): 'tools.nocache.on': True, 'tools.wokauth.on': True }, - '/spice_auto.html': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': paths.spice_file, - 'tools.nocache.on': True, - 'tools.kimchiauth.on': True - }, - '/spice-html5': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': paths.spice_dir, - 'tools.nocache.on': True - }, - '/spice-html5/spice.css': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': paths.spice_css_file, - 'tools.nocache.on': True, - }, '/wok-ui.html': { 'tools.wokauth.on': True }, - '/data/screenshots': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': get_screenshot_path(), - 'tools.nocache.on': False - }, - '/data/debugreports': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': get_debugreports_path(), - 'tools.nocache.on': False, - 'tools.kimchiauth.on': True, - 'tools.staticdir.content_types': {'xz': 'application/x-xz'} - }, - '/config/ui/tabs.xml': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': '%s/config/ui/tabs.xml' % - paths.prefix, - 'tools.nocache.on': True - }, - '/favicon.ico': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': '%s/images/logo.ico' % paths.ui_dir - }, - '/robots.txt': { - 'tools.staticfile.on': True, - 'tools.staticfile.filename': '%s/robots.txt' % paths.ui_dir - }, - '/help': { - 'tools.staticdir.on': True, - 'tools.staticdir.dir': '%s/ui/pages/help' % paths.prefix, - 'tools.staticdir.index': 'en_US/index.html', - 'tools.nocache.on': True - } } def __init__(self): diff --git a/src/wok/root.py b/src/wok/root.py index a3b8be1..2b4ad44 100644 --- a/src/wok/root.py +++ b/src/wok/root.py @@ -114,16 +114,16 @@ class Root(Resource): raise cherrypy.HTTPError(404) -class KimchiRoot(Root): +class WokRoot(Root): def __init__(self, model, dev_env): - super(KimchiRoot, self).__init__(model, dev_env) - self.default_page = 'kimchi-ui.html' + super(WokRoot, self).__init__(model, dev_env) + self.default_page = 'wok-ui.html' for ident, node in sub_nodes.items(): setattr(self, ident, node(model)) with open(os.path.join(paths.src_dir, 'API.json')) as f: self.api_schema = json.load(f) self.paths = paths - self.domain = 'kimchi' + self.domain = 'wok' self.messages = messages @cherrypy.expose diff --git a/src/wok/server.py b/src/wok/server.py index 0f99663..711c24f 100644 --- a/src/wok/server.py +++ b/src/wok/server.py @@ -25,13 +25,12 @@ import os from wok import auth from wok import config -from wok.model import model -from wok import mockmodel from wok import vnc -from wok.config import KimchiConfig, PluginConfig +from wok.model import model +from wok.config import WokConfig, PluginConfig from wok.control import sub_nodes from wok.proxy import start_proxy, terminate_proxy -from wok.root import KimchiRoot +from wok.root import WokRoot from wok.utils import get_enabled_plugins, import_class @@ -64,16 +63,13 @@ class Server(object): make_dirs = [ os.path.dirname(os.path.abspath(options.access_log)), os.path.dirname(os.path.abspath(options.error_log)), - os.path.dirname(os.path.abspath(config.get_object_store())), - os.path.abspath(config.get_screenshot_path()), - os.path.abspath(config.get_debugreports_path()), - os.path.abspath(config.get_distros_store()) + os.path.dirname(os.path.abspath(config.get_object_store())) ] for directory in make_dirs: if not os.path.isdir(directory): os.makedirs(directory) - self.configObj = KimchiConfig() + self.configObj = WokConfig() # We'll use the session timeout (= 10 minutes) and the # nginx timeout (= 10 minutes). This monitor isn't involved # in anything other than monitor the timeout of the connection, @@ -126,12 +122,10 @@ class Server(object): if hasattr(options, 'model'): model_instance = options.model - elif options.test: - model_instance = mockmodel.MockModel() else: model_instance = model.Model() - if isinstance(model_instance, model.Model): + if isinstance(model_instance, model.Model) and not options.test: vnc_ws_proxy = vnc.new_ws_proxy() cherrypy.engine.subscribe('exit', vnc_ws_proxy.terminate) @@ -141,7 +135,7 @@ class Server(object): ident = "/%s" % ident cfg[ident] = {'tools.wokauth.on': True} - self.app = cherrypy.tree.mount(KimchiRoot(model_instance, dev_env), + self.app = cherrypy.tree.mount(WokRoot(model_instance, dev_env), config=self.configObj) self._load_plugins() diff --git a/src/wok/utils.py b/src/wok/utils.py index 267cd3e..42e753d 100644 --- a/src/wok/utils.py +++ b/src/wok/utils.py @@ -113,7 +113,7 @@ def get_enabled_plugins(): def get_all_tabs(): - files = [os.path.join(paths.prefix, 'config/ui/tabs.xml')] + files = [] for plugin, _ in get_enabled_plugins(): files.append(os.path.join(PluginPaths(plugin).ui_dir, diff --git a/ui/js/src/wok.main.js b/ui/js/src/wok.main.js index 089b523..5b1f1bc 100644 --- a/ui/js/src/wok.main.js +++ b/ui/js/src/wok.main.js @@ -90,12 +90,11 @@ wok.main = function() { return tabs; }; - var tabConfigUrl = 'config/ui/tabs.xml'; var pluginConfigUrl = 'plugins/{plugin}/ui/config/tab-ext.xml'; var pluginI18nUrl = 'plugins/{plugin}/i18n.json'; var DEFAULT_HASH; var buildTabs = function(callback) { - var tabs = retrieveTabs(tabConfigUrl); + var tabs = []; wok.listPlugins(function(plugins) { $(plugins).each(function(i, p) { var url = wok.substitute(pluginConfigUrl, { -- 1.7.1