[PATCH 0/8] Refactor exception

From: Aline Manera <alinefm@br.ibm.com> This patch set includes: - Create a common Exception class (KimchiError) to translate the error message and proper set the parameters - Create a i18n.py file with all messages used on backend - Update build process to add the messages in this file to .po files - Update UI to show the message received from backend to the user - Update UI messages to add a code for them - Display error message like: <code>: <msg> Aline Manera (8): refactor exception: Create a common Exception to translate error messages refactor exception: Add messages to be translated on backend refactor exception: Set error messages for jsonschema validation refator exception: Update control to raise the exception message refactor exception: Update all exceptions refactor exception: Update gen-pot script to get messages from i18n.py refactor exception: Update UI references refactor exception: Update all po files plugins/sample/API.json | 23 +- plugins/sample/Makefile.am | 1 + plugins/sample/__init__.py | 7 +- plugins/sample/i18n.py | 44 ++ plugins/sample/model.py | 12 +- po/POTFILES.in | 1 + po/en_US.po | 686 ++++++++++++++++++++++++------ po/gen-pot.in | 8 +- po/kimchi.pot | 624 ++++++++++++++++++++++----- po/pt_BR.po | 684 +++++++++++++++++++++++------ po/zh_CN.po | 678 +++++++++++++++++++++++------ src/kimchi/API.json | 144 +++++-- src/kimchi/Makefile.am | 1 + src/kimchi/asynctask.py | 4 +- src/kimchi/auth.py | 3 +- src/kimchi/control/base.py | 90 ++-- src/kimchi/control/utils.py | 5 +- src/kimchi/disks.py | 5 +- src/kimchi/distroloader.py | 5 +- src/kimchi/exception.py | 42 +- src/kimchi/i18n.py | 173 ++++++++ src/kimchi/iscsi.py | 6 +- src/kimchi/isoinfo.py | 17 +- src/kimchi/mockmodel.py | 113 +++-- src/kimchi/model/config.py | 2 +- src/kimchi/model/debugreports.py | 18 +- src/kimchi/model/host.py | 10 +- src/kimchi/model/interfaces.py | 4 +- src/kimchi/model/libvirtstoragepool.py | 14 +- src/kimchi/model/networks.py | 37 +- src/kimchi/model/storagepools.py | 39 +- src/kimchi/model/storageservers.py | 2 +- src/kimchi/model/storagevolumes.py | 37 +- src/kimchi/model/templates.py | 44 +- src/kimchi/model/utils.py | 2 +- src/kimchi/model/vmifaces.py | 15 +- src/kimchi/model/vms.py | 28 +- src/kimchi/objectstore.py | 4 +- src/kimchi/root.py | 3 + src/kimchi/template.py | 2 +- src/kimchi/utils.py | 12 +- src/kimchi/vmtemplate.py | 7 +- tests/test_exception.py | 4 +- tests/test_rest.py | 4 +- tests/utils.py | 5 +- ui/js/src/kimchi.api.js | 4 +- ui/js/src/kimchi.guest_add_main.js | 7 +- ui/js/src/kimchi.guest_main.js | 32 +- ui/js/src/kimchi.host.js | 46 +- ui/js/src/kimchi.line-chart.js | 2 +- ui/js/src/kimchi.login_window.js | 8 +- ui/js/src/kimchi.main.js | 6 +- ui/js/src/kimchi.message.js | 4 + ui/js/src/kimchi.network.js | 22 +- ui/js/src/kimchi.report_add_main.js | 8 +- ui/js/src/kimchi.storage_main.js | 18 +- ui/js/src/kimchi.storagepool_add_main.js | 28 +- ui/js/src/kimchi.template_add_main.js | 18 +- ui/js/src/kimchi.template_main.js | 16 +- ui/js/widgets/filter-select.js | 4 +- ui/js/widgets/select-menu.js | 4 +- ui/pages/i18n.html.tmpl | 172 ++++---- 62 files changed, 3046 insertions(+), 1022 deletions(-) create mode 100644 plugins/sample/i18n.py create mode 100644 src/kimchi/i18n.py -- 1.7.10.4

From: Aline Manera <alinefm@br.ibm.com> KimchiException will be the base for all other Exception types in Kimchi It will translate the error message before raising it. Then UI can use the message directly. That way we avoid duplicating messages on UI and backend. Also add i18n.py which will contain all the backend messages to be translated. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/Makefile.am | 1 + plugins/sample/__init__.py | 7 ++++++- plugins/sample/i18n.py | 29 +++++++++++++++++++++++++++++ src/kimchi/Makefile.am | 1 + src/kimchi/exception.py | 28 ++++++++++++++++++++++++++++ src/kimchi/i18n.py | 29 +++++++++++++++++++++++++++++ src/kimchi/root.py | 3 +++ 7 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 plugins/sample/i18n.py create mode 100644 src/kimchi/i18n.py diff --git a/plugins/sample/Makefile.am b/plugins/sample/Makefile.am index 0cb5723..afab703 100644 --- a/plugins/sample/Makefile.am +++ b/plugins/sample/Makefile.am @@ -26,4 +26,5 @@ EXTRA_DIST = \ __init__.py \ API.json \ model.py \ + i18n.py \ sample.conf diff --git a/plugins/sample/__init__.py b/plugins/sample/__init__.py index a1fe44e..fff9aa7 100644 --- a/plugins/sample/__init__.py +++ b/plugins/sample/__init__.py @@ -27,8 +27,10 @@ import os from cherrypy import expose +from kimchi.config import PluginPaths from kimchi.control.base import Collection, Resource -from model import Model +from plugins.sample.i18n import messages +from plugins.sample.model import Model model = Model() @@ -40,6 +42,9 @@ class Drawings(Resource): self.description = Description(model) self.rectangles = Rectangles(model) self.circles = Circles(model) + self.paths = PluginPaths('sample') + self.domain = 'sample' + self.messages = messages self.api_schema = json.load(open(os.path.join(os.path.dirname( os.path.abspath(__file__)), 'API.json'))) diff --git a/plugins/sample/i18n.py b/plugins/sample/i18n.py new file mode 100644 index 0000000..204460c --- /dev/null +++ b/plugins/sample/i18n.py @@ -0,0 +1,29 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# +# 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 gettext + +_ = gettext.gettext + + +messages = { +} diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 1653c0c..51a496e 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -32,6 +32,7 @@ kimchi_PYTHON = \ distroloader.py \ exception.py \ featuretests.py \ + i18n.py \ iscsi.py \ isoinfo.py \ mockmodel.py \ diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py index a37015b..7fcce54 100644 --- a/src/kimchi/exception.py +++ b/src/kimchi/exception.py @@ -20,6 +20,34 @@ # 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 +import gettext + + +from kimchi.template import get_lang, validate_language + + +class KimchiException(Exception): + def __init__(self, code='', args={}): + lang = validate_language(get_lang()) + paths = cherrypy.request.app.root.paths + domain = cherrypy.request.app.root.domain + messages = cherrypy.request.app.root.messages + text = messages.get(code, code) + + try: + translation = gettext.translation(domain, paths.mo_dir, [lang]) + except: + translation = gettext + + for key, value in args.iteritems(): + if not isinstance(value, unicode): + args[key] = unicode(value, 'utf-8') + + msg = unicode(translation.gettext(text), 'utf-8') % args + pattern = "%s: %s" % (code, msg) + Exception.__init__(self, pattern) + class NotFoundError(Exception): pass diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py new file mode 100644 index 0000000..204460c --- /dev/null +++ b/src/kimchi/i18n.py @@ -0,0 +1,29 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# +# 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 gettext + +_ = gettext.gettext + + +messages = { +} diff --git a/src/kimchi/root.py b/src/kimchi/root.py index ce4a49c..2b5c4b8 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -28,6 +28,7 @@ import os from kimchi import auth from kimchi import template +from kimchi.i18n import messages from kimchi.config import paths from kimchi.control import sub_nodes from kimchi.control.base import Resource @@ -95,6 +96,8 @@ class KimchiRoot(Root): self.api_schema = json.load(open(os.path.join(paths.src_dir, 'API.json'))) self.paths = paths + self.domain = 'kimchi' + self.messages = messages @cherrypy.expose def login(self, *args): -- 1.7.10.4

Reviewed-by: Leonardo Garcia <lagarcia@br.ibm.com> On 02/09/2014 08:47 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
KimchiException will be the base for all other Exception types in Kimchi It will translate the error message before raising it. Then UI can use the message directly. That way we avoid duplicating messages on UI and backend. Also add i18n.py which will contain all the backend messages to be translated.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/Makefile.am | 1 + plugins/sample/__init__.py | 7 ++++++- plugins/sample/i18n.py | 29 +++++++++++++++++++++++++++++ src/kimchi/Makefile.am | 1 + src/kimchi/exception.py | 28 ++++++++++++++++++++++++++++ src/kimchi/i18n.py | 29 +++++++++++++++++++++++++++++ src/kimchi/root.py | 3 +++ 7 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 plugins/sample/i18n.py create mode 100644 src/kimchi/i18n.py
diff --git a/plugins/sample/Makefile.am b/plugins/sample/Makefile.am index 0cb5723..afab703 100644 --- a/plugins/sample/Makefile.am +++ b/plugins/sample/Makefile.am @@ -26,4 +26,5 @@ EXTRA_DIST = \ __init__.py \ API.json \ model.py \ + i18n.py \ sample.conf diff --git a/plugins/sample/__init__.py b/plugins/sample/__init__.py index a1fe44e..fff9aa7 100644 --- a/plugins/sample/__init__.py +++ b/plugins/sample/__init__.py @@ -27,8 +27,10 @@ import os from cherrypy import expose
+from kimchi.config import PluginPaths from kimchi.control.base import Collection, Resource -from model import Model +from plugins.sample.i18n import messages +from plugins.sample.model import Model
model = Model() @@ -40,6 +42,9 @@ class Drawings(Resource): self.description = Description(model) self.rectangles = Rectangles(model) self.circles = Circles(model) + self.paths = PluginPaths('sample') + self.domain = 'sample' + self.messages = messages self.api_schema = json.load(open(os.path.join(os.path.dirname( os.path.abspath(__file__)), 'API.json')))
diff --git a/plugins/sample/i18n.py b/plugins/sample/i18n.py new file mode 100644 index 0000000..204460c --- /dev/null +++ b/plugins/sample/i18n.py @@ -0,0 +1,29 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# +# 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 gettext + +_ = gettext.gettext + + +messages = { +} diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 1653c0c..51a496e 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -32,6 +32,7 @@ kimchi_PYTHON = \ distroloader.py \ exception.py \ featuretests.py \ + i18n.py \ iscsi.py \ isoinfo.py \ mockmodel.py \ diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py index a37015b..7fcce54 100644 --- a/src/kimchi/exception.py +++ b/src/kimchi/exception.py @@ -20,6 +20,34 @@ # 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 +import gettext + + +from kimchi.template import get_lang, validate_language + + +class KimchiException(Exception): + def __init__(self, code='', args={}): + lang = validate_language(get_lang()) + paths = cherrypy.request.app.root.paths + domain = cherrypy.request.app.root.domain + messages = cherrypy.request.app.root.messages + text = messages.get(code, code) + + try: + translation = gettext.translation(domain, paths.mo_dir, [lang]) + except: + translation = gettext + + for key, value in args.iteritems(): + if not isinstance(value, unicode): + args[key] = unicode(value, 'utf-8') + + msg = unicode(translation.gettext(text), 'utf-8') % args + pattern = "%s: %s" % (code, msg) + Exception.__init__(self, pattern) +
class NotFoundError(Exception): pass diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py new file mode 100644 index 0000000..204460c --- /dev/null +++ b/src/kimchi/i18n.py @@ -0,0 +1,29 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# +# 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 gettext + +_ = gettext.gettext + + +messages = { +} diff --git a/src/kimchi/root.py b/src/kimchi/root.py index ce4a49c..2b5c4b8 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -28,6 +28,7 @@ import os
from kimchi import auth from kimchi import template +from kimchi.i18n import messages from kimchi.config import paths from kimchi.control import sub_nodes from kimchi.control.base import Resource @@ -95,6 +96,8 @@ class KimchiRoot(Root): self.api_schema = json.load(open(os.path.join(paths.src_dir, 'API.json'))) self.paths = paths + self.domain = 'kimchi' + self.messages = messages
@cherrypy.expose def login(self, *args):

From: Aline Manera <alinefm@br.ibm.com> src/kimchi/i18n.py and plugins/sample/i18n.py contain all messages used in backend to report error to the user Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/i18n.py | 15 +++++ src/kimchi/i18n.py | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) diff --git a/plugins/sample/i18n.py b/plugins/sample/i18n.py index 204460c..b4cd5cb 100644 --- a/plugins/sample/i18n.py +++ b/plugins/sample/i18n.py @@ -26,4 +26,19 @@ _ = gettext.gettext messages = { + "SPAPI0001E": _("Unkown parameter specified %(value)s"), + "SPAPI0002E": _("The specified value %(value)s is not a positive number"), + + "SPCIRC0001E": _("Circle %(name)s already exists"), + "SPCIRC0002E": _("Circle %(name)s does not exist"), + "SPCIRC0003E": _("Specify name and radius to create a Circle"), + "SPCIRC0004E": _("Circle name must be a string"), + "SPCIRC0005E": _("Circle radius must be a positive number"), + + "SPRET0001E": _("Rectangle %(name)s already exists"), + "SPRET0002E": _("Rectangle %(name)s does not exist"), + "SPRET0003E": _("Specify name, length and width to create a Rectangle"), + "SPRET0004E": _("Rectangle name must be a string"), + "SPRET0005E": _("Rectangle length must be a positive number"), + "SPRET0006E": _("Rectangle width must be a positive number"), } diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 204460c..1a8fb5b 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -26,4 +26,148 @@ _ = gettext.gettext messages = { + "KCHAPI0001E": _("Unkown parameter specified %(value)s"), + + "KCHASYNC0001E": _("Datastore is not initiated in the model object."), + + "KCHAUTH0001E": _("Authentication failed for user '%(userid)s'. [Error code: %(code)s]"), + + "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"), + "KCHDISKS0002E": _("Error while getting block device information for %(device)s."), + + "KCHDL0001E": _("Unable to find distro file: %(filename)s"), + "KCHDL0002E": _("Unable to parse distro file: %(filename)s.Make sure, it is a json file."), + + "KCHISCSI0001E": _("Unable to login to iSCSI host target %(portal)s. Details: %(err)s"), + "KCHISCSI0002E": _("Unable to login to iSCSI host %(host)s target %(target)s"), + + "KCHISO0001E": _("Unable to find ISO file ISO %(filename)s"), + "KCHISO0002E": _("The ISO file %(filename)s is not bootable"), + "KCHISO0003E": _("The ISO file %(filename)s does not have a valid El Torito boot record"), + "KCHISO0004E": _("Invalid El Torito validation entry in ISO %(filename)s"), + "KCHISO0005E": _("Invalid El Torito boot indicator in ISO %(filename)s"), + "KCHISO0006E": _("Unexpected volume type for primary volume in ISO %(filename)s"), + "KCHISO0007E": _("Bad format while reading volume descriptor in ISO %(filename)s"), + + "KCHVM0001E": _("Virtual machine $(name)s already exists"), + "KCHVM0002E": _("Virtual machine %(name)s does not exist"), + "KCHVM0003E": _("Unable to rename virtual machine %(name)s. The name %(new_name)s already exists or it is not powered off."), + "KCHVM0004E": _("Unable to retrieve screenshot for stopped virtual machine %(name)s"), + "KCHVM0005E": _("Remote ISO image is not supported by this server."), + "KCHVM0006E": _("Screenshot not supported for virtual machine %(name)s"), + "KCHVM0007E": _("Unable to create virtual machine %(name)s. Details: %(err)s"), + "KCHVM0008E": _("Unable to rename virtual machine %(name)s. Details: %(err)s"), + "KCHVM0009E": _("Unable to retrieve virtual machine %(name)s. Details: %(err)"), + "KCHVM0010E": _("Unable to connect to powered off machine %(name)s."), + "KCHVM0011E": _("Virtual machine name must be a string"), + "KCHVM0012E": _("Invalid template URI: %(value)s specified for virtual machine"), + "KCHVM0013E": _("Invalid storage pool URI: %(value)s specified for virtual machine"), + "KCHVM0014E": _("Supported virtual machine graphics are spice or vnc"), + "KCHVM0015E": _("Graphics address to listen on must be IPv4 or IPv6"), + "KCHVM0016E": _("Specify a template to create a Virtual Machine from"), + + "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), + "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), + "KCHVMIF0003E": _("Do not support guest interface hot plug attachment"), + "KCHVMIF0004E": _("Supported virtual machine interfaces type is only network"), + "KCHVMIF0005E": _("Network name for virtual machine interface must be a string"), + "KCHVMIF0006E": _("Invalid network model card specified for virtual machine interface"), + "KCHVMIF0007E": _("Specify type and network to add a new virtual machine interface"), + + "KCHTMPL0001E": _("Template %(name)s already exists"), + "KCHTMPL0002E": _("Template %(name)s does not exist"), + "KCHTMPL0003E": _("Network '%(network)s' specified for template %(template)s does not exist"), + "KCHTMPL0004E": _("Storage Pool %(pool)s specified for template %(template)s does not exist"), + "KCHTMPL0005E": _("Storage Pool %(pool)s specified for template %(template)s is not active"), + "KCHTMPL0006E": _("Invalid parameter '%(param)s' specified for cdrom."), + "KCHTMPL0007E": _("Network %(network)s specified for template %(template)s is not active"), + "KCHTMPL0008E": _("Template name must be a string"), + "KCHTMPL0009E": _("Template icon must be a path to the image"), + "KCHTMPL0010E": _("Template distribution must be a string"), + "KCHTMPL0011E": _("Template distribution version must be a string"), + "KCHTMPL0012E": _("The number of CPUs must be a integer"), + "KCHTMPL0013E": _("Amount of memory (MB) must be an integer greater than 512"), + "KCHTMPL0014E": _("Template CDROM must be a local or remote ISO file"), + "KCHTMPL0015E": _("Invalid storage pool URI %(value)s specified for Template"), + "KCHTMPL0016E": _("Specify an ISO image as CDROM to create a Template"), + "KCHTMPL0017E": _("All networks for the Template must be specified in a list."), + + "KCHPOOL0001E": _("Storage Pool %(name)s already exists"), + "KCHPOOL0002E": _("Storage Pool %(name)s does not exist"), + "KCHPOOL0003E": _("Autostart flag must be true or false"), + "KCHPOOL0004E": _("Specify %(item)s in order to create the Storage Pool %(name)s"), + "KCHPOOL0005E": _("Unable to delete active Storage Pool %(name)s"), + "KCHPOOL0006E": _("Unable to list Storage Pools. Details: %(err)s"), + "KCHPOOL0007E": _("Unable to create Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0008E": _("Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0009E": _("Unable to activate Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0010E": _("Unable to deactivate Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0011E": _("Unable to delete Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0012E": _("Unable to create NFS Pool as export path %(path)s may block during mount"), + "KCHPOOL0013E": _("Unable to create NFS Pool as export path %(path)s mount failed"), + "KCHPOOL0014E": _("Unsupported Storage Pool type: %(type)s"), + "KCHPOOL0015E": _("Error while getting xml for Storage Pool %(pool)s"), + "KCHPOOL0016E": _("Storage Pool name must be a string"), + "KCHPOOL0017E": _("Supported Storage Pool types are dir, netfs, logical and kimchi-iso"), + "KCHPOOL0018E": _("Storage Pool path must be a string"), + "KCHPOOL0019E": _("Storage Pool host must be a IP or hostname"), + "KCHPOOL0020E": _("Storage Pool devices must be the full path to the block device"), + "KCHPOOL0021E": _("Storage Pool devices parameter must be a list"), + "KCHPOOL0022E": _("Target IQN of an iSCSI pool must be a string"), + "KCHPOOL0023E": _("Port of a remote storage server must be an integer between 1 and 65535"), + "KCHPOOL0024E": _("Login username of the iSCSI target must be a string"), + "KCHPOOL0025E": _("Login password of the iSCSI target must be a string"), + "KCHPOOL0026E": _("Specify name and type to create a Storage Pool"), + + "KCHVOL0001E": _("Storage Volume %(name)s already exists"), + "KCHVOL0002E": _("Storage Volume %(name)s does not exist in Storage Pool %(pool)s"), + "KCHVOL0003E": _("Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is not active"), + "KCHVOL0004E": _("Specify %(item)s in order to create Storage Volume %(volume)s"), + "KCHVOL0005E": _("Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s is not active"), + "KCHVOL0006E": _("Unable to list Storage Volumes because Storage Pool %(pool)s is not active"), + "KCHVOL0007E": _("Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: %(err)s"), + "KCHVOL0008E": _("Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s"), + "KCHVOL0009E": _("Unable to wipe Storage Volumes %(name)s. Details: %(err)s"), + "KCHVOL0010E": _("Unable to delete Storage Volume %(name)s. Details: %(err)s"), + "KCHVOL0011E": _("Unable to resize Storage Volume %(name)s. Details: %(err)s"), + + "KCHIFACE0001E": _("Interface %(name)s does not exist"), + + "KCHNET0001E": _("Network %(name)s already exists"), + "KCHNET0002E": _("Network %(name)s does not exist"), + "KCHNET0003E": _("Subnet %(subnet)s specified for network %(network)s is not valid."), + "KCHNET0004E": _("Specify a network interface to create bridged network %(name)s"), + "KCHNET0005E": _("Unable to delete active network %(name)s"), + "KCHNET0006E": _("Interface %(iface)s specified for network %(network)s is already in use"), + "KCHNET0007E": _("Interface should be bare nic, bonding or bridge device."), + "KCHNET0008E": _("Unable to create network %(name)s. Details: %(err)s"), + "KCHNET0009E": _("Unable to find a free IP address for network '%(name)s'"), + "KCHNET0010E": _("Unable to create VLAN tagged bridge using interface %(iface)s. Details: %(err)"), + "KCHNET0011E": _("Network name must be a string"), + "KCHNET0012E": _("Supported network types are isolated, nat and bridge"), + "KCHNET0013E": _("Network subnet must be a string with ip address and prefix or netmask"), + "KCHNET0014E": _("Network interface must be a string"), + "KCHNET0015E": _("Network VLAN ID must be an integer between 1 and 4094"), + "KCHNET0016E": _("Specify name and type to create a Network"), + + "KCHDR0001E": _("Debug report %(name)s does not exist"), + "KCHDR0002E": _("Debug report tool not found in system"), + "KCHDR0003E": _("Unable to create debug report %(name)s. Details: %(err)s."), + "KCHDR0004E": _("Can not find generated debug report named %(name)s"), + "KCHDR0005E": _("Unable to generate debug report %(name)s. Details: %(err)s"), + + "KCHSR0001E": _("Storage server %(server)s was not used by Kimchi"), + + "KCHDISTRO0001E": _("Distro '%(name)s' does not exist"), + + "KCHPART0001E": _("Partition %(name)s does not exist in the host"), + + "KCHHOST0001E": _("Unable to shutdown host machine as there are running virtual machines"), + "KCHHOST0002E": _("Unable to reboot host machine as there are running virtual machines"), + + "KCHOBJST0001E": _("Unable to find %(item)s in datastore"), + + "KCHUTILS0001E": _("Invalid URI %(uri)s"), + "KCHUTILS0002E": _("Timeout while running command '%(cmd)s' after %(seconds)s seconds"), + "KCHUTILS0003E": _("Unable to choose a virutal machine name"), } -- 1.7.10.4

From: Aline Manera <alinefm@br.ibm.com>
src/kimchi/i18n.py and plugins/sample/i18n.py contain all messages used in backend to report error to the user
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/i18n.py | 15 +++++ src/kimchi/i18n.py | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+)
diff --git a/plugins/sample/i18n.py b/plugins/sample/i18n.py index 204460c..b4cd5cb 100644 --- a/plugins/sample/i18n.py +++ b/plugins/sample/i18n.py @@ -26,4 +26,19 @@ _ = gettext.gettext
messages = { + "SPAPI0001E": _("Unkown parameter specified %(value)s"), + "SPAPI0002E": _("The specified value %(value)s is not a positive number"), + + "SPCIRC0001E": _("Circle %(name)s already exists"), + "SPCIRC0002E": _("Circle %(name)s does not exist"), + "SPCIRC0003E": _("Specify name and radius to create a Circle"), + "SPCIRC0004E": _("Circle name must be a string"), + "SPCIRC0005E": _("Circle radius must be a positive number"), + + "SPRET0001E": _("Rectangle %(name)s already exists"), + "SPRET0002E": _("Rectangle %(name)s does not exist"), + "SPRET0003E": _("Specify name, length and width to create a Rectangle"), + "SPRET0004E": _("Rectangle name must be a string"), + "SPRET0005E": _("Rectangle length must be a positive number"), + "SPRET0006E": _("Rectangle width must be a positive number"), From where does these key values come? Are they just randomly chosen? Randomly or not, there should be a comment on how they were chosen in
On 02/09/2014 08:47 PM, Aline Manera wrote: the commit message. Also, IIRC, I heard that we were using the English version of the message as the key instead of these crypt keys. Has this changed? Best regards, Leonardo Garcia
} diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 204460c..1a8fb5b 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -26,4 +26,148 @@ _ = gettext.gettext
messages = { + "KCHAPI0001E": _("Unkown parameter specified %(value)s"), + + "KCHASYNC0001E": _("Datastore is not initiated in the model object."), + + "KCHAUTH0001E": _("Authentication failed for user '%(userid)s'. [Error code: %(code)s]"), + + "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"), + "KCHDISKS0002E": _("Error while getting block device information for %(device)s."), + + "KCHDL0001E": _("Unable to find distro file: %(filename)s"), + "KCHDL0002E": _("Unable to parse distro file: %(filename)s.Make sure, it is a json file."), + + "KCHISCSI0001E": _("Unable to login to iSCSI host target %(portal)s. Details: %(err)s"), + "KCHISCSI0002E": _("Unable to login to iSCSI host %(host)s target %(target)s"), + + "KCHISO0001E": _("Unable to find ISO file ISO %(filename)s"), + "KCHISO0002E": _("The ISO file %(filename)s is not bootable"), + "KCHISO0003E": _("The ISO file %(filename)s does not have a valid El Torito boot record"), + "KCHISO0004E": _("Invalid El Torito validation entry in ISO %(filename)s"), + "KCHISO0005E": _("Invalid El Torito boot indicator in ISO %(filename)s"), + "KCHISO0006E": _("Unexpected volume type for primary volume in ISO %(filename)s"), + "KCHISO0007E": _("Bad format while reading volume descriptor in ISO %(filename)s"), + + "KCHVM0001E": _("Virtual machine $(name)s already exists"), + "KCHVM0002E": _("Virtual machine %(name)s does not exist"), + "KCHVM0003E": _("Unable to rename virtual machine %(name)s. The name %(new_name)s already exists or it is not powered off."), + "KCHVM0004E": _("Unable to retrieve screenshot for stopped virtual machine %(name)s"), + "KCHVM0005E": _("Remote ISO image is not supported by this server."), + "KCHVM0006E": _("Screenshot not supported for virtual machine %(name)s"), + "KCHVM0007E": _("Unable to create virtual machine %(name)s. Details: %(err)s"), + "KCHVM0008E": _("Unable to rename virtual machine %(name)s. Details: %(err)s"), + "KCHVM0009E": _("Unable to retrieve virtual machine %(name)s. Details: %(err)"), + "KCHVM0010E": _("Unable to connect to powered off machine %(name)s."), + "KCHVM0011E": _("Virtual machine name must be a string"), + "KCHVM0012E": _("Invalid template URI: %(value)s specified for virtual machine"), + "KCHVM0013E": _("Invalid storage pool URI: %(value)s specified for virtual machine"), + "KCHVM0014E": _("Supported virtual machine graphics are spice or vnc"), + "KCHVM0015E": _("Graphics address to listen on must be IPv4 or IPv6"), + "KCHVM0016E": _("Specify a template to create a Virtual Machine from"), + + "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), + "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), + "KCHVMIF0003E": _("Do not support guest interface hot plug attachment"), + "KCHVMIF0004E": _("Supported virtual machine interfaces type is only network"), + "KCHVMIF0005E": _("Network name for virtual machine interface must be a string"), + "KCHVMIF0006E": _("Invalid network model card specified for virtual machine interface"), + "KCHVMIF0007E": _("Specify type and network to add a new virtual machine interface"), + + "KCHTMPL0001E": _("Template %(name)s already exists"), + "KCHTMPL0002E": _("Template %(name)s does not exist"), + "KCHTMPL0003E": _("Network '%(network)s' specified for template %(template)s does not exist"), + "KCHTMPL0004E": _("Storage Pool %(pool)s specified for template %(template)s does not exist"), + "KCHTMPL0005E": _("Storage Pool %(pool)s specified for template %(template)s is not active"), + "KCHTMPL0006E": _("Invalid parameter '%(param)s' specified for cdrom."), + "KCHTMPL0007E": _("Network %(network)s specified for template %(template)s is not active"), + "KCHTMPL0008E": _("Template name must be a string"), + "KCHTMPL0009E": _("Template icon must be a path to the image"), + "KCHTMPL0010E": _("Template distribution must be a string"), + "KCHTMPL0011E": _("Template distribution version must be a string"), + "KCHTMPL0012E": _("The number of CPUs must be a integer"), + "KCHTMPL0013E": _("Amount of memory (MB) must be an integer greater than 512"), + "KCHTMPL0014E": _("Template CDROM must be a local or remote ISO file"), + "KCHTMPL0015E": _("Invalid storage pool URI %(value)s specified for Template"), + "KCHTMPL0016E": _("Specify an ISO image as CDROM to create a Template"), + "KCHTMPL0017E": _("All networks for the Template must be specified in a list."), + + "KCHPOOL0001E": _("Storage Pool %(name)s already exists"), + "KCHPOOL0002E": _("Storage Pool %(name)s does not exist"), + "KCHPOOL0003E": _("Autostart flag must be true or false"), + "KCHPOOL0004E": _("Specify %(item)s in order to create the Storage Pool %(name)s"), + "KCHPOOL0005E": _("Unable to delete active Storage Pool %(name)s"), + "KCHPOOL0006E": _("Unable to list Storage Pools. Details: %(err)s"), + "KCHPOOL0007E": _("Unable to create Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0008E": _("Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0009E": _("Unable to activate Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0010E": _("Unable to deactivate Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0011E": _("Unable to delete Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0012E": _("Unable to create NFS Pool as export path %(path)s may block during mount"), + "KCHPOOL0013E": _("Unable to create NFS Pool as export path %(path)s mount failed"), + "KCHPOOL0014E": _("Unsupported Storage Pool type: %(type)s"), + "KCHPOOL0015E": _("Error while getting xml for Storage Pool %(pool)s"), + "KCHPOOL0016E": _("Storage Pool name must be a string"), + "KCHPOOL0017E": _("Supported Storage Pool types are dir, netfs, logical and kimchi-iso"), + "KCHPOOL0018E": _("Storage Pool path must be a string"), + "KCHPOOL0019E": _("Storage Pool host must be a IP or hostname"), + "KCHPOOL0020E": _("Storage Pool devices must be the full path to the block device"), + "KCHPOOL0021E": _("Storage Pool devices parameter must be a list"), + "KCHPOOL0022E": _("Target IQN of an iSCSI pool must be a string"), + "KCHPOOL0023E": _("Port of a remote storage server must be an integer between 1 and 65535"), + "KCHPOOL0024E": _("Login username of the iSCSI target must be a string"), + "KCHPOOL0025E": _("Login password of the iSCSI target must be a string"), + "KCHPOOL0026E": _("Specify name and type to create a Storage Pool"), + + "KCHVOL0001E": _("Storage Volume %(name)s already exists"), + "KCHVOL0002E": _("Storage Volume %(name)s does not exist in Storage Pool %(pool)s"), + "KCHVOL0003E": _("Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is not active"), + "KCHVOL0004E": _("Specify %(item)s in order to create Storage Volume %(volume)s"), + "KCHVOL0005E": _("Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s is not active"), + "KCHVOL0006E": _("Unable to list Storage Volumes because Storage Pool %(pool)s is not active"), + "KCHVOL0007E": _("Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: %(err)s"), + "KCHVOL0008E": _("Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s"), + "KCHVOL0009E": _("Unable to wipe Storage Volumes %(name)s. Details: %(err)s"), + "KCHVOL0010E": _("Unable to delete Storage Volume %(name)s. Details: %(err)s"), + "KCHVOL0011E": _("Unable to resize Storage Volume %(name)s. Details: %(err)s"), + + "KCHIFACE0001E": _("Interface %(name)s does not exist"), + + "KCHNET0001E": _("Network %(name)s already exists"), + "KCHNET0002E": _("Network %(name)s does not exist"), + "KCHNET0003E": _("Subnet %(subnet)s specified for network %(network)s is not valid."), + "KCHNET0004E": _("Specify a network interface to create bridged network %(name)s"), + "KCHNET0005E": _("Unable to delete active network %(name)s"), + "KCHNET0006E": _("Interface %(iface)s specified for network %(network)s is already in use"), + "KCHNET0007E": _("Interface should be bare nic, bonding or bridge device."), + "KCHNET0008E": _("Unable to create network %(name)s. Details: %(err)s"), + "KCHNET0009E": _("Unable to find a free IP address for network '%(name)s'"), + "KCHNET0010E": _("Unable to create VLAN tagged bridge using interface %(iface)s. Details: %(err)"), + "KCHNET0011E": _("Network name must be a string"), + "KCHNET0012E": _("Supported network types are isolated, nat and bridge"), + "KCHNET0013E": _("Network subnet must be a string with ip address and prefix or netmask"), + "KCHNET0014E": _("Network interface must be a string"), + "KCHNET0015E": _("Network VLAN ID must be an integer between 1 and 4094"), + "KCHNET0016E": _("Specify name and type to create a Network"), + + "KCHDR0001E": _("Debug report %(name)s does not exist"), + "KCHDR0002E": _("Debug report tool not found in system"), + "KCHDR0003E": _("Unable to create debug report %(name)s. Details: %(err)s."), + "KCHDR0004E": _("Can not find generated debug report named %(name)s"), + "KCHDR0005E": _("Unable to generate debug report %(name)s. Details: %(err)s"), + + "KCHSR0001E": _("Storage server %(server)s was not used by Kimchi"), + + "KCHDISTRO0001E": _("Distro '%(name)s' does not exist"), + + "KCHPART0001E": _("Partition %(name)s does not exist in the host"), + + "KCHHOST0001E": _("Unable to shutdown host machine as there are running virtual machines"), + "KCHHOST0002E": _("Unable to reboot host machine as there are running virtual machines"), + + "KCHOBJST0001E": _("Unable to find %(item)s in datastore"), + + "KCHUTILS0001E": _("Invalid URI %(uri)s"), + "KCHUTILS0002E": _("Timeout while running command '%(cmd)s' after %(seconds)s seconds"), + "KCHUTILS0003E": _("Unable to choose a virutal machine name"), }

On 02/11/2014 01:08 AM, Leonardo Augusto Guimarães Garcia wrote:
From: Aline Manera <alinefm@br.ibm.com>
src/kimchi/i18n.py and plugins/sample/i18n.py contain all messages used in backend to report error to the user
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/i18n.py | 15 +++++ src/kimchi/i18n.py | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+)
diff --git a/plugins/sample/i18n.py b/plugins/sample/i18n.py index 204460c..b4cd5cb 100644 --- a/plugins/sample/i18n.py +++ b/plugins/sample/i18n.py @@ -26,4 +26,19 @@ _ = gettext.gettext
messages = { + "SPAPI0001E": _("Unkown parameter specified %(value)s"), + "SPAPI0002E": _("The specified value %(value)s is not a positive number"), + + "SPCIRC0001E": _("Circle %(name)s already exists"), + "SPCIRC0002E": _("Circle %(name)s does not exist"), + "SPCIRC0003E": _("Specify name and radius to create a Circle"), + "SPCIRC0004E": _("Circle name must be a string"), + "SPCIRC0005E": _("Circle radius must be a positive number"), + + "SPRET0001E": _("Rectangle %(name)s already exists"), + "SPRET0002E": _("Rectangle %(name)s does not exist"), + "SPRET0003E": _("Specify name, length and width to create a Rectangle"), + "SPRET0004E": _("Rectangle name must be a string"), + "SPRET0005E": _("Rectangle length must be a positive number"), + "SPRET0006E": _("Rectangle width must be a positive number"), From where does these key values come? Are they just randomly chosen? Randomly or not, there should be a comment on how they were chosen in
On 02/09/2014 08:47 PM, Aline Manera wrote: the commit message.
I have explained about them on RFC. But of course, it needs to be in commit message. I will add it on V2.
Also, IIRC, I heard that we were using the English version of the message as the key instead of these crypt keys. Has this changed?
There are 2 different things - the code and the key. This file is built like: <code>: _(<key>) The key is an English text which represents the text to be translated and recognized by gettext. The code I am introducing now so we can identify the error message independent of the language used by the user. For example, an user running Kimchi in Japanese can report a bug with the errors messages he got and we can identify the error by the code as we probably don't know Japanese. The error message will be shown to the user like: <code>: <translated-message> For example: KCHASYNC0001E: Datastore is not initiated in the model object.
Best regards,
Leonardo Garcia
} diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 204460c..1a8fb5b 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -26,4 +26,148 @@ _ = gettext.gettext
messages = { + "KCHAPI0001E": _("Unkown parameter specified %(value)s"), + + "KCHASYNC0001E": _("Datastore is not initiated in the model object."), + + "KCHAUTH0001E": _("Authentication failed for user '%(userid)s'. [Error code: %(code)s]"), + + "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"), + "KCHDISKS0002E": _("Error while getting block device information for %(device)s."), + + "KCHDL0001E": _("Unable to find distro file: %(filename)s"), + "KCHDL0002E": _("Unable to parse distro file: %(filename)s.Make sure, it is a json file."), + + "KCHISCSI0001E": _("Unable to login to iSCSI host target %(portal)s. Details: %(err)s"), + "KCHISCSI0002E": _("Unable to login to iSCSI host %(host)s target %(target)s"), + + "KCHISO0001E": _("Unable to find ISO file ISO %(filename)s"), + "KCHISO0002E": _("The ISO file %(filename)s is not bootable"), + "KCHISO0003E": _("The ISO file %(filename)s does not have a valid El Torito boot record"), + "KCHISO0004E": _("Invalid El Torito validation entry in ISO %(filename)s"), + "KCHISO0005E": _("Invalid El Torito boot indicator in ISO %(filename)s"), + "KCHISO0006E": _("Unexpected volume type for primary volume in ISO %(filename)s"), + "KCHISO0007E": _("Bad format while reading volume descriptor in ISO %(filename)s"), + + "KCHVM0001E": _("Virtual machine $(name)s already exists"), + "KCHVM0002E": _("Virtual machine %(name)s does not exist"), + "KCHVM0003E": _("Unable to rename virtual machine %(name)s. The name %(new_name)s already exists or it is not powered off."), + "KCHVM0004E": _("Unable to retrieve screenshot for stopped virtual machine %(name)s"), + "KCHVM0005E": _("Remote ISO image is not supported by this server."), + "KCHVM0006E": _("Screenshot not supported for virtual machine %(name)s"), + "KCHVM0007E": _("Unable to create virtual machine %(name)s. Details: %(err)s"), + "KCHVM0008E": _("Unable to rename virtual machine %(name)s. Details: %(err)s"), + "KCHVM0009E": _("Unable to retrieve virtual machine %(name)s. Details: %(err)"), + "KCHVM0010E": _("Unable to connect to powered off machine %(name)s."), + "KCHVM0011E": _("Virtual machine name must be a string"), + "KCHVM0012E": _("Invalid template URI: %(value)s specified for virtual machine"), + "KCHVM0013E": _("Invalid storage pool URI: %(value)s specified for virtual machine"), + "KCHVM0014E": _("Supported virtual machine graphics are spice or vnc"), + "KCHVM0015E": _("Graphics address to listen on must be IPv4 or IPv6"), + "KCHVM0016E": _("Specify a template to create a Virtual Machine from"), + + "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), + "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), + "KCHVMIF0003E": _("Do not support guest interface hot plug attachment"), + "KCHVMIF0004E": _("Supported virtual machine interfaces type is only network"), + "KCHVMIF0005E": _("Network name for virtual machine interface must be a string"), + "KCHVMIF0006E": _("Invalid network model card specified for virtual machine interface"), + "KCHVMIF0007E": _("Specify type and network to add a new virtual machine interface"), + + "KCHTMPL0001E": _("Template %(name)s already exists"), + "KCHTMPL0002E": _("Template %(name)s does not exist"), + "KCHTMPL0003E": _("Network '%(network)s' specified for template %(template)s does not exist"), + "KCHTMPL0004E": _("Storage Pool %(pool)s specified for template %(template)s does not exist"), + "KCHTMPL0005E": _("Storage Pool %(pool)s specified for template %(template)s is not active"), + "KCHTMPL0006E": _("Invalid parameter '%(param)s' specified for cdrom."), + "KCHTMPL0007E": _("Network %(network)s specified for template %(template)s is not active"), + "KCHTMPL0008E": _("Template name must be a string"), + "KCHTMPL0009E": _("Template icon must be a path to the image"), + "KCHTMPL0010E": _("Template distribution must be a string"), + "KCHTMPL0011E": _("Template distribution version must be a string"), + "KCHTMPL0012E": _("The number of CPUs must be a integer"), + "KCHTMPL0013E": _("Amount of memory (MB) must be an integer greater than 512"), + "KCHTMPL0014E": _("Template CDROM must be a local or remote ISO file"), + "KCHTMPL0015E": _("Invalid storage pool URI %(value)s specified for Template"), + "KCHTMPL0016E": _("Specify an ISO image as CDROM to create a Template"), + "KCHTMPL0017E": _("All networks for the Template must be specified in a list."), + + "KCHPOOL0001E": _("Storage Pool %(name)s already exists"), + "KCHPOOL0002E": _("Storage Pool %(name)s does not exist"), + "KCHPOOL0003E": _("Autostart flag must be true or false"), + "KCHPOOL0004E": _("Specify %(item)s in order to create the Storage Pool %(name)s"), + "KCHPOOL0005E": _("Unable to delete active Storage Pool %(name)s"), + "KCHPOOL0006E": _("Unable to list Storage Pools. Details: %(err)s"), + "KCHPOOL0007E": _("Unable to create Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0008E": _("Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0009E": _("Unable to activate Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0010E": _("Unable to deactivate Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0011E": _("Unable to delete Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0012E": _("Unable to create NFS Pool as export path %(path)s may block during mount"), + "KCHPOOL0013E": _("Unable to create NFS Pool as export path %(path)s mount failed"), + "KCHPOOL0014E": _("Unsupported Storage Pool type: %(type)s"), + "KCHPOOL0015E": _("Error while getting xml for Storage Pool %(pool)s"), + "KCHPOOL0016E": _("Storage Pool name must be a string"), + "KCHPOOL0017E": _("Supported Storage Pool types are dir, netfs, logical and kimchi-iso"), + "KCHPOOL0018E": _("Storage Pool path must be a string"), + "KCHPOOL0019E": _("Storage Pool host must be a IP or hostname"), + "KCHPOOL0020E": _("Storage Pool devices must be the full path to the block device"), + "KCHPOOL0021E": _("Storage Pool devices parameter must be a list"), + "KCHPOOL0022E": _("Target IQN of an iSCSI pool must be a string"), + "KCHPOOL0023E": _("Port of a remote storage server must be an integer between 1 and 65535"), + "KCHPOOL0024E": _("Login username of the iSCSI target must be a string"), + "KCHPOOL0025E": _("Login password of the iSCSI target must be a string"), + "KCHPOOL0026E": _("Specify name and type to create a Storage Pool"), + + "KCHVOL0001E": _("Storage Volume %(name)s already exists"), + "KCHVOL0002E": _("Storage Volume %(name)s does not exist in Storage Pool %(pool)s"), + "KCHVOL0003E": _("Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is not active"), + "KCHVOL0004E": _("Specify %(item)s in order to create Storage Volume %(volume)s"), + "KCHVOL0005E": _("Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s is not active"), + "KCHVOL0006E": _("Unable to list Storage Volumes because Storage Pool %(pool)s is not active"), + "KCHVOL0007E": _("Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: %(err)s"), + "KCHVOL0008E": _("Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s"), + "KCHVOL0009E": _("Unable to wipe Storage Volumes %(name)s. Details: %(err)s"), + "KCHVOL0010E": _("Unable to delete Storage Volume %(name)s. Details: %(err)s"), + "KCHVOL0011E": _("Unable to resize Storage Volume %(name)s. Details: %(err)s"), + + "KCHIFACE0001E": _("Interface %(name)s does not exist"), + + "KCHNET0001E": _("Network %(name)s already exists"), + "KCHNET0002E": _("Network %(name)s does not exist"), + "KCHNET0003E": _("Subnet %(subnet)s specified for network %(network)s is not valid."), + "KCHNET0004E": _("Specify a network interface to create bridged network %(name)s"), + "KCHNET0005E": _("Unable to delete active network %(name)s"), + "KCHNET0006E": _("Interface %(iface)s specified for network %(network)s is already in use"), + "KCHNET0007E": _("Interface should be bare nic, bonding or bridge device."), + "KCHNET0008E": _("Unable to create network %(name)s. Details: %(err)s"), + "KCHNET0009E": _("Unable to find a free IP address for network '%(name)s'"), + "KCHNET0010E": _("Unable to create VLAN tagged bridge using interface %(iface)s. Details: %(err)"), + "KCHNET0011E": _("Network name must be a string"), + "KCHNET0012E": _("Supported network types are isolated, nat and bridge"), + "KCHNET0013E": _("Network subnet must be a string with ip address and prefix or netmask"), + "KCHNET0014E": _("Network interface must be a string"), + "KCHNET0015E": _("Network VLAN ID must be an integer between 1 and 4094"), + "KCHNET0016E": _("Specify name and type to create a Network"), + + "KCHDR0001E": _("Debug report %(name)s does not exist"), + "KCHDR0002E": _("Debug report tool not found in system"), + "KCHDR0003E": _("Unable to create debug report %(name)s. Details: %(err)s."), + "KCHDR0004E": _("Can not find generated debug report named %(name)s"), + "KCHDR0005E": _("Unable to generate debug report %(name)s. Details: %(err)s"), + + "KCHSR0001E": _("Storage server %(server)s was not used by Kimchi"), + + "KCHDISTRO0001E": _("Distro '%(name)s' does not exist"), + + "KCHPART0001E": _("Partition %(name)s does not exist in the host"), + + "KCHHOST0001E": _("Unable to shutdown host machine as there are running virtual machines"), + "KCHHOST0002E": _("Unable to reboot host machine as there are running virtual machines"), + + "KCHOBJST0001E": _("Unable to find %(item)s in datastore"), + + "KCHUTILS0001E": _("Invalid URI %(uri)s"), + "KCHUTILS0002E": _("Timeout while running command '%(cmd)s' after %(seconds)s seconds"), + "KCHUTILS0003E": _("Unable to choose a virutal machine name"), }

On 02/11/2014 10:14 AM, Aline Manera wrote:
On 02/11/2014 01:08 AM, Leonardo Augusto Guimarães Garcia wrote:
From: Aline Manera <alinefm@br.ibm.com>
src/kimchi/i18n.py and plugins/sample/i18n.py contain all messages used in backend to report error to the user
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/i18n.py | 15 +++++ src/kimchi/i18n.py | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+)
diff --git a/plugins/sample/i18n.py b/plugins/sample/i18n.py index 204460c..b4cd5cb 100644 --- a/plugins/sample/i18n.py +++ b/plugins/sample/i18n.py @@ -26,4 +26,19 @@ _ = gettext.gettext
messages = { + "SPAPI0001E": _("Unkown parameter specified %(value)s"), + "SPAPI0002E": _("The specified value %(value)s is not a positive number"), + + "SPCIRC0001E": _("Circle %(name)s already exists"), + "SPCIRC0002E": _("Circle %(name)s does not exist"), + "SPCIRC0003E": _("Specify name and radius to create a Circle"), + "SPCIRC0004E": _("Circle name must be a string"), + "SPCIRC0005E": _("Circle radius must be a positive number"), + + "SPRET0001E": _("Rectangle %(name)s already exists"), + "SPRET0002E": _("Rectangle %(name)s does not exist"), + "SPRET0003E": _("Specify name, length and width to create a Rectangle"), + "SPRET0004E": _("Rectangle name must be a string"), + "SPRET0005E": _("Rectangle length must be a positive number"), + "SPRET0006E": _("Rectangle width must be a positive number"), From where does these key values come? Are they just randomly chosen? Randomly or not, there should be a comment on how they were chosen in
On 02/09/2014 08:47 PM, Aline Manera wrote: the commit message.
I have explained about them on RFC. But of course, it needs to be in commit message. I will add it on V2.
Also, IIRC, I heard that we were using the English version of the message as the key instead of these crypt keys. Has this changed?
There are 2 different things - the code and the key.
This file is built like: <code>: _(<key>)
The key is an English text which represents the text to be translated and recognized by gettext.
The code I am introducing now so we can identify the error message independent of the language used by the user. For example, an user running Kimchi in Japanese can report a bug with the errors messages he got and we can identify the error by the code as we probably don't know Japanese.
The error message will be shown to the user like: <code>: <translated-message>
For example: KCHASYNC0001E: Datastore is not initiated in the model object. Ok, understood, thanks. I think this needs to be in the commit message as well.
Best regards, Leonardo Garcia
Best regards,
Leonardo Garcia
} diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 204460c..1a8fb5b 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -26,4 +26,148 @@ _ = gettext.gettext
messages = { + "KCHAPI0001E": _("Unkown parameter specified %(value)s"), + + "KCHASYNC0001E": _("Datastore is not initiated in the model object."), + + "KCHAUTH0001E": _("Authentication failed for user '%(userid)s'. [Error code: %(code)s]"), + + "KCHDISKS0001E": _("Error while getting block devices. Details: %(err)s"), + "KCHDISKS0002E": _("Error while getting block device information for %(device)s."), + + "KCHDL0001E": _("Unable to find distro file: %(filename)s"), + "KCHDL0002E": _("Unable to parse distro file: %(filename)s.Make sure, it is a json file."), + + "KCHISCSI0001E": _("Unable to login to iSCSI host target %(portal)s. Details: %(err)s"), + "KCHISCSI0002E": _("Unable to login to iSCSI host %(host)s target %(target)s"), + + "KCHISO0001E": _("Unable to find ISO file ISO %(filename)s"), + "KCHISO0002E": _("The ISO file %(filename)s is not bootable"), + "KCHISO0003E": _("The ISO file %(filename)s does not have a valid El Torito boot record"), + "KCHISO0004E": _("Invalid El Torito validation entry in ISO %(filename)s"), + "KCHISO0005E": _("Invalid El Torito boot indicator in ISO %(filename)s"), + "KCHISO0006E": _("Unexpected volume type for primary volume in ISO %(filename)s"), + "KCHISO0007E": _("Bad format while reading volume descriptor in ISO %(filename)s"), + + "KCHVM0001E": _("Virtual machine $(name)s already exists"), + "KCHVM0002E": _("Virtual machine %(name)s does not exist"), + "KCHVM0003E": _("Unable to rename virtual machine %(name)s. The name %(new_name)s already exists or it is not powered off."), + "KCHVM0004E": _("Unable to retrieve screenshot for stopped virtual machine %(name)s"), + "KCHVM0005E": _("Remote ISO image is not supported by this server."), + "KCHVM0006E": _("Screenshot not supported for virtual machine %(name)s"), + "KCHVM0007E": _("Unable to create virtual machine %(name)s. Details: %(err)s"), + "KCHVM0008E": _("Unable to rename virtual machine %(name)s. Details: %(err)s"), + "KCHVM0009E": _("Unable to retrieve virtual machine %(name)s. Details: %(err)"), + "KCHVM0010E": _("Unable to connect to powered off machine %(name)s."), + "KCHVM0011E": _("Virtual machine name must be a string"), + "KCHVM0012E": _("Invalid template URI: %(value)s specified for virtual machine"), + "KCHVM0013E": _("Invalid storage pool URI: %(value)s specified for virtual machine"), + "KCHVM0014E": _("Supported virtual machine graphics are spice or vnc"), + "KCHVM0015E": _("Graphics address to listen on must be IPv4 or IPv6"), + "KCHVM0016E": _("Specify a template to create a Virtual Machine from"), + + "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"), + "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"), + "KCHVMIF0003E": _("Do not support guest interface hot plug attachment"), + "KCHVMIF0004E": _("Supported virtual machine interfaces type is only network"), + "KCHVMIF0005E": _("Network name for virtual machine interface must be a string"), + "KCHVMIF0006E": _("Invalid network model card specified for virtual machine interface"), + "KCHVMIF0007E": _("Specify type and network to add a new virtual machine interface"), + + "KCHTMPL0001E": _("Template %(name)s already exists"), + "KCHTMPL0002E": _("Template %(name)s does not exist"), + "KCHTMPL0003E": _("Network '%(network)s' specified for template %(template)s does not exist"), + "KCHTMPL0004E": _("Storage Pool %(pool)s specified for template %(template)s does not exist"), + "KCHTMPL0005E": _("Storage Pool %(pool)s specified for template %(template)s is not active"), + "KCHTMPL0006E": _("Invalid parameter '%(param)s' specified for cdrom."), + "KCHTMPL0007E": _("Network %(network)s specified for template %(template)s is not active"), + "KCHTMPL0008E": _("Template name must be a string"), + "KCHTMPL0009E": _("Template icon must be a path to the image"), + "KCHTMPL0010E": _("Template distribution must be a string"), + "KCHTMPL0011E": _("Template distribution version must be a string"), + "KCHTMPL0012E": _("The number of CPUs must be a integer"), + "KCHTMPL0013E": _("Amount of memory (MB) must be an integer greater than 512"), + "KCHTMPL0014E": _("Template CDROM must be a local or remote ISO file"), + "KCHTMPL0015E": _("Invalid storage pool URI %(value)s specified for Template"), + "KCHTMPL0016E": _("Specify an ISO image as CDROM to create a Template"), + "KCHTMPL0017E": _("All networks for the Template must be specified in a list."), + + "KCHPOOL0001E": _("Storage Pool %(name)s already exists"), + "KCHPOOL0002E": _("Storage Pool %(name)s does not exist"), + "KCHPOOL0003E": _("Autostart flag must be true or false"), + "KCHPOOL0004E": _("Specify %(item)s in order to create the Storage Pool %(name)s"), + "KCHPOOL0005E": _("Unable to delete active Storage Pool %(name)s"), + "KCHPOOL0006E": _("Unable to list Storage Pools. Details: %(err)s"), + "KCHPOOL0007E": _("Unable to create Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0008E": _("Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0009E": _("Unable to activate Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0010E": _("Unable to deactivate Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0011E": _("Unable to delete Storage Pool %(name)s. Details: %(err)s"), + "KCHPOOL0012E": _("Unable to create NFS Pool as export path %(path)s may block during mount"), + "KCHPOOL0013E": _("Unable to create NFS Pool as export path %(path)s mount failed"), + "KCHPOOL0014E": _("Unsupported Storage Pool type: %(type)s"), + "KCHPOOL0015E": _("Error while getting xml for Storage Pool %(pool)s"), + "KCHPOOL0016E": _("Storage Pool name must be a string"), + "KCHPOOL0017E": _("Supported Storage Pool types are dir, netfs, logical and kimchi-iso"), + "KCHPOOL0018E": _("Storage Pool path must be a string"), + "KCHPOOL0019E": _("Storage Pool host must be a IP or hostname"), + "KCHPOOL0020E": _("Storage Pool devices must be the full path to the block device"), + "KCHPOOL0021E": _("Storage Pool devices parameter must be a list"), + "KCHPOOL0022E": _("Target IQN of an iSCSI pool must be a string"), + "KCHPOOL0023E": _("Port of a remote storage server must be an integer between 1 and 65535"), + "KCHPOOL0024E": _("Login username of the iSCSI target must be a string"), + "KCHPOOL0025E": _("Login password of the iSCSI target must be a string"), + "KCHPOOL0026E": _("Specify name and type to create a Storage Pool"), + + "KCHVOL0001E": _("Storage Volume %(name)s already exists"), + "KCHVOL0002E": _("Storage Volume %(name)s does not exist in Storage Pool %(pool)s"), + "KCHVOL0003E": _("Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is not active"), + "KCHVOL0004E": _("Specify %(item)s in order to create Storage Volume %(volume)s"), + "KCHVOL0005E": _("Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s is not active"), + "KCHVOL0006E": _("Unable to list Storage Volumes because Storage Pool %(pool)s is not active"), + "KCHVOL0007E": _("Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: %(err)s"), + "KCHVOL0008E": _("Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s"), + "KCHVOL0009E": _("Unable to wipe Storage Volumes %(name)s. Details: %(err)s"), + "KCHVOL0010E": _("Unable to delete Storage Volume %(name)s. Details: %(err)s"), + "KCHVOL0011E": _("Unable to resize Storage Volume %(name)s. Details: %(err)s"), + + "KCHIFACE0001E": _("Interface %(name)s does not exist"), + + "KCHNET0001E": _("Network %(name)s already exists"), + "KCHNET0002E": _("Network %(name)s does not exist"), + "KCHNET0003E": _("Subnet %(subnet)s specified for network %(network)s is not valid."), + "KCHNET0004E": _("Specify a network interface to create bridged network %(name)s"), + "KCHNET0005E": _("Unable to delete active network %(name)s"), + "KCHNET0006E": _("Interface %(iface)s specified for network %(network)s is already in use"), + "KCHNET0007E": _("Interface should be bare nic, bonding or bridge device."), + "KCHNET0008E": _("Unable to create network %(name)s. Details: %(err)s"), + "KCHNET0009E": _("Unable to find a free IP address for network '%(name)s'"), + "KCHNET0010E": _("Unable to create VLAN tagged bridge using interface %(iface)s. Details: %(err)"), + "KCHNET0011E": _("Network name must be a string"), + "KCHNET0012E": _("Supported network types are isolated, nat and bridge"), + "KCHNET0013E": _("Network subnet must be a string with ip address and prefix or netmask"), + "KCHNET0014E": _("Network interface must be a string"), + "KCHNET0015E": _("Network VLAN ID must be an integer between 1 and 4094"), + "KCHNET0016E": _("Specify name and type to create a Network"), + + "KCHDR0001E": _("Debug report %(name)s does not exist"), + "KCHDR0002E": _("Debug report tool not found in system"), + "KCHDR0003E": _("Unable to create debug report %(name)s. Details: %(err)s."), + "KCHDR0004E": _("Can not find generated debug report named %(name)s"), + "KCHDR0005E": _("Unable to generate debug report %(name)s. Details: %(err)s"), + + "KCHSR0001E": _("Storage server %(server)s was not used by Kimchi"), + + "KCHDISTRO0001E": _("Distro '%(name)s' does not exist"), + + "KCHPART0001E": _("Partition %(name)s does not exist in the host"), + + "KCHHOST0001E": _("Unable to shutdown host machine as there are running virtual machines"), + "KCHHOST0002E": _("Unable to reboot host machine as there are running virtual machines"), + + "KCHOBJST0001E": _("Unable to find %(item)s in datastore"), + + "KCHUTILS0001E": _("Invalid URI %(uri)s"), + "KCHUTILS0002E": _("Timeout while running command '%(cmd)s' after %(seconds)s seconds"), + "KCHUTILS0003E": _("Unable to choose a virutal machine name"), }

From: Aline Manera <alinefm@br.ibm.com> While validating data with jsonschema it raises English messages. To allow translate all error messages to the supported languages it is needed to set a custom error message. In this case, the message code is being used. Then KimchiException can get the correct message based on code and display the translated message. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/API.json | 23 +++++--- src/kimchi/API.json | 144 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 115 insertions(+), 52 deletions(-) diff --git a/plugins/sample/API.json b/plugins/sample/API.json index 58d0969..ebc596b 100644 --- a/plugins/sample/API.json +++ b/plugins/sample/API.json @@ -3,42 +3,51 @@ "title": "Plugin Sample API", "description": "Json schema for Kimchi's Sample Plugin API", "type": "object", + "error": "SPAPI0001E", "properties": { "rectangles_create": { "type": "object", + "error": "SPRET0003E", "properties": { "name": { "description": "The name of the new rectangle instance", "type": "string", - "required": true + "required": true, + "error": "SPRET0004E" }, "length": { "$ref": "#/definitions/positiveNumber", - "required": true + "required": true, + "error": "SPRET0005E" }, "width": { "$ref": "#/definitions/positiveNumber", - "required": true + "required": true, + "error": "SPRET0006E" } } - } - }, + }, "circles_create": { "type": "object", + "error": "SPCIRC0003E", "properties": { "name": { "description": "The name of the new circle instance", "type": "string", - "required": true + "required": true, + "error": "SPCIRC0004E" }, "radius": { "$ref": "#/definitions/positiveNumber", - "required": true + "required": true, + "error": "SPCIRC0005E" } } + } }, "definitions": { "positiveNumber": { + "error": "SPAPI0002E", "type": "number", "minimum": 0, "exclusiveMinimum": true diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 08c77c5..38c4d9f 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -8,8 +8,12 @@ "description": "Configure graphics parameters for the new VM", "type": "object", "properties": { - "type": { "enum": ["spice", "vnc"] }, + "type": { + "enum": ["spice", "vnc"], + "error": "KCHVM0014E" + }, "listen": { + "error": "KCHVM0015E", "type": [ { "type": "string", @@ -27,22 +31,26 @@ "properties": { "storagepools_create": { "type": "object", + "error": "KCHPOOL0026E", "properties": { "name": { "description": "The name of the Storage Pool", "type": "string", "minLength": 1, - "required": true + "required": true, + "error": "KCHPOOL0016E" }, "type": { "description": "The type of the defined Storage Pool", "type": "string", "pattern": "^dir|netfs|logical|kimchi-iso$", - "required": true + "required": true, + "error": "KCHPOOL0017E" }, "path": { "description": "The path of the defined Storage Pool", - "type": "string" + "type": "string", + "error": "KCHPOOL0018E" }, "source": { "description": "Dictionary containing source information of the pool", @@ -50,31 +58,37 @@ "properties": { "host": { "description": "IP or hostname of server for a pool backed from a remote host", - "type": "string" + "type": "string", + "error": "KCHPOOL0019E" }, "path": { "description": "Export path on NFS server for NFS pool", - "type": "string" + "type": "string", + "error": "KCHPOOL0018E" }, "devices": { "description": "Array of devices to be used in the Storage Pool", "type": "array", "minItems": 1, "uniqueItems": true, + "error": "KCHPOOL0021E", "items": { "description": "Full path of the block device node", - "type": "string" + "type": "string", + "error": "KCHPOOL0020E" } }, "target": { "description": "Target IQN of an iSCSI pool", - "type": "string" + "type": "string", + "error": "KCHPOOL0022E" }, "port": { "description": "Listening port of a remote storage server", "type": "integer", "minimum": 1, - "maximum": 65535 + "maximum": 65535, + "error": "KCHPOOL0023E" }, "auth": { "description": "Storage back-end authentication information", @@ -82,11 +96,13 @@ "properties": { "username": { "description": "Login username of the iSCSI target", - "type": "string" + "type": "string", + "error": "KCHPOOL0024E" }, "password": { "description": "Login password of the iSCSI target", - "type": "string" + "type": "string", + "error": "KCHPOOL0025E" } } } @@ -96,21 +112,25 @@ }, "vms_create": { "type": "object", + "error": "KCHVM0016E", "properties": { "name": { "description": "The name of the new VM", - "type": "string" + "type": "string", + "error": "KCHVM0011E" }, "template": { "description": "The URI of a template to use when building a VM", "type": "string", "pattern": "^/templates/[^/]+/?$", - "required": true + "required": true, + "error": "KCHVM0012E" }, "storagepool": { "description": "Assign a specefic Storage Pool to the new VM", "type": "string", - "pattern": "^/storagepools/[^/]+/?$" + "pattern": "^/storagepools/[^/]+/?$", + "error": "KCHVM0013E" }, "graphics": { "$ref": "#/kimchitype/graphics" } } @@ -121,101 +141,120 @@ "name": { "description": "New name of VM", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHVM0011E" } } }, "networks_create": { "type": "object", + "error": "KCHNET0016E", "properties": { "name": { "description": "The name of the new network", "type": "string", "minLength": 1, - "required": true + "required": true, + "error": "KCHNET0011E" }, "connection": { "description": "Specifies how this network should be connected to the other networks", "type": "string", "pattern": "^isolated|nat|bridge$", - "required": true + "required": true, + "error": "KCHNET0012E" }, "subnet": { "description": "Network segment in slash-separated format with ip address and prefix or netmask", - "type": "string" + "type": "string", + "error": "KCHNET0013E" }, "interface": { "description": "The name of a network interface on the host", - "type": "string" + "type": "string", + "error": "KCHNET0014E" }, "vlan_id": { "description": "Network's VLAN ID", "type": "integer", "maximum": 4094, - "minimum": 1 + "minimum": 1, + "error": "KCHNET0015E" } } }, "vmifaces_create": { "type": "object", + "error": "KCHVMIF0007E", "properties": { "type": { "description": "The type of VM network interface that libvirt supports", "type": "string", "pattern": "^network$", - "required": true + "required": true, + "error": "KCHVMIF0004E" }, "network": { "description": "the name of one available network", "minLength": 1, - "type": "string" + "type": "string", + "error": "KCHVMIF0005E" }, "model": { "description": "model of emulated network interface card", "type": "string", - "pattern": "^ne2k_pci|i82551|i82557b|i82559er|rtl8139|e1000|pcnet|virtio$" + "pattern": "^ne2k_pci|i82551|i82557b|i82559er|rtl8139|e1000|pcnet|virtio$", + "error": "KCHVMIF0006E" } } }, "templates_create": { "type": "object", + "error": "KCHTMPL0016E", "properties": { "name": { "description": "The name of the template", "type": "string", "pattern": "^[^ ]+( +[^ ]+)*$", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0008E" }, "icon": { "description": "The template icon path", "type": "string", - "pattern": "^images/" + "pattern": "^images/", + "error": "KCHTMPL0009E" }, "os_distro": { "description": "Distribution name of the Operating System", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0010E" }, "os_version": { "description": "Version of the Operating System", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0011E" }, "cpus": { "description": "Number of CPUs for the template", "type": "integer", - "minimum": 1 + "minimum": 1, + "error": "KCHTMPL0012E" }, "memory": { "description": "Memory (MB) for the template", "type": "integer", - "minimum": 512 + "minimum": 512, + "error": "KCHTMPL0013E" }, "cdrom": { "description": "Path for cdrom", "type": "string", "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$", - "required": true + "required": true, + "error": "KCHTMPL0014E" }, "disks": { "description": "List of disks", @@ -241,13 +280,15 @@ "storagepool": { "description": "Location of the storage pool", "type": "string", - "pattern": "^/storagepools/[^/]+/?$" + "pattern": "^/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" }, "networks": { "description": "list of which networks will be assigned to the new VM.", "type": "array", "items": { "type": "string" }, - "uniqueItems": true + "uniqueItems": true, + "error": "KCHTMPL0017E" }, "folder": { "description": "Folder", @@ -256,7 +297,8 @@ }, "graphics": { "$ref": "#/kimchitype/graphics" } }, - "additionalProperties": false + "additionalProperties": false, + "error": "KCHAPI0001E" }, "storageservers_get_list": { "type": "object", @@ -267,7 +309,8 @@ "pattern": "^netfs$" } }, - "additionalProperties": false + "additionalProperties": false, + "error": "KCHAPI0001E" }, "storagetargets_get_list": { "type": "object", @@ -278,7 +321,8 @@ "pattern": "^netfs$" } }, - "additionalProperties": false + "additionalProperties": false, + "error": "KCHAPI0001E" }, "template_update": { "type": "object", @@ -287,37 +331,44 @@ "description": "The name of the template", "type": "string", "pattern": "^[^ ]+( +[^ ]+)*$", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0008E" }, "icon": { "description": "The template icon path", "type": "string", - "pattern": "^images/" + "pattern": "^images/", + "error": "KCHTMPL0009E" }, "os_distro": { "description": "Distribution name of the Operating System", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0010E" }, "os_version": { "description": "Version of the Operating System", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0011E" }, "cpus": { "description": "Number of CPUs for the template", "type": "integer", - "minimum": 1 + "minimum": 1, + "error": "KCHTMPL0012E" }, "memory": { "description": "Memory (MB) for the template", "type": "integer", - "minimum": 512 + "minimum": 512, + "error": "KCHTMPL0013E" }, "cdrom": { "description": "Path for cdrom", "type": "string", - "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$" + "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$", + "error": "KCHTMPL0014E" }, "disks": { "description": "List of disks", @@ -343,13 +394,15 @@ "storagepool": { "description": "Location of the storage pool", "type": "string", - "pattern": "^/storagepools/[^/]+/?$" + "pattern": "^/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" }, "networks": { "description": "list of which networks will be assigned to the new VM.", "type": "array", "items": { "type": "string" }, - "uniqueItems": true + "uniqueItems": true, + "error": "KCHTMPL0017E" }, "folder": { "description": "Folder", @@ -358,7 +411,8 @@ }, "graphics": { "$ref": "#/kimchitype/graphics" } }, - "additionalProperties": false + "additionalProperties": false, + "error": "KCHAPI0001E" } } } -- 1.7.10.4

Reviewed-by: Leonardo Garcia <lagarcia@br.ibm.com> On 02/09/2014 08:47 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
While validating data with jsonschema it raises English messages. To allow translate all error messages to the supported languages it is needed to set a custom error message. In this case, the message code is being used. Then KimchiException can get the correct message based on code and display the translated message.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/API.json | 23 +++++--- src/kimchi/API.json | 144 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 115 insertions(+), 52 deletions(-)
diff --git a/plugins/sample/API.json b/plugins/sample/API.json index 58d0969..ebc596b 100644 --- a/plugins/sample/API.json +++ b/plugins/sample/API.json @@ -3,42 +3,51 @@ "title": "Plugin Sample API", "description": "Json schema for Kimchi's Sample Plugin API", "type": "object", + "error": "SPAPI0001E", "properties": { "rectangles_create": { "type": "object", + "error": "SPRET0003E", "properties": { "name": { "description": "The name of the new rectangle instance", "type": "string", - "required": true + "required": true, + "error": "SPRET0004E" }, "length": { "$ref": "#/definitions/positiveNumber", - "required": true + "required": true, + "error": "SPRET0005E" }, "width": { "$ref": "#/definitions/positiveNumber", - "required": true + "required": true, + "error": "SPRET0006E" } } - } - }, + }, "circles_create": { "type": "object", + "error": "SPCIRC0003E", "properties": { "name": { "description": "The name of the new circle instance", "type": "string", - "required": true + "required": true, + "error": "SPCIRC0004E" }, "radius": { "$ref": "#/definitions/positiveNumber", - "required": true + "required": true, + "error": "SPCIRC0005E" } } + } }, "definitions": { "positiveNumber": { + "error": "SPAPI0002E", "type": "number", "minimum": 0, "exclusiveMinimum": true diff --git a/src/kimchi/API.json b/src/kimchi/API.json index 08c77c5..38c4d9f 100644 --- a/src/kimchi/API.json +++ b/src/kimchi/API.json @@ -8,8 +8,12 @@ "description": "Configure graphics parameters for the new VM", "type": "object", "properties": { - "type": { "enum": ["spice", "vnc"] }, + "type": { + "enum": ["spice", "vnc"], + "error": "KCHVM0014E" + }, "listen": { + "error": "KCHVM0015E", "type": [ { "type": "string", @@ -27,22 +31,26 @@ "properties": { "storagepools_create": { "type": "object", + "error": "KCHPOOL0026E", "properties": { "name": { "description": "The name of the Storage Pool", "type": "string", "minLength": 1, - "required": true + "required": true, + "error": "KCHPOOL0016E" }, "type": { "description": "The type of the defined Storage Pool", "type": "string", "pattern": "^dir|netfs|logical|kimchi-iso$", - "required": true + "required": true, + "error": "KCHPOOL0017E" }, "path": { "description": "The path of the defined Storage Pool", - "type": "string" + "type": "string", + "error": "KCHPOOL0018E" }, "source": { "description": "Dictionary containing source information of the pool", @@ -50,31 +58,37 @@ "properties": { "host": { "description": "IP or hostname of server for a pool backed from a remote host", - "type": "string" + "type": "string", + "error": "KCHPOOL0019E" }, "path": { "description": "Export path on NFS server for NFS pool", - "type": "string" + "type": "string", + "error": "KCHPOOL0018E" }, "devices": { "description": "Array of devices to be used in the Storage Pool", "type": "array", "minItems": 1, "uniqueItems": true, + "error": "KCHPOOL0021E", "items": { "description": "Full path of the block device node", - "type": "string" + "type": "string", + "error": "KCHPOOL0020E" } }, "target": { "description": "Target IQN of an iSCSI pool", - "type": "string" + "type": "string", + "error": "KCHPOOL0022E" }, "port": { "description": "Listening port of a remote storage server", "type": "integer", "minimum": 1, - "maximum": 65535 + "maximum": 65535, + "error": "KCHPOOL0023E" }, "auth": { "description": "Storage back-end authentication information", @@ -82,11 +96,13 @@ "properties": { "username": { "description": "Login username of the iSCSI target", - "type": "string" + "type": "string", + "error": "KCHPOOL0024E" }, "password": { "description": "Login password of the iSCSI target", - "type": "string" + "type": "string", + "error": "KCHPOOL0025E" } } } @@ -96,21 +112,25 @@ }, "vms_create": { "type": "object", + "error": "KCHVM0016E", "properties": { "name": { "description": "The name of the new VM", - "type": "string" + "type": "string", + "error": "KCHVM0011E" }, "template": { "description": "The URI of a template to use when building a VM", "type": "string", "pattern": "^/templates/[^/]+/?$", - "required": true + "required": true, + "error": "KCHVM0012E" }, "storagepool": { "description": "Assign a specefic Storage Pool to the new VM", "type": "string", - "pattern": "^/storagepools/[^/]+/?$" + "pattern": "^/storagepools/[^/]+/?$", + "error": "KCHVM0013E" }, "graphics": { "$ref": "#/kimchitype/graphics" } } @@ -121,101 +141,120 @@ "name": { "description": "New name of VM", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHVM0011E" } } }, "networks_create": { "type": "object", + "error": "KCHNET0016E", "properties": { "name": { "description": "The name of the new network", "type": "string", "minLength": 1, - "required": true + "required": true, + "error": "KCHNET0011E" }, "connection": { "description": "Specifies how this network should be connected to the other networks", "type": "string", "pattern": "^isolated|nat|bridge$", - "required": true + "required": true, + "error": "KCHNET0012E" }, "subnet": { "description": "Network segment in slash-separated format with ip address and prefix or netmask", - "type": "string" + "type": "string", + "error": "KCHNET0013E" }, "interface": { "description": "The name of a network interface on the host", - "type": "string" + "type": "string", + "error": "KCHNET0014E" }, "vlan_id": { "description": "Network's VLAN ID", "type": "integer", "maximum": 4094, - "minimum": 1 + "minimum": 1, + "error": "KCHNET0015E" } } }, "vmifaces_create": { "type": "object", + "error": "KCHVMIF0007E", "properties": { "type": { "description": "The type of VM network interface that libvirt supports", "type": "string", "pattern": "^network$", - "required": true + "required": true, + "error": "KCHVMIF0004E" }, "network": { "description": "the name of one available network", "minLength": 1, - "type": "string" + "type": "string", + "error": "KCHVMIF0005E" }, "model": { "description": "model of emulated network interface card", "type": "string", - "pattern": "^ne2k_pci|i82551|i82557b|i82559er|rtl8139|e1000|pcnet|virtio$" + "pattern": "^ne2k_pci|i82551|i82557b|i82559er|rtl8139|e1000|pcnet|virtio$", + "error": "KCHVMIF0006E" } } }, "templates_create": { "type": "object", + "error": "KCHTMPL0016E", "properties": { "name": { "description": "The name of the template", "type": "string", "pattern": "^[^ ]+( +[^ ]+)*$", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0008E" }, "icon": { "description": "The template icon path", "type": "string", - "pattern": "^images/" + "pattern": "^images/", + "error": "KCHTMPL0009E" }, "os_distro": { "description": "Distribution name of the Operating System", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0010E" }, "os_version": { "description": "Version of the Operating System", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0011E" }, "cpus": { "description": "Number of CPUs for the template", "type": "integer", - "minimum": 1 + "minimum": 1, + "error": "KCHTMPL0012E" }, "memory": { "description": "Memory (MB) for the template", "type": "integer", - "minimum": 512 + "minimum": 512, + "error": "KCHTMPL0013E" }, "cdrom": { "description": "Path for cdrom", "type": "string", "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$", - "required": true + "required": true, + "error": "KCHTMPL0014E" }, "disks": { "description": "List of disks", @@ -241,13 +280,15 @@ "storagepool": { "description": "Location of the storage pool", "type": "string", - "pattern": "^/storagepools/[^/]+/?$" + "pattern": "^/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" }, "networks": { "description": "list of which networks will be assigned to the new VM.", "type": "array", "items": { "type": "string" }, - "uniqueItems": true + "uniqueItems": true, + "error": "KCHTMPL0017E" }, "folder": { "description": "Folder", @@ -256,7 +297,8 @@ }, "graphics": { "$ref": "#/kimchitype/graphics" } }, - "additionalProperties": false + "additionalProperties": false, + "error": "KCHAPI0001E" }, "storageservers_get_list": { "type": "object", @@ -267,7 +309,8 @@ "pattern": "^netfs$" } }, - "additionalProperties": false + "additionalProperties": false, + "error": "KCHAPI0001E" }, "storagetargets_get_list": { "type": "object", @@ -278,7 +321,8 @@ "pattern": "^netfs$" } }, - "additionalProperties": false + "additionalProperties": false, + "error": "KCHAPI0001E" }, "template_update": { "type": "object", @@ -287,37 +331,44 @@ "description": "The name of the template", "type": "string", "pattern": "^[^ ]+( +[^ ]+)*$", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0008E" }, "icon": { "description": "The template icon path", "type": "string", - "pattern": "^images/" + "pattern": "^images/", + "error": "KCHTMPL0009E" }, "os_distro": { "description": "Distribution name of the Operating System", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0010E" }, "os_version": { "description": "Version of the Operating System", "type": "string", - "minLength": 1 + "minLength": 1, + "error": "KCHTMPL0011E" }, "cpus": { "description": "Number of CPUs for the template", "type": "integer", - "minimum": 1 + "minimum": 1, + "error": "KCHTMPL0012E" }, "memory": { "description": "Memory (MB) for the template", "type": "integer", - "minimum": 512 + "minimum": 512, + "error": "KCHTMPL0013E" }, "cdrom": { "description": "Path for cdrom", "type": "string", - "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$" + "pattern": "^((/)|(http)[s]?:|[t]?(ftp)[s]?:)+.*([.]iso)$", + "error": "KCHTMPL0014E" }, "disks": { "description": "List of disks", @@ -343,13 +394,15 @@ "storagepool": { "description": "Location of the storage pool", "type": "string", - "pattern": "^/storagepools/[^/]+/?$" + "pattern": "^/storagepools/[^/]+/?$", + "error": "KCHTMPL0015E" }, "networks": { "description": "list of which networks will be assigned to the new VM.", "type": "array", "items": { "type": "string" }, - "uniqueItems": true + "uniqueItems": true, + "error": "KCHTMPL0017E" }, "folder": { "description": "Folder", @@ -358,7 +411,8 @@ }, "graphics": { "$ref": "#/kimchitype/graphics" } }, - "additionalProperties": false + "additionalProperties": false, + "error": "KCHAPI0001E" } } }

From: Aline Manera <alinefm@br.ibm.com> The error messages raised on control were being built in there instead of using the exception message And the errors from jsonschema validation also were displayed to the user without a customization what can cause a misunderstanding as it contains technical words. Fix it in order to raise the translated messages to the user. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/base.py | 90 ++++++++++++++++++++----------------------- src/kimchi/control/utils.py | 5 +-- 2 files changed, 44 insertions(+), 51 deletions(-) diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py index f50ff6e..102b53c 100644 --- a/src/kimchi/control/base.py +++ b/src/kimchi/control/base.py @@ -70,18 +70,16 @@ class Resource(object): fn(*model_args) uri_params = tuple(self.model_args) raise internal_redirect(self.uri_fmt % uri_params) - except MissingParameter, param: - error = "Missing parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidParameter, param: - error = "Invalid parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except MissingParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) wrapper.__name__ = action_name wrapper.exposed = True @@ -102,10 +100,10 @@ class Resource(object): except AttributeError: error = "Delete is not allowed for %s" % get_class_name(self) raise cherrypy.HTTPError(405, error) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) @cherrypy.expose def index(self): @@ -113,26 +111,26 @@ class Resource(object): if method == 'GET': try: return self.get() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(406, e.message) elif method == 'DELETE': try: return self.delete() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) elif method == 'PUT': try: return self.update() - except InvalidParameter, msg: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) def update(self): try: @@ -264,28 +262,24 @@ class Collection(object): filter_params = cherrypy.request.params validate_params(filter_params, self, 'get_list') return self.get(filter_params) - except InvalidOperation, param: - error = "Invalid operation: '%s'" % param - raise cherrypy.HTTPError(400, error) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) elif method == 'POST': try: return self.create(*args) - except MissingParameter, param: - error = "Missing parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidParameter, param: - error = "Invalid parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except OperationFailed, param: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) - except InvalidOperation, param: - error = "Invalid operation: '%s'" % param - raise cherrypy.HTTPError(400, error) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + except MissingParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) class AsyncCollection(Collection): diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py index 9c6878b..3e06100 100644 --- a/src/kimchi/control/utils.py +++ b/src/kimchi/control/utils.py @@ -101,9 +101,8 @@ def validate_params(params, instance, action): try: validator.validate(request) - except ValidationError: - raise InvalidParameter('; '.join( - e.message for e in validator.iter_errors(request))) + except ValidationError, e: + raise InvalidParameter(e.schema['error'], {'value': str(e.instance)}) class UrlSubNode(object): -- 1.7.10.4

On 02/09/2014 08:47 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
The error messages raised on control were being built in there instead of using the exception message And the errors from jsonschema validation also were displayed to the user without a customization what can cause a misunderstanding as it contains technical words. Fix it in order to raise the translated messages to the user.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/base.py | 90 ++++++++++++++++++++----------------------- src/kimchi/control/utils.py | 5 +-- 2 files changed, 44 insertions(+), 51 deletions(-)
diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py index f50ff6e..102b53c 100644 --- a/src/kimchi/control/base.py +++ b/src/kimchi/control/base.py @@ -70,18 +70,16 @@ class Resource(object): fn(*model_args) uri_params = tuple(self.model_args) raise internal_redirect(self.uri_fmt % uri_params) - except MissingParameter, param: - error = "Missing parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidParameter, param: - error = "Invalid parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except MissingParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message)
wrapper.__name__ = action_name wrapper.exposed = True @@ -102,10 +100,10 @@ class Resource(object): except AttributeError: error = "Delete is not allowed for %s" % get_class_name(self) This error message is not being translated. It should, right? raise cherrypy.HTTPError(405, error) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message)
@cherrypy.expose def index(self): @@ -113,26 +111,26 @@ class Resource(object): if method == 'GET': try: return self.get() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(406, e.message) elif method == 'DELETE': try: return self.delete() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) elif method == 'PUT': try: return self.update() - except InvalidParameter, msg: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message)
def update(self): try: @@ -264,28 +262,24 @@ class Collection(object): filter_params = cherrypy.request.params validate_params(filter_params, self, 'get_list') return self.get(filter_params) - except InvalidOperation, param: - error = "Invalid operation: '%s'" % param - raise cherrypy.HTTPError(400, error) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message)
elif method == 'POST': try: return self.create(*args) - except MissingParameter, param: - error = "Missing parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidParameter, param: - error = "Invalid parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except OperationFailed, param: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) - except InvalidOperation, param: - error = "Invalid operation: '%s'" % param - raise cherrypy.HTTPError(400, error) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + except MissingParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message)
class AsyncCollection(Collection): diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py index 9c6878b..3e06100 100644 --- a/src/kimchi/control/utils.py +++ b/src/kimchi/control/utils.py @@ -101,9 +101,8 @@ def validate_params(params, instance, action):
try: validator.validate(request) - except ValidationError: - raise InvalidParameter('; '.join( - e.message for e in validator.iter_errors(request))) + except ValidationError, e: + raise InvalidParameter(e.schema['error'], {'value': str(e.instance)})
class UrlSubNode(object): There is at least one error message in the login function in src/kimchi/root.py that is not being covered by this patch. I think the error message on missing parameter there should be translated as well.
Best regards, Leonardo Garcia

On 02/11/2014 01:09 AM, Leonardo Augusto Guimarães Garcia wrote:
On 02/09/2014 08:47 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
The error messages raised on control were being built in there instead of using the exception message And the errors from jsonschema validation also were displayed to the user without a customization what can cause a misunderstanding as it contains technical words. Fix it in order to raise the translated messages to the user.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/base.py | 90 ++++++++++++++++++++----------------------- src/kimchi/control/utils.py | 5 +-- 2 files changed, 44 insertions(+), 51 deletions(-)
diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py index f50ff6e..102b53c 100644 --- a/src/kimchi/control/base.py +++ b/src/kimchi/control/base.py @@ -70,18 +70,16 @@ class Resource(object): fn(*model_args) uri_params = tuple(self.model_args) raise internal_redirect(self.uri_fmt % uri_params) - except MissingParameter, param: - error = "Missing parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidParameter, param: - error = "Invalid parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except MissingParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message)
wrapper.__name__ = action_name wrapper.exposed = True @@ -102,10 +100,10 @@ class Resource(object): except AttributeError: error = "Delete is not allowed for %s" % get_class_name(self) This error message is not being translated. It should, right?
Ops... I forgot this one! I will include in V2.
raise cherrypy.HTTPError(405, error) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message)
@cherrypy.expose def index(self): @@ -113,26 +111,26 @@ class Resource(object): if method == 'GET': try: return self.get() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(406, e.message) elif method == 'DELETE': try: return self.delete() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message) elif method == 'PUT': try: return self.update() - except InvalidParameter, msg: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message)
def update(self): try: @@ -264,28 +262,24 @@ class Collection(object): filter_params = cherrypy.request.params validate_params(filter_params, self, 'get_list') return self.get(filter_params) - except InvalidOperation, param: - error = "Invalid operation: '%s'" % param - raise cherrypy.HTTPError(400, error) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message)
elif method == 'POST': try: return self.create(*args) - except MissingParameter, param: - error = "Missing parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except InvalidParameter, param: - error = "Invalid parameter: '%s'" % param - raise cherrypy.HTTPError(400, error) - except OperationFailed, param: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) - except InvalidOperation, param: - error = "Invalid operation: '%s'" % param - raise cherrypy.HTTPError(400, error) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + except MissingParameter, e: + raise cherrypy.HTTPError(400, e.message) + except InvalidParameter, e: + raise cherrypy.HTTPError(400, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) + except NotFoundError, e: + raise cherrypy.HTTPError(404, e.message)
class AsyncCollection(Collection): diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py index 9c6878b..3e06100 100644 --- a/src/kimchi/control/utils.py +++ b/src/kimchi/control/utils.py @@ -101,9 +101,8 @@ def validate_params(params, instance, action):
try: validator.validate(request) - except ValidationError: - raise InvalidParameter('; '.join( - e.message for e in validator.iter_errors(request))) + except ValidationError, e: + raise InvalidParameter(e.schema['error'], {'value': str(e.instance)})
class UrlSubNode(object):
There is at least one error message in the login function in src/kimchi/root.py that is not being covered by this patch. I think the error message on missing parameter there should be translated as well.
Yeap! I will add in V2.
Best regards,
Leonardo Garcia

From: Aline Manera <alinefm@br.ibm.com> Update all Kimchi exceptions to translate backend messages. Use message code to get the correct messages in i18n.py and raise a message like: "<code>: <translated-message>" Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/model.py | 12 ++-- src/kimchi/asynctask.py | 4 +- src/kimchi/auth.py | 3 +- src/kimchi/disks.py | 5 +- src/kimchi/distroloader.py | 5 +- src/kimchi/exception.py | 14 ++-- src/kimchi/iscsi.py | 6 +- src/kimchi/isoinfo.py | 17 +++-- src/kimchi/mockmodel.py | 113 +++++++++++++++++++------------- src/kimchi/model/config.py | 2 +- src/kimchi/model/debugreports.py | 18 ++--- src/kimchi/model/host.py | 10 +-- src/kimchi/model/interfaces.py | 4 +- src/kimchi/model/libvirtstoragepool.py | 14 ++-- src/kimchi/model/networks.py | 37 ++++++----- src/kimchi/model/storagepools.py | 39 ++++++----- src/kimchi/model/storageservers.py | 2 +- src/kimchi/model/storagevolumes.py | 37 ++++++----- src/kimchi/model/templates.py | 44 ++++++------- src/kimchi/model/utils.py | 2 +- src/kimchi/model/vmifaces.py | 15 ++--- src/kimchi/model/vms.py | 28 ++++---- src/kimchi/objectstore.py | 4 +- src/kimchi/template.py | 2 +- src/kimchi/utils.py | 12 ++-- src/kimchi/vmtemplate.py | 7 +- tests/test_exception.py | 4 +- tests/test_rest.py | 4 +- tests/utils.py | 5 +- 29 files changed, 255 insertions(+), 214 deletions(-) diff --git a/plugins/sample/model.py b/plugins/sample/model.py index 184864d..f7ca319 100644 --- a/plugins/sample/model.py +++ b/plugins/sample/model.py @@ -31,7 +31,7 @@ class CirclesModel(object): def create(self, params): name = params['name'] if name in self._circles: - raise InvalidOperation("Circle %s already exists" % name) + raise InvalidOperation("SPCIRCLE0001E", {'name': name}) self._circles[name] = Circle(params['radius']) return name @@ -48,12 +48,12 @@ class CircleModel(object): try: circle = self._circles[name] except KeyError: - raise NotFoundError("Circle %s not found" % name) + raise NotFoundError("SPCIRC0002E", {'name': name}) return {'radius': circle.radius} def update(self, name, params): if name not in self._circles: - raise NotFoundError("Circle %s not found" % name) + raise NotFoundError("SPCIRC0002E", {'name': name}) self._circles[name].radius = params['radius'] return name @@ -71,7 +71,7 @@ class RectanglesModel(object): def create(self, params): name = params['name'] if name in self._rectangles: - raise InvalidOperation("Rectangle %s already exists" % name) + raise InvalidOperation("SPRET0001E", {'name': name}) self._rectangles[name] = Rectangle(params['length'], params['width']) return name @@ -87,12 +87,12 @@ class RectangleModel(object): try: rectangle = self._rectangles[name] except KeyError: - raise NotFoundError("Rectangle %s not found" % name) + raise NotFoundError("SPRET0002E", {'name': name}) return {'length': rectangle.length, 'width': rectangle.width} def update(self, name, params): if name not in self._rectangles: - raise NotFoundError("Rectangle %s not found" % name) + raise NotFoundError("SPRET0002E", {'name': name}) try: self._rectangles[name].length = params['length'] except KeyError: diff --git a/src/kimchi/asynctask.py b/src/kimchi/asynctask.py index 4ff76e4..f5cba50 100644 --- a/src/kimchi/asynctask.py +++ b/src/kimchi/asynctask.py @@ -31,8 +31,8 @@ from kimchi.exception import OperationFailed class AsyncTask(object): def __init__(self, id, target_uri, fn, objstore, opaque=None): if objstore is None: - raise OperationFailed("Datastore is not initiated in " - "the model object") + raise OperationFailed("KCHASYNC0001E") + self.id = str(id) self.target_uri = target_uri self.fn = fn diff --git a/src/kimchi/auth.py b/src/kimchi/auth.py index 242fdcf..1cae45d 100644 --- a/src/kimchi/auth.py +++ b/src/kimchi/auth.py @@ -68,7 +68,8 @@ def authenticate(username, password, service="passwd"): try: auth.authenticate() except PAM.error, (resp, code): - raise OperationFailed(resp, code) + msg_args = {'userid': username, 'code': code} + raise OperationFailed("KCHAUTH0001E", msg_args) return True diff --git a/src/kimchi/disks.py b/src/kimchi/disks.py index 941aaca..83d5cc6 100644 --- a/src/kimchi/disks.py +++ b/src/kimchi/disks.py @@ -44,7 +44,7 @@ def _get_lsblk_devs(keys, devs=[]): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = lsblk.communicate() if lsblk.returncode != 0: - raise OperationFailed('Error executing lsblk: %s' % err) + raise OperationFailed("KCHDISKS0001E", {'err': err}) return _parse_lsblk_output(out, keys) @@ -60,8 +60,7 @@ def _get_dev_major_min(name): maj_min = dev['maj:min'] break else: - msg = "Failed to find major and minor number for %s" % name - raise OperationFailed(msg) + raise OperationFailed("KCHDISKS0002E", {'device': name}) return maj_min diff --git a/src/kimchi/distroloader.py b/src/kimchi/distroloader.py index 98fd764..f0b0208 100644 --- a/src/kimchi/distroloader.py +++ b/src/kimchi/distroloader.py @@ -37,10 +37,11 @@ class DistroLoader(object): self.location = location or config.get_distros_store() def _get_json_info(self, fname): + msg_args = {'filename': fname} if not os.path.isfile(fname): msg = "DistroLoader: failed to find distro file: %s" % fname kimchi_log.error(msg) - raise NotFoundError(msg) + raise NotFoundError("KCHDL0001E", msg_args) try: with open(fname) as f: data = json.load(f) @@ -48,7 +49,7 @@ class DistroLoader(object): except ValueError: msg = "DistroLoader: failed to parse distro file: %s" % fname kimchi_log.error(msg) - raise OperationFailed(msg) + raise OperationFailed("KCHDL0002E", msg_args) def get(self): all_json_files = glob.glob("%s/%s" % (self.location, "*.json")) diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py index 7fcce54..952e243 100644 --- a/src/kimchi/exception.py +++ b/src/kimchi/exception.py @@ -49,29 +49,29 @@ class KimchiException(Exception): Exception.__init__(self, pattern) -class NotFoundError(Exception): +class NotFoundError(KimchiException): pass -class OperationFailed(Exception): +class OperationFailed(KimchiException): pass -class MissingParameter(Exception): +class MissingParameter(KimchiException): pass -class InvalidParameter(Exception): +class InvalidParameter(KimchiException): pass -class InvalidOperation(Exception): +class InvalidOperation(KimchiException): pass -class IsoFormatError(Exception): +class IsoFormatError(KimchiException): pass -class TimeoutExpired(Exception): +class TimeoutExpired(KimchiException): pass diff --git a/src/kimchi/iscsi.py b/src/kimchi/iscsi.py index 35c0b8a..248188c 100644 --- a/src/kimchi/iscsi.py +++ b/src/kimchi/iscsi.py @@ -55,7 +55,8 @@ class TargetClient(object): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = iscsiadm.communicate() if iscsiadm.returncode != 0: - raise OperationFailed('Error executing iscsiadm: %s' % err) + msg_args = {'portal': self.portal, 'err': err} + raise OperationFailed("KCHISCSI0001E", msg_args) return out def _discover(self): @@ -65,7 +66,8 @@ class TargetClient(object): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = iscsiadm.communicate() if iscsiadm.returncode != 0: - raise OperationFailed('Error executing iscsiadm: %s' % err) + msg_args = {'portal': self.portal, 'err': err} + raise OperationFailed("KCHISCSI0001E", msg_args) return out def _run_op(self, op): diff --git a/src/kimchi/isoinfo.py b/src/kimchi/isoinfo.py index a3cd4cd..5629391 100644 --- a/src/kimchi/isoinfo.py +++ b/src/kimchi/isoinfo.py @@ -149,11 +149,11 @@ class IsoImage(object): if check_url_path(self.path): return True - raise IsoFormatError('ISO %s does not exist' % self.path) + raise IsoFormatError("KCHISO0001E", {'filename': self.path}) def probe(self): if not self.bootable: - raise IsoFormatError("ISO %s not bootable" % self.path) + raise IsoFormatError("KCHISO0002E", {'filename': self.path}) matcher = Matcher(self.volume_id) @@ -197,7 +197,8 @@ class IsoImage(object): if vd_type == 0: # Found El-Torito Boot Record break if not et_ident.startswith('EL TORITO SPECIFICATION'): - raise IsoFormatError("Invalid El Torito boot record") + raise IsoFormatError("KCHISO0003E", + {'filename': self.path}) offset = IsoImage.SECTOR_SIZE * boot_cat size = IsoImage.EL_TORITO_VALIDATION_ENTRY.size + \ @@ -210,7 +211,8 @@ class IsoImage(object): (hdr_id, platform_id, pad0, ident, csum, key55, keyAA) = self._unpack(fmt, tmp_data) if key55 != 0x55 or keyAA != 0xaa: - raise IsoFormatError("Invalid El Torito validation entry") + raise IsoFormatError("KCHISO0004E", + {'filename': self.path}) fmt = IsoImage.EL_TORITO_BOOT_ENTRY tmp_data = data[ptr:ptr+fmt.size] @@ -221,7 +223,8 @@ class IsoImage(object): elif boot == 0: self.bootable = False else: - raise IsoFormatError("Invalid El Torito boot indicator") + raise IsoFormatError("KCHISO0005E", + {'filename': self.path}) def _scan_primary_vol(self, data): """ @@ -232,9 +235,9 @@ class IsoImage(object): info = self._unpack(IsoImage.VOL_DESC, primary_vol_data) (vd_type, vd_ident, vd_ver, pad0, sys_id, vol_id) = info if vd_type != 1: - raise IsoFormatError("Unexpected volume type for primary volume") + raise IsoFormatError("KCHISO0006E", {'filename': self.path}) if vd_ident != 'CD001' or vd_ver != 1: - raise IsoFormatError("Bad format while reading volume descriptor") + raise IsoFormatError("KCHISO0007E", {'filename': self.path}) self.volume_id = vol_id def _get_iso_data(self, offset, size): diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index 4e276eb..e5425b2 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -83,7 +83,8 @@ class MockModel(object): if 'name' in params: if state == 'running' or params['name'] in self.vms_get_list(): - raise InvalidParameter("VM name existed or vm not shutoff.") + msg_args = {'name': dom.name, 'new_name': params['name']} + raise InvalidParameter("KCHVM0003E", msg_args) else: del self._mock_vms[dom.name] dom.name = params['name'] @@ -134,7 +135,7 @@ class MockModel(object): name = get_vm_name(params.get('name'), t_name, self._mock_vms.keys()) if name in self._mock_vms: - raise InvalidOperation("VM already exists") + raise InvalidOperation("KCHVM0001E", {'name': name}) vm_uuid = str(uuid.uuid4()) vm_overrides = dict() @@ -166,7 +167,8 @@ class MockModel(object): def vmscreenshot_lookup(self, name): vm = self._get_vm(name) if vm.info['state'] != 'running': - raise NotFoundError('No screenshot for stopped vm') + raise NotFoundError("KCHVM0004E", {'name': name}) + screenshot = self._mock_screenshots.setdefault( vm.uuid, MockVMScreenshot({'uuid': vm.uuid})) return screenshot.lookup() @@ -185,18 +187,19 @@ class MockModel(object): try: del self._mock_templates[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHTMPL0002E", {'name': name}) def templates_create(self, params): name = params['name'] if name in self._mock_templates: - raise InvalidOperation("Template already exists") + raise InvalidOperation("KCHTMPL0001E", {'name': name}) + for net_name in params.get(u'networks', []): try: self._get_network(net_name) except NotFoundError: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + msg_args = {'network': net_name, 'template': name} + raise InvalidParameter("KCHTMPL0003E", msg_args) t = MockVMTemplate(params, self) self._mock_templates[name] = t @@ -212,15 +215,16 @@ class MockModel(object): new_storagepool = new_t.get(u'storagepool', '') try: self._get_storagepool(pool_name_from_uri(new_storagepool)) - except Exception as e: - raise InvalidParameter("Storagepool specified is not valid: %s." % e.message) + except Exception: + msg_args = {'pool': new_storagepool, 'template': name} + raise InvalidParameter("KCHTMPL0004E", msg_args) for net_name in params.get(u'networks', []): try: self._get_network(net_name) except NotFoundError: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + msg_args = {'network': net_name, 'template': name} + raise InvalidParameter("KCHTMPL0003E", msg_args) self.template_delete(name) try: @@ -243,7 +247,7 @@ class MockModel(object): else: return t except KeyError: - raise NotFoundError() + raise NotFoundError("KCHTMPL0002E", {'name': name}) def debugreport_lookup(self, name): path = config.get_debugreports_path() @@ -251,7 +255,7 @@ class MockModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name', name}) ctime = os.stat(file_target).st_ctime ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) @@ -269,7 +273,7 @@ class MockModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name', name}) os.remove(file_target) @@ -291,7 +295,7 @@ class MockModel(object): try: return self._mock_vms[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHVM0002E", {'name': name}) def storagepools_create(self, params): try: @@ -304,9 +308,12 @@ class MockModel(object): else: pool.info['autostart'] = False except KeyError, item: - raise MissingParameter(item) + raise MissingParameter("KCHPOOL0004E", + {'item': item, 'name': name}) + if name in self._mock_storagepools or name in (ISO_POOL_NAME,): - raise InvalidOperation("StoragePool already exists") + raise InvalidOperation("KCHPOOL0001E", {'name': name}) + self._mock_storagepools[name] = pool return name @@ -318,7 +325,8 @@ class MockModel(object): def storagepool_update(self, name, params): autostart = params['autostart'] if autostart not in [True, False]: - raise InvalidOperation("Autostart flag must be true or false") + raise InvalidOperation("KCHPOOL0003E") + storagepool = self._get_storagepool(name) storagepool.info['autostart'] = autostart ident = storagepool.name @@ -342,12 +350,15 @@ class MockModel(object): try: return self._mock_storagepools[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHPOOL0002E", {'name': name}) def storagevolumes_create(self, pool_name, params): pool = self._get_storagepool(pool_name) if pool.info['state'] == 'inactive': - raise InvalidOperation("StoragePool not active") + raise InvalidOperation("KCHVOL0003E", + {'pool': pool_name, + 'volume': params['name']}) + try: name = params['name'] volume = MockStorageVolume(pool, name, params) @@ -356,15 +367,20 @@ class MockModel(object): volume.info['path'] = os.path.join( pool.info['path'], name) except KeyError, item: - raise MissingParameter(item) + raise MissingParameter("KCHVOL0004E", + {'item': item, 'volume': name}) + if name in pool._volumes: - raise InvalidOperation("StorageVolume already exists") + raise InvalidOperation("KCHVOL0001E", {'name': name}) + pool._volumes[name] = volume return name def storagevolume_lookup(self, pool, name): if self._get_storagepool(pool).info['state'] != 'active': - raise InvalidOperation("StoragePool %s is not active" % pool) + raise InvalidOperation("KCHVOL0005E", {'pool': pool, + 'volume': name}) + storagevolume = self._get_storagevolume(pool, name) return storagevolume.info @@ -384,8 +400,7 @@ class MockModel(object): def storagevolumes_get_list(self, pool): res = self._get_storagepool(pool) if res.info['state'] == 'inactive': - raise InvalidOperation( - "Unable to list volumes of inactive storagepool %s" % pool) + raise InvalidOperation("KCHVOL0006E", {'pool': pool}) return res._volumes.keys() def isopool_lookup(self, name): @@ -438,7 +453,7 @@ class MockModel(object): # Avoid inconsistent pool result because of lease between list and lookup pass - raise NotFoundError("storage server %s not used by kimchi" % server) + raise NotFoundError("KCHSR0001E", {'server': server}) def dummy_interfaces(self): interfaces = {} @@ -461,7 +476,8 @@ class MockModel(object): def networks_create(self, params): name = params['name'] if name in self.networks_get_list(): - raise InvalidOperation("Network %s already exists" % name) + raise InvalidOperation("KCHNET0001E", {'name': name}) + network = MockNetwork(name) connection = params['connection'] network.info['connection'] = connection @@ -469,22 +485,23 @@ class MockModel(object): try: interface = params['interface'] network.info['interface'] = interface - except KeyError, key: - raise MissingParameter(key) + except KeyError: + raise MissingParameter("KCHNET0004E", + {'name': name}) subnet = params.get('subnet', '') if subnet: network.info['subnet'] = subnet try: net = ipaddr.IPNetwork(subnet) - except ValueError, e: - raise InvalidParameter(e) + except ValueError: + msg_args = {'subnet':subnet, 'network': name} + raise InvalidParameter("KCHNET0003E", msg_args) network.info['dhcp'] = { 'start': str(net.network + net.numhosts / 2), 'stop': str(net.network + net.numhosts - 2)} - if name in self._mock_networks: - raise InvalidOperation("Network already exists") + self._mock_networks[name] = network return name @@ -492,7 +509,7 @@ class MockModel(object): try: return self._mock_networks[name] except KeyError: - raise NotFoundError("Network '%s'" % name) + raise NotFoundError("KCHNET0002E", {'name': name}) def _get_vms_attach_to_a_network(self, network): vms = [] @@ -523,8 +540,9 @@ class MockModel(object): def vmifaces_create(self, vm, params): if (params["type"] == "network" and params["network"] not in self.networks_get_list()): - raise InvalidParameter("%s is not an available network" % - params["network"]) + msg_args = {'network': params["network"], 'name': vm} + raise InvalidParameter("KCHVMIF0002E", msg_args) + dom = self._get_vm(vm) iface = MockVMIface(params["network"]) ("model" in params.keys() and @@ -544,7 +562,7 @@ class MockModel(object): try: info = dom.ifaces[mac].info except KeyError: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'iface': mac, 'name': vm}) return info def vmiface_delete(self, vm, mac): @@ -552,7 +570,7 @@ class MockModel(object): try: del dom.ifaces[mac] except KeyError: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'iface': mac, 'name': vm}) def tasks_get_list(self): with self.objstore as session: @@ -573,7 +591,7 @@ class MockModel(object): try: return self._get_storagepool(pool)._volumes[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHVOL0002E", {'name': name, 'pool': pool}) def _get_distros(self): distroloader = DistroLoader() @@ -586,7 +604,7 @@ class MockModel(object): try: return self.distros[name] except KeyError: - raise NotFoundError("distro '%s' not found" % name) + raise NotFoundError("KCHDISTRO0001E", {'name': name}) def _gen_debugreport_file(self, ident): return self.add_task('', self._create_log, ident) @@ -638,14 +656,14 @@ class MockModel(object): # Check for running vms before shutdown running_vms = self.vms_get_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Shutdown not allowed: VMs are running!") + raise OperationFailed("KCHHOST0001E") cherrypy.engine.exit() def host_reboot(self, args=None): # Find running VMs running_vms = self.vms_get_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Reboot not allowed: VMs are running!") + raise OperationFailed("KCHHOST0002E") cherrypy.engine.stop() time.sleep(10) cherrypy.engine.start() @@ -656,8 +674,8 @@ class MockModel(object): def partition_lookup(self, name): if name not in disks.get_partitions_names(): - raise NotFoundError("Partition %s not found in the host" - % name) + raise NotFoundError("KCHPART0001E", {'name': name}) + return disks.get_partition_details(name) def config_lookup(self, name): @@ -677,9 +695,12 @@ class MockVMTemplate(VMTemplate): try: pool = self.model._get_storagepool(pool_name) except NotFoundError: - raise InvalidParameter('Storage specified by template does not exist') + msg_args = {'pool': pool_name, 'template': self.name} + raise InvalidParameter("KCHTMPL0004E", msg_args) + if pool.info['state'] != 'active': - raise InvalidParameter('Storage specified by template is not active') + msg_args = {'pool': pool_name, 'template': self.name} + raise InvalidParameter("KCHTMPL0005E", msg_args) return pool diff --git a/src/kimchi/model/config.py b/src/kimchi/model/config.py index 0e66e02..9b5814a 100644 --- a/src/kimchi/model/config.py +++ b/src/kimchi/model/config.py @@ -95,4 +95,4 @@ class DistroModel(object): try: return self._distros.distros[name] except KeyError: - raise NotFoundError("Distro '%s' not found." % name) + raise NotFoundError("KCHDISTRO0001E", {'name': name}) diff --git a/src/kimchi/model/debugreports.py b/src/kimchi/model/debugreports.py index a1cb19c..2c5b13a 100644 --- a/src/kimchi/model/debugreports.py +++ b/src/kimchi/model/debugreports.py @@ -59,7 +59,7 @@ class DebugReportsModel(object): if gen_cmd is not None: return add_task('', gen_cmd, self.objstore, name) - raise OperationFailed("debugreport tool not found") + raise OperationFailed("KCHDR0002E") @staticmethod def sosreport_generate(cb, name): @@ -68,9 +68,11 @@ class DebugReportsModel(object): retcode = subprocess.call(command, shell=True, stdout=subprocess.PIPE) if retcode < 0: - raise OperationFailed('Command terminated with signal') + raise OperationFailed("KCHDR0003E", {'name': name, + 'err': retcode}) elif retcode > 0: - raise OperationFailed('Command failed: rc = %i' % retcode) + raise OperationFailed("KCHDR0003E", {'name': name, + 'err': retcode}) pattern = '/tmp/sosreport-%s-*' % name for reportFile in glob.glob(pattern): if not fnmatch.fnmatch(reportFile, '*.md5'): @@ -83,8 +85,8 @@ class DebugReportsModel(object): # runs successfully. In future we might have a general name # mangling function in kimchi to format the name before passing # it to sosreport. Then we can delete this exception. - raise OperationFailed('Can not find generated debug report ' - 'named by %s' % pattern) + raise OperationFailed("KCHDR0004E", {'name': pattern}) + ext = output.split('.', 1)[1] path = config.get_debugreports_path() target = os.path.join(path, name) @@ -104,7 +106,7 @@ class DebugReportsModel(object): # and update the task status there log = logging.getLogger('Model') log.warning('Exception in generating debug file: %s', e) - raise OperationFailed(e) + raise OperationFailed("KCHDR0005E", {'name': name, 'err': e}) @staticmethod def get_system_report_tool(): @@ -139,7 +141,7 @@ class DebugReportModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name': name}) ctime = os.stat(file_target).st_ctime ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) @@ -154,7 +156,7 @@ class DebugReportModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name': name}) os.remove(file_target) diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index a3d9e38..80f93db 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -67,7 +67,8 @@ class HostModel(object): # Check for running vms before shutdown running_vms = self._get_vms_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Shutdown not allowed: VMs are running!") + raise OperationFailed("KCHHOST0001E") + kimchi_log.info('Host is going to shutdown.') os.system('shutdown -h now') @@ -75,7 +76,8 @@ class HostModel(object): # Find running VMs running_vms = self._get_vms_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Reboot not allowed: VMs are running!") + raise OperationFailed("KCHHOST0002E") + kimchi_log.info('Host is going to reboot.') os.system('reboot') @@ -196,6 +198,6 @@ class PartitionModel(object): def lookup(self, name): if name not in disks.get_partitions_names(): - raise NotFoundError("Partition %s not found in the host" - % name) + raise NotFoundError("KCHPART0001E", {'name': name}) + return disks.get_partition_details(name) diff --git a/src/kimchi/model/interfaces.py b/src/kimchi/model/interfaces.py index 52c6bae..96b1261 100644 --- a/src/kimchi/model/interfaces.py +++ b/src/kimchi/model/interfaces.py @@ -42,5 +42,5 @@ class InterfaceModel(object): def lookup(self, name): try: return netinfo.get_interface_info(name) - except ValueError, e: - raise NotFoundError(e) + except ValueError: + raise NotFoundError("KCHIFACE0001E", {'name': name}) diff --git a/src/kimchi/model/libvirtstoragepool.py b/src/kimchi/model/libvirtstoragepool.py index f4dbf2e..f9b395c 100644 --- a/src/kimchi/model/libvirtstoragepool.py +++ b/src/kimchi/model/libvirtstoragepool.py @@ -38,7 +38,7 @@ class StoragePoolDef(object): for klass in cls.__subclasses__(): if poolArgs['type'] == klass.poolType: return klass(poolArgs) - raise OperationFailed('Unsupported pool type: %s' % poolArgs['type']) + raise OperationFailed("KCHPOOL0014E", {'type': poolArgs['type']}) def __init__(self, poolArgs): self.poolArgs = poolArgs @@ -56,7 +56,7 @@ class StoragePoolDef(object): idempotent''' # TODO: When add new pool type, should also add the related test in # tests/test_storagepool.py - raise OperationFailed('self.xml is not implemented: %s' % self) + raise OperationFailed("KCHPOOL0015E", {'pool': self}) class DirPoolDef(StoragePoolDef): @@ -101,8 +101,7 @@ class NetfsPoolDef(StoragePoolDef): run_command(mount_cmd, 30) rollback.prependDefer(run_command, umount_cmd) except TimeoutExpired: - err = "Export path %s may block during nfs mount" - raise InvalidParameter(err % export_path) + raise InvalidParameter("KCHPOOL0012E", {'path': export_path}) with open("/proc/mounts", "rb") as f: rawMounts = f.read() @@ -113,8 +112,7 @@ class NetfsPoolDef(StoragePoolDef): mounted = True if not mounted: - err = "Export path %s mount failed during nfs mount" - raise InvalidParameter(err % export_path) + raise InvalidParameter("KCHPOOL0013E", {'path': export_path}) @property def xml(self): @@ -181,8 +179,8 @@ class IscsiPoolDef(StoragePoolDef): def prepare(self, conn): source = self.poolArgs['source'] if not TargetClient(**source).validate(): - raise OperationFailed("Can not login to iSCSI host %s target %s" % - (source['host'], source['target'])) + msg_args = {'host': source['host'], 'target': source['target']} + raise OperationFailed("KCHISCSI0002E", msg_args) self._prepare_auth(conn) def _prepare_auth(self, conn): diff --git a/src/kimchi/model/networks.py b/src/kimchi/model/networks.py index b164141..05105df 100644 --- a/src/kimchi/model/networks.py +++ b/src/kimchi/model/networks.py @@ -39,7 +39,7 @@ class NetworksModel(object): conn = self.conn.get() name = params['name'] if name in self.get_list(): - raise InvalidOperation("Network %s already exists" % name) + raise InvalidOperation("KCHNET0001E", {'name': name}) connection = params["connection"] # set forward mode, isolated do not need forward @@ -60,7 +60,8 @@ class NetworksModel(object): network = conn.networkDefineXML(xml) network.setAutostart(True) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHNET0008E", + {'name': name, 'err': e.get_error_message()}) return name @@ -80,13 +81,13 @@ class NetworksModel(object): subnet and net_addrs.append(ipaddr.IPNetwork(subnet)) netaddr = knetwork.get_one_free_network(net_addrs) if not netaddr: - raise OperationFailed("can not find a free IP address for " - "network '%s'" % params['name']) + raise OperationFailed("KCHNET0009E", {'name': params['name']}) try: ip = ipaddr.IPNetwork(netaddr) - except ValueError as e: - raise InvalidParameter("%s" % e) + except ValueError: + raise InvalidParameter("KCHNET0003E", {'subent': netaddr, + 'network': params['name']}) if ip.ip == ip.network: ip.ip = ip.ip + 1 @@ -101,10 +102,11 @@ class NetworksModel(object): try: iface = params['interface'] if iface in self.get_all_networks_interfaces(): - raise InvalidParameter("interface '%s' already in use." % - iface) - except KeyError, e: - raise MissingParameter(e) + msg_args = {'iface': iface, 'network': params['name']} + raise InvalidParameter("KCHNET0006E", msg_args) + except KeyError: + raise MissingParameter("KCHNET0004E", {'name': params['name']}) + if netinfo.is_bridge(iface): params['bridge'] = iface elif netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface): @@ -115,8 +117,7 @@ class NetworksModel(object): self._create_vlan_tagged_bridge(str(iface), str(params['vlan_id'])) else: - raise InvalidParameter("the interface should be bare nic, " - "bonding or bridge device.") + raise InvalidParameter("KCHNET0007E") def get_all_networks_interfaces(self): net_names = self.get_list() @@ -144,7 +145,8 @@ class NetworksModel(object): vlan_tagged_br.create() except libvirt.libvirtError as e: conn.changeRollback() - raise OperationFailed(e.message) + raise OperationFailed("KCHNET0010E", {'iface': interface, + 'err': e.message}) else: conn.changeCommit() return br_name @@ -211,8 +213,8 @@ class NetworkModel(object): def delete(self, name): network = self._get_network(name) if network.isActive(): - raise InvalidOperation( - "Unable to delete the active network %s" % name) + raise InvalidOperation("KCHNET0005E", {'name': name}) + self._remove_vlan_tagged_bridge(network) network.undefine() @@ -220,9 +222,8 @@ class NetworkModel(object): conn = self.conn.get() try: return conn.networkLookupByName(name) - except libvirt.libvirtError as e: - raise NotFoundError("Network '%s' not found: %s" % - (name, e.get_error_message())) + except libvirt.libvirtError: + raise NotFoundError("KCHNET0002E", {'name': name}) @staticmethod def get_network_from_xml(xml): diff --git a/src/kimchi/model/storagepools.py b/src/kimchi/model/storagepools.py index 233a8a7..fa73ce9 100644 --- a/src/kimchi/model/storagepools.py +++ b/src/kimchi/model/storagepools.py @@ -55,7 +55,8 @@ class StoragePoolsModel(object): names += conn.listDefinedStoragePools() return sorted(names) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0006E", + {'err': e.get_error_message()}) def create(self, params): task_id = None @@ -63,19 +64,19 @@ class StoragePoolsModel(object): try: name = params['name'] if name in (ISO_POOL_NAME, ): - raise InvalidOperation("StoragePool already exists") + raise InvalidOperation("KCHPOOL0001E", {'name': name}) if params['type'] == 'kimchi-iso': task_id = self._do_deep_scan(params) poolDef = StoragePoolDef.create(params) poolDef.prepare(conn) xml = poolDef.xml - except KeyError, key: - raise MissingParameter(key) + except KeyError, item: + raise MissingParameter("KCHPOOL0004E", + {'item': item, 'name': name}) if name in self.get_list(): - err = "The name %s has been used by a pool" - raise InvalidOperation(err % name) + raise InvalidOperation("KCHPOOL0001E", {'name': name}) try: if task_id: @@ -92,9 +93,9 @@ class StoragePoolsModel(object): # disable autostart for others pool.setAutostart(0) except libvirt.libvirtError as e: - msg = "Problem creating Storage Pool: %s" - kimchi_log.error(msg, e) - raise OperationFailed(e.get_error_message()) + kimchi_log.error("Problem creating Storage Pool: %s", e) + raise OperationFailed("KCHPOOL0007E", + {'name': name, 'err': e.get_error_message()}) return name def _clean_scan(self, pool_name): @@ -144,7 +145,7 @@ class StoragePoolModel(object): return conn.storagePoolLookupByName(name) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL: - raise NotFoundError("Storage Pool '%s' not found" % name) + raise NotFoundError("KCHTMPL0002E", {'name': name}) else: raise @@ -156,7 +157,8 @@ class StoragePoolModel(object): else: return 0 except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0008E", + {'name': pool, 'err': e.get_error_message()}) def _get_storage_source(self, pool_type, pool_xml): source = {} @@ -203,7 +205,8 @@ class StoragePoolModel(object): def update(self, name, params): autostart = params['autostart'] if autostart not in [True, False]: - raise InvalidOperation("Autostart flag must be true or false") + raise InvalidOperation("KCHPOOL0003E") + pool = self.get_storagepool(name, self.conn) if autostart: pool.setAutostart(1) @@ -217,24 +220,26 @@ class StoragePoolModel(object): try: pool.create(0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0009E", + {'name': name, 'err': e.get_error_message()}) def deactivate(self, name): pool = self.get_storagepool(name, self.conn) try: pool.destroy() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0010E", + {'name': name, 'err': e.get_error_message()}) def delete(self, name): pool = self.get_storagepool(name, self.conn) if pool.isActive(): - err = "Unable to delete the active storagepool %s" - raise InvalidOperation(err % name) + raise InvalidOperation("KCHPOOL0005E", {'name': name}) try: pool.undefine() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0011E", + {'name': name, 'err': e.get_error_message()}) class IsoPoolModel(object): diff --git a/src/kimchi/model/storageservers.py b/src/kimchi/model/storageservers.py index 6a7c14a..26e1f6f 100644 --- a/src/kimchi/model/storageservers.py +++ b/src/kimchi/model/storageservers.py @@ -75,4 +75,4 @@ class StorageServerModel(object): # lookup pass - raise NotFoundError('server %s does not used by kimchi' % server) + raise NotFoundError("KCHSR0001E", {'server': server}) diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py index 8440a76..e3f00ca 100644 --- a/src/kimchi/model/storagevolumes.py +++ b/src/kimchi/model/storagevolumes.py @@ -57,29 +57,33 @@ class StorageVolumesModel(object): params.setdefault('allocation', 0) params.setdefault('format', 'qcow2') + name = params['name'] try: pool = StoragePoolModel.get_storagepool(pool, self.conn) - name = params['name'] xml = vol_xml % params - except KeyError, key: - raise MissingParameter(key) + except KeyError, item: + raise MissingParameter("KCHVOL0004E", {'item': item, + 'volume': name}) try: pool.createXML(xml, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0007E", + {'name': name, 'pool': pool, + 'err': e.get_error_message()}) return name - def get_list(self, pool): - pool = StoragePoolModel.get_storagepool(pool, self.conn) + def get_list(self, pool_name): + pool = StoragePoolModel.get_storagepool(pool_name, self.conn) if not pool.isActive(): - err = "Unable to list volumes in inactive storagepool %s" - raise InvalidOperation(err % pool.name()) + raise InvalidOperation("KCHVOL0006E", {'pool': pool_name}) try: pool.refresh(0) return pool.listVolumes() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0008E", + {'pool': pool_name, + 'err': e.get_error_message()}) class StorageVolumeModel(object): @@ -89,13 +93,13 @@ class StorageVolumeModel(object): def _get_storagevolume(self, pool, name): pool = StoragePoolModel.get_storagepool(pool, self.conn) if not pool.isActive(): - err = "Unable to list volumes in inactive storagepool %s" - raise InvalidOperation(err % pool.name()) + raise InvalidOperation("KCHVOL0006E", {'name': pool}) try: return pool.storageVolLookupByName(name) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL: - raise NotFoundError("Storage Volume '%s' not found" % name) + raise NotFoundError("KCHVOL0002E", {'name': name, + 'pool': pool}) else: raise @@ -131,14 +135,16 @@ class StorageVolumeModel(object): try: volume.wipePattern(libvirt.VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0009E", + {'name': name, 'err': e.get_error_message()}) def delete(self, pool, name): volume = self._get_storagevolume(pool, name) try: volume.delete(0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0010E", + {'name': name, 'err': e.get_error_message()}) def resize(self, pool, name, size): size = size << 20 @@ -146,7 +152,8 @@ class StorageVolumeModel(object): try: volume.resize(size, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0011E", + {'name': name, 'err': e.get_error_message()}) class IsoVolumesModel(object): diff --git a/src/kimchi/model/templates.py b/src/kimchi/model/templates.py index 03632a6..0eb7faa 100644 --- a/src/kimchi/model/templates.py +++ b/src/kimchi/model/templates.py @@ -25,7 +25,7 @@ import copy import libvirt from kimchi import xmlutils -from kimchi.exception import InvalidOperation, InvalidParameter, NotFoundError +from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.utils import pool_name_from_uri from kimchi.vmtemplate import VMTemplate @@ -44,20 +44,20 @@ class TemplatesModel(object): pool_name = pool_name_from_uri(pool_uri) try: conn.storagePoolLookupByName(pool_name) - except Exception as e: - err = "Storagepool specified is not valid: %s." - raise InvalidParameter(err % e.message) + except Exception: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': name}) for net_name in params.get(u'networks', []): try: conn.networkLookupByName(net_name) - except Exception, e: - raise InvalidParameter("Network '%s' specified by template " - "does not exist." % net_name) + except Exception: + raise InvalidParameter("KCHTMPL0003E", {'network': net_name, + 'template': name}) with self.objstore as session: if name in session.get_list('template'): - raise InvalidOperation("Template already exists") + raise InvalidOperation("KCHTMPL0001E", {'name': name}) t = LibvirtVMTemplate(params, scan=True) session.store('template', name, t.info) return name @@ -100,17 +100,17 @@ class TemplateModel(object): try: conn = self.conn.get() conn.storagePoolLookupByName(pool_name) - except Exception as e: - err = "Storagepool specified is not valid: %s." - raise InvalidParameter(err % e.message) + except Exception: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': name}) for net_name in params.get(u'networks', []): try: conn = self.conn.get() conn.networkLookupByName(net_name) - except Exception, e: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + except Exception: + raise InvalidParameter("KCHTMPL0003E", {'network': net_name, + 'template': name}) self.delete(name) try: @@ -133,12 +133,12 @@ class LibvirtVMTemplate(VMTemplate): conn = self.conn.get() pool = conn.storagePoolLookupByName(pool_name) except libvirt.libvirtError: - err = 'Storage specified by template does not exist' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': self.name}) if not pool.isActive(): - err = 'Storage specified by template is not active' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0005E", {'pool': pool_name, + 'template': self.name}) return pool @@ -149,12 +149,12 @@ class LibvirtVMTemplate(VMTemplate): conn = self.conn.get() network = conn.networkLookupByName(name) except libvirt.libvirtError: - err = 'Network specified by template does not exist' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0003E", {'network': name, + 'template': self.name}) if not network.isActive(): - err = 'Network specified by template is not active' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0007E", {'network': name, + 'template': self.name}) def _get_storage_path(self): pool = self._storage_validate() diff --git a/src/kimchi/model/utils.py b/src/kimchi/model/utils.py index a27b867..b642f05 100644 --- a/src/kimchi/model/utils.py +++ b/src/kimchi/model/utils.py @@ -30,4 +30,4 @@ def get_vm_name(vm_name, t_name, name_list): vm_name = "%s-vm-%i" % (t_name, i) if vm_name not in name_list: return vm_name - raise OperationFailed("Unable to choose a VM name") + raise OperationFailed("KCHUTILS0003E") diff --git a/src/kimchi/model/vmifaces.py b/src/kimchi/model/vmifaces.py index f3eddb2..f526e0d 100644 --- a/src/kimchi/model/vmifaces.py +++ b/src/kimchi/model/vmifaces.py @@ -52,13 +52,12 @@ class VMIfacesModel(object): networks = conn.listNetworks() + conn.listDefinedNetworks() if params["type"] == "network" and params["network"] not in networks: - raise InvalidParameter("%s is not an available network" % - params["network"]) + raise InvalidParameter("KCHVMIF0002E", + {'name': vm, 'network': params["network"]}) dom = VMModel.get_vm(vm, self.conn) if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - raise InvalidOperation("do not support hot plugging attach " - "guest interface") + raise InvalidOperation("KCHVMIF0003E") macs = (iface.mac.get('address') for iface in self.get_vmifaces(vm, self.conn)) @@ -108,7 +107,7 @@ class VMIfaceModel(object): iface = self._get_vmiface(vm, mac) if iface is None: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) info['type'] = iface.attrib['type'] info['mac'] = iface.mac.get('address') @@ -126,10 +125,10 @@ class VMIfaceModel(object): iface = self._get_vmiface(vm, mac) if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - raise InvalidOperation("do not support hot plugging detach " - "guest interface") + raise InvalidOperation("KCHVMIF0003E") + if iface is None: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac}) dom.detachDeviceFlags(etree.tostring(iface), libvirt.VIR_DOMAIN_AFFECT_CURRENT) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index d4384a1..d9e4f20 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -163,7 +163,7 @@ class VMsModel(object): name = get_vm_name(params.get('name'), t_name, vm_list) # incoming text, from js json, is unicode, do not need decode if name in vm_list: - raise InvalidOperation("VM already exists") + raise InvalidOperation("KCHVM0001E", {'name': name}) vm_overrides = dict() pool_uri = params.get('storagepool') @@ -173,8 +173,7 @@ class VMsModel(object): vm_overrides) if not self.caps.qemu_stream and t.info.get('iso_stream', False): - err = "Remote ISO image is not supported by this server." - raise InvalidOperation(err) + raise InvalidOperation("KCHVM0005E") t.validate() vol_list = t.fork_vm_storage(vm_uuid) @@ -201,7 +200,8 @@ class VMsModel(object): for v in vol_list: vol = conn.storageVolLookupByPath(v['path']) vol.delete(0) - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVM0007E", {'name': name, + 'err': e.get_error_message()}) return name @@ -237,15 +237,16 @@ class VMModel(object): try: if 'name' in params: if state == 'running': - err = "VM name only can be updated when vm is powered off." - raise InvalidParameter(err) + msg_args = {'name': dom.name(), 'new_name': params['name']} + raise InvalidParameter("KCHVM0003E", msg_args) else: dom.undefine() conn = self.conn.get() dom = conn.defineXML(new_xml) except libvirt.libvirtError as e: dom = conn.defineXML(old_xml) - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVM0008E", {'name': dom.name(), + 'err': e.get_error_message()}) return dom def _live_vm_update(self, dom, params): @@ -308,8 +309,8 @@ class VMModel(object): except NotFoundError: return False except Exception, e: - err = "Unable to retrieve VM '%s': %s" - raise OperationFailed(err % (name, e.message)) + raise OperationFailed("KCHVM0009E", {'name': name, + 'err': e.message}) @staticmethod def get_vm(name, conn): @@ -319,7 +320,7 @@ class VMModel(object): return conn.lookupByName(name.encode("utf-8")) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: - raise NotFoundError("Virtual Machine '%s' not found" % name) + raise NotFoundError("KCHVM0002E", {'name': name}) else: raise @@ -384,8 +385,7 @@ class VMModel(object): if graphics_port is not None: vnc.add_proxy_token(name, graphics_port) else: - raise OperationFailed("Only able to connect to running vm's vnc " - "graphics.") + raise OperationFailed("KCHVM0010E", {'name': name}) def _vmscreenshot_delete(self, vm_uuid): screenshot = VMScreenshotModel.get_screenshot(vm_uuid, self.objstore, @@ -405,7 +405,7 @@ class VMScreenshotModel(object): d_info = dom.info() vm_uuid = dom.UUIDString() if DOM_STATE_MAP[d_info[0]] != 'running': - raise NotFoundError('No screenshot for stopped vm') + raise NotFoundError("KCHVM0004E", {'name': name}) screenshot = self.get_screenshot(vm_uuid, self.objstore, self.conn) img_path = screenshot.lookup() @@ -448,7 +448,7 @@ class LibvirtVMScreenshot(VMScreenshot): stream.abort() except: pass - raise NotFoundError("Screenshot not supported for %s" % vm_name) + raise NotFoundError("KCHVM0006E", {'name': vm_name}) else: stream.finish() finally: diff --git a/src/kimchi/objectstore.py b/src/kimchi/objectstore.py index 7b567f3..5cb8ae1 100644 --- a/src/kimchi/objectstore.py +++ b/src/kimchi/objectstore.py @@ -54,7 +54,7 @@ class ObjectStoreSession(object): jsonstr = res.fetchall()[0][0] except IndexError: self.conn.rollback() - raise NotFoundError(ident) + raise NotFoundError("KCHOBJST0001E", {'item': ident}) return json.loads(jsonstr) def delete(self, obj_type, ident, ignore_missing=False): @@ -63,7 +63,7 @@ class ObjectStoreSession(object): (obj_type, ident)) if c.rowcount != 1 and not ignore_missing: self.conn.rollback() - raise NotFoundError(ident) + raise NotFoundError("KCHOBJST0001E", {'item': ident}) self.conn.commit() def store(self, obj_type, ident, data): diff --git a/src/kimchi/template.py b/src/kimchi/template.py index 173e7c6..fd1d591 100644 --- a/src/kimchi/template.py +++ b/src/kimchi/template.py @@ -27,6 +27,7 @@ import json import os +from kimchi.config import paths from Cheetah.Template import Template from glob import iglob @@ -53,7 +54,6 @@ def get_lang(): def get_support_languages(): - paths = cherrypy.request.app.root.paths mopath = "%s/*" % paths.mo_dir return [path.rsplit('/', 1)[1] for path in iglob(mopath)] diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index 8795957..a1410c0 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -29,12 +29,10 @@ import urllib2 from threading import Timer from cherrypy.lib.reprconf import Parser -from kimchi.config import paths, PluginPaths -from kimchi.exception import TimeoutExpired - from kimchi.asynctask import AsyncTask -from kimchi.exception import InvalidParameter +from kimchi.config import paths, PluginPaths +from kimchi.exception import InvalidParameter, TimeoutExpired kimchi_log = cherrypy.log.error_log @@ -45,7 +43,7 @@ def _uri_to_name(collection, uri): expr = '/%s/(.*?)/?$' % collection m = re.match(expr, uri) if not m: - raise InvalidParameter(uri) + raise InvalidParameter("KCHUTILS0001E", {'uri': uri}) return m.group(1) @@ -169,7 +167,9 @@ def run_command(cmd, timeout=None): msg = ("subprocess is killed by signal.SIGKILL for " "timeout %s seconds" % timeout) kimchi_log.error(msg) - raise TimeoutExpired(msg) + + msg_args = {'cmd': cmd, 'seconds': timeout} + raise TimeoutExpired("KCHUTILS0002E", msg_args) return out, error, proc.returncode except TimeoutExpired: diff --git a/src/kimchi/vmtemplate.py b/src/kimchi/vmtemplate.py index 58147e3..7aa0a65 100644 --- a/src/kimchi/vmtemplate.py +++ b/src/kimchi/vmtemplate.py @@ -27,7 +27,6 @@ import urllib import urlparse -from kimchi import isoinfo from kimchi import osinfo from kimchi.exception import InvalidParameter, IsoFormatError from kimchi.isoinfo import IsoImage @@ -58,7 +57,7 @@ class VMTemplate(object): iso_prefixes = ['/', 'http', 'https', 'ftp', 'ftps', 'tftp'] if len(filter(iso.startswith, iso_prefixes)) == 0: - raise InvalidParameter("Invalid parameter specified for cdrom.") + raise InvalidParameter("KCHTMPL0006E", {'param': iso}) if not iso.startswith('/'): self.info.update({'iso_stream': True}) @@ -66,8 +65,8 @@ class VMTemplate(object): try: iso_img = IsoImage(iso) iso_distro, iso_version = iso_img.probe() - except IsoFormatError, e: - raise InvalidParameter(e) + except IsoFormatError: + raise InvalidParameter("KCHISO0001E", {'filename': iso}) # Fetch defaults based on the os distro and version os_distro = args.get('os_distro', iso_distro) diff --git a/tests/test_exception.py b/tests/test_exception.py index b64ab94..79c8e4f 100644 --- a/tests/test_exception.py +++ b/tests/test_exception.py @@ -77,8 +77,8 @@ class ExceptionTests(unittest.TestCase): # test 400 missing required parameter req = json.dumps({}) resp = json.loads(request(host, port, '/vms', req, 'POST').read()) - msg = u"Invalid parameter: 'u'template' is a required property'" self.assertEquals('400 Bad Request', resp.get('code')) + msg = u"KCHVM0016E: Specify a template to create a Virtual Machine from" self.assertEquals(msg, resp.get('reason')) self.assertNotIn('call_stack', resp) @@ -107,7 +107,7 @@ class ExceptionTests(unittest.TestCase): # test 400 missing required parameter req = json.dumps({}) resp = json.loads(request(host, port, '/vms', req, 'POST').read()) - msg = u"Invalid parameter: 'u'template' is a required property'" + msg = u"KCHVM0016E: Specify a template to create a Virtual Machine from" self.assertEquals('400 Bad Request', resp.get('code')) self.assertEquals(msg, resp.get('reason')) self.assertIn('call_stack', resp) diff --git a/tests/test_rest.py b/tests/test_rest.py index 0ed293b..4b58e18 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -568,7 +568,7 @@ class RestTests(unittest.TestCase): resp = self.request('/vms', req, 'POST') self.assertEquals(400, resp.status) resp = json.loads(resp.read()) - self.assertIn('Invalid parameter', resp['reason']) + self.assertIn(u"KCHVM0016E:", resp['reason']) def test_create_vm_with_bad_template_uri(self): req = json.dumps({'name': 'vm-bad-template', @@ -576,7 +576,7 @@ class RestTests(unittest.TestCase): resp = self.request('/vms', req, 'POST') self.assertEquals(400, resp.status) resp = json.loads(resp.read()) - self.assertIn('Invalid parameter', resp['reason']) + self.assertIn(u"KCHVM0012E", resp['reason']) def test_get_storagepools(self): storagepools = json.loads(self.request('/storagepools').read()) diff --git a/tests/utils.py b/tests/utils.py index 40dfae2..14c57d4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -155,8 +155,9 @@ def patch_auth(): def _authenticate(username, password, service="passwd"): try: return fake_user[username] == password - except KeyError: - raise OperationFailed('Bad login') + except KeyError, e: + raise OperationFailed("KCHAUTH0001E", {'userid': 'username', + 'code': e.message}) import kimchi.auth kimchi.auth.authenticate = _authenticate -- 1.7.10.4

On 02/09/2014 08:47 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Update all Kimchi exceptions to translate backend messages. Use message code to get the correct messages in i18n.py and raise a message like: "<code>: <translated-message>"
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/model.py | 12 ++-- src/kimchi/asynctask.py | 4 +- src/kimchi/auth.py | 3 +- src/kimchi/disks.py | 5 +- src/kimchi/distroloader.py | 5 +- src/kimchi/exception.py | 14 ++-- src/kimchi/iscsi.py | 6 +- src/kimchi/isoinfo.py | 17 +++-- src/kimchi/mockmodel.py | 113 +++++++++++++++++++------------- src/kimchi/model/config.py | 2 +- src/kimchi/model/debugreports.py | 18 ++--- src/kimchi/model/host.py | 10 +-- src/kimchi/model/interfaces.py | 4 +- src/kimchi/model/libvirtstoragepool.py | 14 ++-- src/kimchi/model/networks.py | 37 ++++++----- src/kimchi/model/storagepools.py | 39 ++++++----- src/kimchi/model/storageservers.py | 2 +- src/kimchi/model/storagevolumes.py | 37 ++++++----- src/kimchi/model/templates.py | 44 ++++++------- src/kimchi/model/utils.py | 2 +- src/kimchi/model/vmifaces.py | 15 ++--- src/kimchi/model/vms.py | 28 ++++---- src/kimchi/objectstore.py | 4 +- src/kimchi/template.py | 2 +- src/kimchi/utils.py | 12 ++-- src/kimchi/vmtemplate.py | 7 +- tests/test_exception.py | 4 +- tests/test_rest.py | 4 +- tests/utils.py | 5 +- 29 files changed, 255 insertions(+), 214 deletions(-)
diff --git a/plugins/sample/model.py b/plugins/sample/model.py index 184864d..f7ca319 100644 --- a/plugins/sample/model.py +++ b/plugins/sample/model.py @@ -31,7 +31,7 @@ class CirclesModel(object): def create(self, params): name = params['name'] if name in self._circles: - raise InvalidOperation("Circle %s already exists" % name) + raise InvalidOperation("SPCIRCLE0001E", {'name': name}) self._circles[name] = Circle(params['radius']) return name
@@ -48,12 +48,12 @@ class CircleModel(object): try: circle = self._circles[name] except KeyError: - raise NotFoundError("Circle %s not found" % name) + raise NotFoundError("SPCIRC0002E", {'name': name}) return {'radius': circle.radius}
def update(self, name, params): if name not in self._circles: - raise NotFoundError("Circle %s not found" % name) + raise NotFoundError("SPCIRC0002E", {'name': name}) self._circles[name].radius = params['radius'] return name
@@ -71,7 +71,7 @@ class RectanglesModel(object): def create(self, params): name = params['name'] if name in self._rectangles: - raise InvalidOperation("Rectangle %s already exists" % name) + raise InvalidOperation("SPRET0001E", {'name': name}) self._rectangles[name] = Rectangle(params['length'], params['width']) return name
@@ -87,12 +87,12 @@ class RectangleModel(object): try: rectangle = self._rectangles[name] except KeyError: - raise NotFoundError("Rectangle %s not found" % name) + raise NotFoundError("SPRET0002E", {'name': name}) return {'length': rectangle.length, 'width': rectangle.width}
def update(self, name, params): if name not in self._rectangles: - raise NotFoundError("Rectangle %s not found" % name) + raise NotFoundError("SPRET0002E", {'name': name}) try: self._rectangles[name].length = params['length'] except KeyError: diff --git a/src/kimchi/asynctask.py b/src/kimchi/asynctask.py index 4ff76e4..f5cba50 100644 --- a/src/kimchi/asynctask.py +++ b/src/kimchi/asynctask.py @@ -31,8 +31,8 @@ from kimchi.exception import OperationFailed class AsyncTask(object): def __init__(self, id, target_uri, fn, objstore, opaque=None): if objstore is None: - raise OperationFailed("Datastore is not initiated in " - "the model object") + raise OperationFailed("KCHASYNC0001E") + self.id = str(id) self.target_uri = target_uri self.fn = fn diff --git a/src/kimchi/auth.py b/src/kimchi/auth.py index 242fdcf..1cae45d 100644 --- a/src/kimchi/auth.py +++ b/src/kimchi/auth.py @@ -68,7 +68,8 @@ def authenticate(username, password, service="passwd"): try: auth.authenticate() except PAM.error, (resp, code): - raise OperationFailed(resp, code) + msg_args = {'userid': username, 'code': code} + raise OperationFailed("KCHAUTH0001E", msg_args)
return True
diff --git a/src/kimchi/disks.py b/src/kimchi/disks.py index 941aaca..83d5cc6 100644 --- a/src/kimchi/disks.py +++ b/src/kimchi/disks.py @@ -44,7 +44,7 @@ def _get_lsblk_devs(keys, devs=[]): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = lsblk.communicate() if lsblk.returncode != 0: - raise OperationFailed('Error executing lsblk: %s' % err) + raise OperationFailed("KCHDISKS0001E", {'err': err})
return _parse_lsblk_output(out, keys)
@@ -60,8 +60,7 @@ def _get_dev_major_min(name): maj_min = dev['maj:min'] break else: - msg = "Failed to find major and minor number for %s" % name - raise OperationFailed(msg) + raise OperationFailed("KCHDISKS0002E", {'device': name})
return maj_min
diff --git a/src/kimchi/distroloader.py b/src/kimchi/distroloader.py index 98fd764..f0b0208 100644 --- a/src/kimchi/distroloader.py +++ b/src/kimchi/distroloader.py @@ -37,10 +37,11 @@ class DistroLoader(object): self.location = location or config.get_distros_store()
def _get_json_info(self, fname): + msg_args = {'filename': fname} if not os.path.isfile(fname): msg = "DistroLoader: failed to find distro file: %s" % fname kimchi_log.error(msg) - raise NotFoundError(msg) + raise NotFoundError("KCHDL0001E", msg_args) try: with open(fname) as f: data = json.load(f) @@ -48,7 +49,7 @@ class DistroLoader(object): except ValueError: msg = "DistroLoader: failed to parse distro file: %s" % fname kimchi_log.error(msg) - raise OperationFailed(msg) + raise OperationFailed("KCHDL0002E", msg_args)
def get(self): all_json_files = glob.glob("%s/%s" % (self.location, "*.json")) diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py index 7fcce54..952e243 100644 --- a/src/kimchi/exception.py +++ b/src/kimchi/exception.py @@ -49,29 +49,29 @@ class KimchiException(Exception): Exception.__init__(self, pattern)
-class NotFoundError(Exception): +class NotFoundError(KimchiException): pass
-class OperationFailed(Exception): +class OperationFailed(KimchiException): pass
-class MissingParameter(Exception): +class MissingParameter(KimchiException): pass
-class InvalidParameter(Exception): +class InvalidParameter(KimchiException): pass
-class InvalidOperation(Exception): +class InvalidOperation(KimchiException): pass
-class IsoFormatError(Exception): +class IsoFormatError(KimchiException): pass
-class TimeoutExpired(Exception): +class TimeoutExpired(KimchiException): pass diff --git a/src/kimchi/iscsi.py b/src/kimchi/iscsi.py index 35c0b8a..248188c 100644 --- a/src/kimchi/iscsi.py +++ b/src/kimchi/iscsi.py @@ -55,7 +55,8 @@ class TargetClient(object): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = iscsiadm.communicate() if iscsiadm.returncode != 0: - raise OperationFailed('Error executing iscsiadm: %s' % err) + msg_args = {'portal': self.portal, 'err': err} + raise OperationFailed("KCHISCSI0001E", msg_args) return out
def _discover(self): @@ -65,7 +66,8 @@ class TargetClient(object): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = iscsiadm.communicate() if iscsiadm.returncode != 0: - raise OperationFailed('Error executing iscsiadm: %s' % err) + msg_args = {'portal': self.portal, 'err': err} + raise OperationFailed("KCHISCSI0001E", msg_args) return out
def _run_op(self, op): diff --git a/src/kimchi/isoinfo.py b/src/kimchi/isoinfo.py index a3cd4cd..5629391 100644 --- a/src/kimchi/isoinfo.py +++ b/src/kimchi/isoinfo.py @@ -149,11 +149,11 @@ class IsoImage(object): if check_url_path(self.path): return True
- raise IsoFormatError('ISO %s does not exist' % self.path) + raise IsoFormatError("KCHISO0001E", {'filename': self.path})
def probe(self): if not self.bootable: - raise IsoFormatError("ISO %s not bootable" % self.path) + raise IsoFormatError("KCHISO0002E", {'filename': self.path})
matcher = Matcher(self.volume_id)
@@ -197,7 +197,8 @@ class IsoImage(object): if vd_type == 0: # Found El-Torito Boot Record break if not et_ident.startswith('EL TORITO SPECIFICATION'): - raise IsoFormatError("Invalid El Torito boot record") + raise IsoFormatError("KCHISO0003E", + {'filename': self.path})
offset = IsoImage.SECTOR_SIZE * boot_cat size = IsoImage.EL_TORITO_VALIDATION_ENTRY.size + \ @@ -210,7 +211,8 @@ class IsoImage(object): (hdr_id, platform_id, pad0, ident, csum, key55, keyAA) = self._unpack(fmt, tmp_data) if key55 != 0x55 or keyAA != 0xaa: - raise IsoFormatError("Invalid El Torito validation entry") + raise IsoFormatError("KCHISO0004E", + {'filename': self.path})
fmt = IsoImage.EL_TORITO_BOOT_ENTRY tmp_data = data[ptr:ptr+fmt.size] @@ -221,7 +223,8 @@ class IsoImage(object): elif boot == 0: self.bootable = False else: - raise IsoFormatError("Invalid El Torito boot indicator") + raise IsoFormatError("KCHISO0005E", + {'filename': self.path})
def _scan_primary_vol(self, data): """ @@ -232,9 +235,9 @@ class IsoImage(object): info = self._unpack(IsoImage.VOL_DESC, primary_vol_data) (vd_type, vd_ident, vd_ver, pad0, sys_id, vol_id) = info if vd_type != 1: - raise IsoFormatError("Unexpected volume type for primary volume") + raise IsoFormatError("KCHISO0006E", {'filename': self.path}) if vd_ident != 'CD001' or vd_ver != 1: - raise IsoFormatError("Bad format while reading volume descriptor") + raise IsoFormatError("KCHISO0007E", {'filename': self.path}) self.volume_id = vol_id
def _get_iso_data(self, offset, size): diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index 4e276eb..e5425b2 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -83,7 +83,8 @@ class MockModel(object):
if 'name' in params: if state == 'running' or params['name'] in self.vms_get_list(): - raise InvalidParameter("VM name existed or vm not shutoff.") + msg_args = {'name': dom.name, 'new_name': params['name']} + raise InvalidParameter("KCHVM0003E", msg_args) else: del self._mock_vms[dom.name] dom.name = params['name'] @@ -134,7 +135,7 @@ class MockModel(object): name = get_vm_name(params.get('name'), t_name, self._mock_vms.keys()) if name in self._mock_vms: - raise InvalidOperation("VM already exists") + raise InvalidOperation("KCHVM0001E", {'name': name})
vm_uuid = str(uuid.uuid4()) vm_overrides = dict() @@ -166,7 +167,8 @@ class MockModel(object): def vmscreenshot_lookup(self, name): vm = self._get_vm(name) if vm.info['state'] != 'running': - raise NotFoundError('No screenshot for stopped vm') + raise NotFoundError("KCHVM0004E", {'name': name}) + screenshot = self._mock_screenshots.setdefault( vm.uuid, MockVMScreenshot({'uuid': vm.uuid})) return screenshot.lookup() @@ -185,18 +187,19 @@ class MockModel(object): try: del self._mock_templates[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHTMPL0002E", {'name': name})
def templates_create(self, params): name = params['name'] if name in self._mock_templates: - raise InvalidOperation("Template already exists") + raise InvalidOperation("KCHTMPL0001E", {'name': name}) + for net_name in params.get(u'networks', []): try: self._get_network(net_name) except NotFoundError: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + msg_args = {'network': net_name, 'template': name} + raise InvalidParameter("KCHTMPL0003E", msg_args)
t = MockVMTemplate(params, self) self._mock_templates[name] = t @@ -212,15 +215,16 @@ class MockModel(object): new_storagepool = new_t.get(u'storagepool', '') try: self._get_storagepool(pool_name_from_uri(new_storagepool)) - except Exception as e: - raise InvalidParameter("Storagepool specified is not valid: %s." % e.message) + except Exception: + msg_args = {'pool': new_storagepool, 'template': name} + raise InvalidParameter("KCHTMPL0004E", msg_args)
for net_name in params.get(u'networks', []): try: self._get_network(net_name) except NotFoundError: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + msg_args = {'network': net_name, 'template': name} + raise InvalidParameter("KCHTMPL0003E", msg_args)
self.template_delete(name) try: @@ -243,7 +247,7 @@ class MockModel(object): else: return t except KeyError: - raise NotFoundError() + raise NotFoundError("KCHTMPL0002E", {'name': name})
def debugreport_lookup(self, name): path = config.get_debugreports_path() @@ -251,7 +255,7 @@ class MockModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name', name})
ctime = os.stat(file_target).st_ctime ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) @@ -269,7 +273,7 @@ class MockModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name', name})
os.remove(file_target)
@@ -291,7 +295,7 @@ class MockModel(object): try: return self._mock_vms[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHVM0002E", {'name': name})
def storagepools_create(self, params): try: @@ -304,9 +308,12 @@ class MockModel(object): else: pool.info['autostart'] = False except KeyError, item: - raise MissingParameter(item) + raise MissingParameter("KCHPOOL0004E", + {'item': item, 'name': name}) + if name in self._mock_storagepools or name in (ISO_POOL_NAME,): - raise InvalidOperation("StoragePool already exists") + raise InvalidOperation("KCHPOOL0001E", {'name': name}) + self._mock_storagepools[name] = pool return name
@@ -318,7 +325,8 @@ class MockModel(object): def storagepool_update(self, name, params): autostart = params['autostart'] if autostart not in [True, False]: - raise InvalidOperation("Autostart flag must be true or false") + raise InvalidOperation("KCHPOOL0003E") + storagepool = self._get_storagepool(name) storagepool.info['autostart'] = autostart ident = storagepool.name @@ -342,12 +350,15 @@ class MockModel(object): try: return self._mock_storagepools[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHPOOL0002E", {'name': name})
def storagevolumes_create(self, pool_name, params): pool = self._get_storagepool(pool_name) if pool.info['state'] == 'inactive': - raise InvalidOperation("StoragePool not active") + raise InvalidOperation("KCHVOL0003E", + {'pool': pool_name, + 'volume': params['name']}) + try: name = params['name'] volume = MockStorageVolume(pool, name, params) @@ -356,15 +367,20 @@ class MockModel(object): volume.info['path'] = os.path.join( pool.info['path'], name) except KeyError, item: - raise MissingParameter(item) + raise MissingParameter("KCHVOL0004E", + {'item': item, 'volume': name}) + if name in pool._volumes: - raise InvalidOperation("StorageVolume already exists") + raise InvalidOperation("KCHVOL0001E", {'name': name}) + pool._volumes[name] = volume return name
def storagevolume_lookup(self, pool, name): if self._get_storagepool(pool).info['state'] != 'active': - raise InvalidOperation("StoragePool %s is not active" % pool) + raise InvalidOperation("KCHVOL0005E", {'pool': pool, + 'volume': name}) + storagevolume = self._get_storagevolume(pool, name) return storagevolume.info
@@ -384,8 +400,7 @@ class MockModel(object): def storagevolumes_get_list(self, pool): res = self._get_storagepool(pool) if res.info['state'] == 'inactive': - raise InvalidOperation( - "Unable to list volumes of inactive storagepool %s" % pool) + raise InvalidOperation("KCHVOL0006E", {'pool': pool}) return res._volumes.keys()
def isopool_lookup(self, name): @@ -438,7 +453,7 @@ class MockModel(object): # Avoid inconsistent pool result because of lease between list and lookup pass
- raise NotFoundError("storage server %s not used by kimchi" % server) + raise NotFoundError("KCHSR0001E", {'server': server})
def dummy_interfaces(self): interfaces = {} @@ -461,7 +476,8 @@ class MockModel(object): def networks_create(self, params): name = params['name'] if name in self.networks_get_list(): - raise InvalidOperation("Network %s already exists" % name) + raise InvalidOperation("KCHNET0001E", {'name': name}) + network = MockNetwork(name) connection = params['connection'] network.info['connection'] = connection @@ -469,22 +485,23 @@ class MockModel(object): try: interface = params['interface'] network.info['interface'] = interface - except KeyError, key: - raise MissingParameter(key) + except KeyError: + raise MissingParameter("KCHNET0004E", + {'name': name})
subnet = params.get('subnet', '') if subnet: network.info['subnet'] = subnet try: net = ipaddr.IPNetwork(subnet) - except ValueError, e: - raise InvalidParameter(e) + except ValueError: + msg_args = {'subnet':subnet, 'network': name} + raise InvalidParameter("KCHNET0003E", msg_args)
network.info['dhcp'] = { 'start': str(net.network + net.numhosts / 2), 'stop': str(net.network + net.numhosts - 2)} - if name in self._mock_networks: - raise InvalidOperation("Network already exists") + self._mock_networks[name] = network return name
@@ -492,7 +509,7 @@ class MockModel(object): try: return self._mock_networks[name] except KeyError: - raise NotFoundError("Network '%s'" % name) + raise NotFoundError("KCHNET0002E", {'name': name})
def _get_vms_attach_to_a_network(self, network): vms = [] @@ -523,8 +540,9 @@ class MockModel(object): def vmifaces_create(self, vm, params): if (params["type"] == "network" and params["network"] not in self.networks_get_list()): - raise InvalidParameter("%s is not an available network" % - params["network"]) + msg_args = {'network': params["network"], 'name': vm} + raise InvalidParameter("KCHVMIF0002E", msg_args) + dom = self._get_vm(vm) iface = MockVMIface(params["network"]) ("model" in params.keys() and @@ -544,7 +562,7 @@ class MockModel(object): try: info = dom.ifaces[mac].info except KeyError: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'iface': mac, 'name': vm}) return info
def vmiface_delete(self, vm, mac): @@ -552,7 +570,7 @@ class MockModel(object): try: del dom.ifaces[mac] except KeyError: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'iface': mac, 'name': vm})
def tasks_get_list(self): with self.objstore as session: @@ -573,7 +591,7 @@ class MockModel(object): try: return self._get_storagepool(pool)._volumes[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHVOL0002E", {'name': name, 'pool': pool})
def _get_distros(self): distroloader = DistroLoader() @@ -586,7 +604,7 @@ class MockModel(object): try: return self.distros[name] except KeyError: - raise NotFoundError("distro '%s' not found" % name) + raise NotFoundError("KCHDISTRO0001E", {'name': name})
def _gen_debugreport_file(self, ident): return self.add_task('', self._create_log, ident) @@ -638,14 +656,14 @@ class MockModel(object): # Check for running vms before shutdown running_vms = self.vms_get_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Shutdown not allowed: VMs are running!") + raise OperationFailed("KCHHOST0001E") cherrypy.engine.exit()
def host_reboot(self, args=None): # Find running VMs running_vms = self.vms_get_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Reboot not allowed: VMs are running!") + raise OperationFailed("KCHHOST0002E") cherrypy.engine.stop() time.sleep(10) cherrypy.engine.start() @@ -656,8 +674,8 @@ class MockModel(object):
def partition_lookup(self, name): if name not in disks.get_partitions_names(): - raise NotFoundError("Partition %s not found in the host" - % name) + raise NotFoundError("KCHPART0001E", {'name': name}) + return disks.get_partition_details(name)
def config_lookup(self, name): @@ -677,9 +695,12 @@ class MockVMTemplate(VMTemplate): try: pool = self.model._get_storagepool(pool_name) except NotFoundError: - raise InvalidParameter('Storage specified by template does not exist') + msg_args = {'pool': pool_name, 'template': self.name} + raise InvalidParameter("KCHTMPL0004E", msg_args) + if pool.info['state'] != 'active': - raise InvalidParameter('Storage specified by template is not active') + msg_args = {'pool': pool_name, 'template': self.name} + raise InvalidParameter("KCHTMPL0005E", msg_args)
return pool
diff --git a/src/kimchi/model/config.py b/src/kimchi/model/config.py index 0e66e02..9b5814a 100644 --- a/src/kimchi/model/config.py +++ b/src/kimchi/model/config.py @@ -95,4 +95,4 @@ class DistroModel(object): try: return self._distros.distros[name] except KeyError: - raise NotFoundError("Distro '%s' not found." % name) + raise NotFoundError("KCHDISTRO0001E", {'name': name}) diff --git a/src/kimchi/model/debugreports.py b/src/kimchi/model/debugreports.py index a1cb19c..2c5b13a 100644 --- a/src/kimchi/model/debugreports.py +++ b/src/kimchi/model/debugreports.py @@ -59,7 +59,7 @@ class DebugReportsModel(object): if gen_cmd is not None: return add_task('', gen_cmd, self.objstore, name)
- raise OperationFailed("debugreport tool not found") + raise OperationFailed("KCHDR0002E")
@staticmethod def sosreport_generate(cb, name): @@ -68,9 +68,11 @@ class DebugReportsModel(object): retcode = subprocess.call(command, shell=True, stdout=subprocess.PIPE) if retcode < 0: - raise OperationFailed('Command terminated with signal') + raise OperationFailed("KCHDR0003E", {'name': name, + 'err': retcode}) elif retcode > 0: - raise OperationFailed('Command failed: rc = %i' % retcode) + raise OperationFailed("KCHDR0003E", {'name': name, + 'err': retcode}) pattern = '/tmp/sosreport-%s-*' % name for reportFile in glob.glob(pattern): if not fnmatch.fnmatch(reportFile, '*.md5'): @@ -83,8 +85,8 @@ class DebugReportsModel(object): # runs successfully. In future we might have a general name # mangling function in kimchi to format the name before passing # it to sosreport. Then we can delete this exception. - raise OperationFailed('Can not find generated debug report ' - 'named by %s' % pattern) + raise OperationFailed("KCHDR0004E", {'name': pattern}) + ext = output.split('.', 1)[1] path = config.get_debugreports_path() target = os.path.join(path, name) @@ -104,7 +106,7 @@ class DebugReportsModel(object): # and update the task status there log = logging.getLogger('Model') log.warning('Exception in generating debug file: %s', e) - raise OperationFailed(e) + raise OperationFailed("KCHDR0005E", {'name': name, 'err': e})
@staticmethod def get_system_report_tool(): @@ -139,7 +141,7 @@ class DebugReportModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name': name})
ctime = os.stat(file_target).st_ctime ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) @@ -154,7 +156,7 @@ class DebugReportModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name': name})
os.remove(file_target)
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index a3d9e38..80f93db 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -67,7 +67,8 @@ class HostModel(object): # Check for running vms before shutdown running_vms = self._get_vms_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Shutdown not allowed: VMs are running!") + raise OperationFailed("KCHHOST0001E") + kimchi_log.info('Host is going to shutdown.') os.system('shutdown -h now')
@@ -75,7 +76,8 @@ class HostModel(object): # Find running VMs running_vms = self._get_vms_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Reboot not allowed: VMs are running!") + raise OperationFailed("KCHHOST0002E") + kimchi_log.info('Host is going to reboot.') os.system('reboot')
@@ -196,6 +198,6 @@ class PartitionModel(object):
def lookup(self, name): if name not in disks.get_partitions_names(): - raise NotFoundError("Partition %s not found in the host" - % name) + raise NotFoundError("KCHPART0001E", {'name': name}) + return disks.get_partition_details(name) diff --git a/src/kimchi/model/interfaces.py b/src/kimchi/model/interfaces.py index 52c6bae..96b1261 100644 --- a/src/kimchi/model/interfaces.py +++ b/src/kimchi/model/interfaces.py @@ -42,5 +42,5 @@ class InterfaceModel(object): def lookup(self, name): try: return netinfo.get_interface_info(name) - except ValueError, e: - raise NotFoundError(e) + except ValueError: + raise NotFoundError("KCHIFACE0001E", {'name': name}) diff --git a/src/kimchi/model/libvirtstoragepool.py b/src/kimchi/model/libvirtstoragepool.py index f4dbf2e..f9b395c 100644 --- a/src/kimchi/model/libvirtstoragepool.py +++ b/src/kimchi/model/libvirtstoragepool.py @@ -38,7 +38,7 @@ class StoragePoolDef(object): for klass in cls.__subclasses__(): if poolArgs['type'] == klass.poolType: return klass(poolArgs) - raise OperationFailed('Unsupported pool type: %s' % poolArgs['type']) + raise OperationFailed("KCHPOOL0014E", {'type': poolArgs['type']})
def __init__(self, poolArgs): self.poolArgs = poolArgs @@ -56,7 +56,7 @@ class StoragePoolDef(object): idempotent''' # TODO: When add new pool type, should also add the related test in # tests/test_storagepool.py - raise OperationFailed('self.xml is not implemented: %s' % self) + raise OperationFailed("KCHPOOL0015E", {'pool': self})
class DirPoolDef(StoragePoolDef): @@ -101,8 +101,7 @@ class NetfsPoolDef(StoragePoolDef): run_command(mount_cmd, 30) rollback.prependDefer(run_command, umount_cmd) except TimeoutExpired: - err = "Export path %s may block during nfs mount" - raise InvalidParameter(err % export_path) + raise InvalidParameter("KCHPOOL0012E", {'path': export_path})
with open("/proc/mounts", "rb") as f: rawMounts = f.read() @@ -113,8 +112,7 @@ class NetfsPoolDef(StoragePoolDef): mounted = True
if not mounted: - err = "Export path %s mount failed during nfs mount" - raise InvalidParameter(err % export_path) + raise InvalidParameter("KCHPOOL0013E", {'path': export_path})
@property def xml(self): @@ -181,8 +179,8 @@ class IscsiPoolDef(StoragePoolDef): def prepare(self, conn): source = self.poolArgs['source'] if not TargetClient(**source).validate(): - raise OperationFailed("Can not login to iSCSI host %s target %s" % - (source['host'], source['target'])) + msg_args = {'host': source['host'], 'target': source['target']} + raise OperationFailed("KCHISCSI0002E", msg_args) self._prepare_auth(conn)
def _prepare_auth(self, conn): diff --git a/src/kimchi/model/networks.py b/src/kimchi/model/networks.py index b164141..05105df 100644 --- a/src/kimchi/model/networks.py +++ b/src/kimchi/model/networks.py @@ -39,7 +39,7 @@ class NetworksModel(object): conn = self.conn.get() name = params['name'] if name in self.get_list(): - raise InvalidOperation("Network %s already exists" % name) + raise InvalidOperation("KCHNET0001E", {'name': name})
connection = params["connection"] # set forward mode, isolated do not need forward @@ -60,7 +60,8 @@ class NetworksModel(object): network = conn.networkDefineXML(xml) network.setAutostart(True) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHNET0008E", + {'name': name, 'err': e.get_error_message()})
return name
@@ -80,13 +81,13 @@ class NetworksModel(object): subnet and net_addrs.append(ipaddr.IPNetwork(subnet)) netaddr = knetwork.get_one_free_network(net_addrs) if not netaddr: - raise OperationFailed("can not find a free IP address for " - "network '%s'" % params['name']) + raise OperationFailed("KCHNET0009E", {'name': params['name']})
try: ip = ipaddr.IPNetwork(netaddr) - except ValueError as e: - raise InvalidParameter("%s" % e) + except ValueError: + raise InvalidParameter("KCHNET0003E", {'subent': netaddr, + 'network': params['name']})
if ip.ip == ip.network: ip.ip = ip.ip + 1 @@ -101,10 +102,11 @@ class NetworksModel(object): try: iface = params['interface'] if iface in self.get_all_networks_interfaces(): - raise InvalidParameter("interface '%s' already in use." % - iface) - except KeyError, e: - raise MissingParameter(e) + msg_args = {'iface': iface, 'network': params['name']} + raise InvalidParameter("KCHNET0006E", msg_args) + except KeyError: + raise MissingParameter("KCHNET0004E", {'name': params['name']}) + if netinfo.is_bridge(iface): params['bridge'] = iface elif netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface): @@ -115,8 +117,7 @@ class NetworksModel(object): self._create_vlan_tagged_bridge(str(iface), str(params['vlan_id'])) else: - raise InvalidParameter("the interface should be bare nic, " - "bonding or bridge device.") + raise InvalidParameter("KCHNET0007E")
def get_all_networks_interfaces(self): net_names = self.get_list() @@ -144,7 +145,8 @@ class NetworksModel(object): vlan_tagged_br.create() except libvirt.libvirtError as e: conn.changeRollback() - raise OperationFailed(e.message) + raise OperationFailed("KCHNET0010E", {'iface': interface, + 'err': e.message}) else: conn.changeCommit() return br_name @@ -211,8 +213,8 @@ class NetworkModel(object): def delete(self, name): network = self._get_network(name) if network.isActive(): - raise InvalidOperation( - "Unable to delete the active network %s" % name) + raise InvalidOperation("KCHNET0005E", {'name': name}) + self._remove_vlan_tagged_bridge(network) network.undefine()
@@ -220,9 +222,8 @@ class NetworkModel(object): conn = self.conn.get() try: return conn.networkLookupByName(name) - except libvirt.libvirtError as e: - raise NotFoundError("Network '%s' not found: %s" % - (name, e.get_error_message())) + except libvirt.libvirtError: + raise NotFoundError("KCHNET0002E", {'name': name})
@staticmethod def get_network_from_xml(xml): diff --git a/src/kimchi/model/storagepools.py b/src/kimchi/model/storagepools.py index 233a8a7..fa73ce9 100644 --- a/src/kimchi/model/storagepools.py +++ b/src/kimchi/model/storagepools.py @@ -55,7 +55,8 @@ class StoragePoolsModel(object): names += conn.listDefinedStoragePools() return sorted(names) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0006E", + {'err': e.get_error_message()})
def create(self, params): task_id = None @@ -63,19 +64,19 @@ class StoragePoolsModel(object): try: name = params['name'] if name in (ISO_POOL_NAME, ): - raise InvalidOperation("StoragePool already exists") + raise InvalidOperation("KCHPOOL0001E", {'name': name})
if params['type'] == 'kimchi-iso': task_id = self._do_deep_scan(params) poolDef = StoragePoolDef.create(params) poolDef.prepare(conn) xml = poolDef.xml - except KeyError, key: - raise MissingParameter(key) + except KeyError, item: + raise MissingParameter("KCHPOOL0004E", + {'item': item, 'name': name})
if name in self.get_list(): - err = "The name %s has been used by a pool" - raise InvalidOperation(err % name) + raise InvalidOperation("KCHPOOL0001E", {'name': name})
try: if task_id: @@ -92,9 +93,9 @@ class StoragePoolsModel(object): # disable autostart for others pool.setAutostart(0) except libvirt.libvirtError as e: - msg = "Problem creating Storage Pool: %s" - kimchi_log.error(msg, e) - raise OperationFailed(e.get_error_message()) + kimchi_log.error("Problem creating Storage Pool: %s", e) + raise OperationFailed("KCHPOOL0007E", + {'name': name, 'err': e.get_error_message()}) return name
def _clean_scan(self, pool_name): @@ -144,7 +145,7 @@ class StoragePoolModel(object): return conn.storagePoolLookupByName(name) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL: - raise NotFoundError("Storage Pool '%s' not found" % name) + raise NotFoundError("KCHTMPL0002E", {'name': name}) else: raise
@@ -156,7 +157,8 @@ class StoragePoolModel(object): else: return 0 except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0008E", + {'name': pool, 'err': e.get_error_message()})
def _get_storage_source(self, pool_type, pool_xml): source = {} @@ -203,7 +205,8 @@ class StoragePoolModel(object): def update(self, name, params): autostart = params['autostart'] if autostart not in [True, False]: - raise InvalidOperation("Autostart flag must be true or false") + raise InvalidOperation("KCHPOOL0003E") + pool = self.get_storagepool(name, self.conn) if autostart: pool.setAutostart(1) @@ -217,24 +220,26 @@ class StoragePoolModel(object): try: pool.create(0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0009E", + {'name': name, 'err': e.get_error_message()})
def deactivate(self, name): pool = self.get_storagepool(name, self.conn) try: pool.destroy() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0010E", + {'name': name, 'err': e.get_error_message()})
def delete(self, name): pool = self.get_storagepool(name, self.conn) if pool.isActive(): - err = "Unable to delete the active storagepool %s" - raise InvalidOperation(err % name) + raise InvalidOperation("KCHPOOL0005E", {'name': name}) try: pool.undefine() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0011E", + {'name': name, 'err': e.get_error_message()})
class IsoPoolModel(object): diff --git a/src/kimchi/model/storageservers.py b/src/kimchi/model/storageservers.py index 6a7c14a..26e1f6f 100644 --- a/src/kimchi/model/storageservers.py +++ b/src/kimchi/model/storageservers.py @@ -75,4 +75,4 @@ class StorageServerModel(object): # lookup pass
- raise NotFoundError('server %s does not used by kimchi' % server) + raise NotFoundError("KCHSR0001E", {'server': server}) diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py index 8440a76..e3f00ca 100644 --- a/src/kimchi/model/storagevolumes.py +++ b/src/kimchi/model/storagevolumes.py @@ -57,29 +57,33 @@ class StorageVolumesModel(object): params.setdefault('allocation', 0) params.setdefault('format', 'qcow2')
+ name = params['name'] try: pool = StoragePoolModel.get_storagepool(pool, self.conn) - name = params['name'] xml = vol_xml % params - except KeyError, key: - raise MissingParameter(key) + except KeyError, item: + raise MissingParameter("KCHVOL0004E", {'item': item, + 'volume': name})
try: pool.createXML(xml, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0007E", + {'name': name, 'pool': pool, + 'err': e.get_error_message()}) return name
- def get_list(self, pool): - pool = StoragePoolModel.get_storagepool(pool, self.conn) + def get_list(self, pool_name): + pool = StoragePoolModel.get_storagepool(pool_name, self.conn) if not pool.isActive(): - err = "Unable to list volumes in inactive storagepool %s" - raise InvalidOperation(err % pool.name()) + raise InvalidOperation("KCHVOL0006E", {'pool': pool_name}) try: pool.refresh(0) return pool.listVolumes() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0008E", + {'pool': pool_name, + 'err': e.get_error_message()})
class StorageVolumeModel(object): @@ -89,13 +93,13 @@ class StorageVolumeModel(object): def _get_storagevolume(self, pool, name): pool = StoragePoolModel.get_storagepool(pool, self.conn) if not pool.isActive(): - err = "Unable to list volumes in inactive storagepool %s" - raise InvalidOperation(err % pool.name()) + raise InvalidOperation("KCHVOL0006E", {'name': pool}) try: return pool.storageVolLookupByName(name) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL: - raise NotFoundError("Storage Volume '%s' not found" % name) + raise NotFoundError("KCHVOL0002E", {'name': name, + 'pool': pool}) else: raise
@@ -131,14 +135,16 @@ class StorageVolumeModel(object): try: volume.wipePattern(libvirt.VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0009E", + {'name': name, 'err': e.get_error_message()})
def delete(self, pool, name): volume = self._get_storagevolume(pool, name) try: volume.delete(0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0010E", + {'name': name, 'err': e.get_error_message()})
def resize(self, pool, name, size): size = size << 20 @@ -146,7 +152,8 @@ class StorageVolumeModel(object): try: volume.resize(size, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0011E", + {'name': name, 'err': e.get_error_message()})
class IsoVolumesModel(object): diff --git a/src/kimchi/model/templates.py b/src/kimchi/model/templates.py index 03632a6..0eb7faa 100644 --- a/src/kimchi/model/templates.py +++ b/src/kimchi/model/templates.py @@ -25,7 +25,7 @@ import copy import libvirt
from kimchi import xmlutils -from kimchi.exception import InvalidOperation, InvalidParameter, NotFoundError +from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.utils import pool_name_from_uri from kimchi.vmtemplate import VMTemplate
@@ -44,20 +44,20 @@ class TemplatesModel(object): pool_name = pool_name_from_uri(pool_uri) try: conn.storagePoolLookupByName(pool_name) - except Exception as e: - err = "Storagepool specified is not valid: %s." - raise InvalidParameter(err % e.message) + except Exception: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': name})
for net_name in params.get(u'networks', []): try: conn.networkLookupByName(net_name) - except Exception, e: - raise InvalidParameter("Network '%s' specified by template " - "does not exist." % net_name) + except Exception: + raise InvalidParameter("KCHTMPL0003E", {'network': net_name, + 'template': name})
with self.objstore as session: if name in session.get_list('template'): - raise InvalidOperation("Template already exists") + raise InvalidOperation("KCHTMPL0001E", {'name': name}) t = LibvirtVMTemplate(params, scan=True) session.store('template', name, t.info) return name @@ -100,17 +100,17 @@ class TemplateModel(object): try: conn = self.conn.get() conn.storagePoolLookupByName(pool_name) - except Exception as e: - err = "Storagepool specified is not valid: %s." - raise InvalidParameter(err % e.message) + except Exception: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': name})
for net_name in params.get(u'networks', []): try: conn = self.conn.get() conn.networkLookupByName(net_name) - except Exception, e: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + except Exception: + raise InvalidParameter("KCHTMPL0003E", {'network': net_name, + 'template': name})
self.delete(name) try: @@ -133,12 +133,12 @@ class LibvirtVMTemplate(VMTemplate): conn = self.conn.get() pool = conn.storagePoolLookupByName(pool_name) except libvirt.libvirtError: - err = 'Storage specified by template does not exist' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': self.name})
if not pool.isActive(): - err = 'Storage specified by template is not active' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0005E", {'pool': pool_name, + 'template': self.name})
return pool
@@ -149,12 +149,12 @@ class LibvirtVMTemplate(VMTemplate): conn = self.conn.get() network = conn.networkLookupByName(name) except libvirt.libvirtError: - err = 'Network specified by template does not exist' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0003E", {'network': name, + 'template': self.name})
if not network.isActive(): - err = 'Network specified by template is not active' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0007E", {'network': name, + 'template': self.name})
def _get_storage_path(self): pool = self._storage_validate() diff --git a/src/kimchi/model/utils.py b/src/kimchi/model/utils.py index a27b867..b642f05 100644 --- a/src/kimchi/model/utils.py +++ b/src/kimchi/model/utils.py @@ -30,4 +30,4 @@ def get_vm_name(vm_name, t_name, name_list): vm_name = "%s-vm-%i" % (t_name, i) if vm_name not in name_list: return vm_name - raise OperationFailed("Unable to choose a VM name") + raise OperationFailed("KCHUTILS0003E") diff --git a/src/kimchi/model/vmifaces.py b/src/kimchi/model/vmifaces.py index f3eddb2..f526e0d 100644 --- a/src/kimchi/model/vmifaces.py +++ b/src/kimchi/model/vmifaces.py @@ -52,13 +52,12 @@ class VMIfacesModel(object): networks = conn.listNetworks() + conn.listDefinedNetworks()
if params["type"] == "network" and params["network"] not in networks: - raise InvalidParameter("%s is not an available network" % - params["network"]) + raise InvalidParameter("KCHVMIF0002E", + {'name': vm, 'network': params["network"]})
dom = VMModel.get_vm(vm, self.conn) if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - raise InvalidOperation("do not support hot plugging attach " - "guest interface") + raise InvalidOperation("KCHVMIF0003E")
macs = (iface.mac.get('address') for iface in self.get_vmifaces(vm, self.conn)) @@ -108,7 +107,7 @@ class VMIfaceModel(object):
iface = self._get_vmiface(vm, mac) if iface is None: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac})
info['type'] = iface.attrib['type'] info['mac'] = iface.mac.get('address') @@ -126,10 +125,10 @@ class VMIfaceModel(object): iface = self._get_vmiface(vm, mac)
if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - raise InvalidOperation("do not support hot plugging detach " - "guest interface") + raise InvalidOperation("KCHVMIF0003E") + if iface is None: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac})
dom.detachDeviceFlags(etree.tostring(iface), libvirt.VIR_DOMAIN_AFFECT_CURRENT) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index d4384a1..d9e4f20 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -163,7 +163,7 @@ class VMsModel(object): name = get_vm_name(params.get('name'), t_name, vm_list) # incoming text, from js json, is unicode, do not need decode if name in vm_list: - raise InvalidOperation("VM already exists") + raise InvalidOperation("KCHVM0001E", {'name': name})
vm_overrides = dict() pool_uri = params.get('storagepool') @@ -173,8 +173,7 @@ class VMsModel(object): vm_overrides)
if not self.caps.qemu_stream and t.info.get('iso_stream', False): - err = "Remote ISO image is not supported by this server." - raise InvalidOperation(err) + raise InvalidOperation("KCHVM0005E")
t.validate() vol_list = t.fork_vm_storage(vm_uuid) @@ -201,7 +200,8 @@ class VMsModel(object): for v in vol_list: vol = conn.storageVolLookupByPath(v['path']) vol.delete(0) - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVM0007E", {'name': name, + 'err': e.get_error_message()})
return name
@@ -237,15 +237,16 @@ class VMModel(object): try: if 'name' in params: if state == 'running': - err = "VM name only can be updated when vm is powered off." - raise InvalidParameter(err) + msg_args = {'name': dom.name(), 'new_name': params['name']} + raise InvalidParameter("KCHVM0003E", msg_args) else: dom.undefine() conn = self.conn.get() dom = conn.defineXML(new_xml) except libvirt.libvirtError as e: dom = conn.defineXML(old_xml) - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVM0008E", {'name': dom.name(), + 'err': e.get_error_message()}) return dom
def _live_vm_update(self, dom, params): @@ -308,8 +309,8 @@ class VMModel(object): except NotFoundError: return False except Exception, e: - err = "Unable to retrieve VM '%s': %s" - raise OperationFailed(err % (name, e.message)) + raise OperationFailed("KCHVM0009E", {'name': name, + 'err': e.message})
@staticmethod def get_vm(name, conn): @@ -319,7 +320,7 @@ class VMModel(object): return conn.lookupByName(name.encode("utf-8")) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: - raise NotFoundError("Virtual Machine '%s' not found" % name) + raise NotFoundError("KCHVM0002E", {'name': name}) else: raise
@@ -384,8 +385,7 @@ class VMModel(object): if graphics_port is not None: vnc.add_proxy_token(name, graphics_port) else: - raise OperationFailed("Only able to connect to running vm's vnc " - "graphics.") + raise OperationFailed("KCHVM0010E", {'name': name})
def _vmscreenshot_delete(self, vm_uuid): screenshot = VMScreenshotModel.get_screenshot(vm_uuid, self.objstore, @@ -405,7 +405,7 @@ class VMScreenshotModel(object): d_info = dom.info() vm_uuid = dom.UUIDString() if DOM_STATE_MAP[d_info[0]] != 'running': - raise NotFoundError('No screenshot for stopped vm') + raise NotFoundError("KCHVM0004E", {'name': name})
screenshot = self.get_screenshot(vm_uuid, self.objstore, self.conn) img_path = screenshot.lookup() @@ -448,7 +448,7 @@ class LibvirtVMScreenshot(VMScreenshot): stream.abort() except: pass - raise NotFoundError("Screenshot not supported for %s" % vm_name) + raise NotFoundError("KCHVM0006E", {'name': vm_name}) else: stream.finish() finally: diff --git a/src/kimchi/objectstore.py b/src/kimchi/objectstore.py index 7b567f3..5cb8ae1 100644 --- a/src/kimchi/objectstore.py +++ b/src/kimchi/objectstore.py @@ -54,7 +54,7 @@ class ObjectStoreSession(object): jsonstr = res.fetchall()[0][0] except IndexError: self.conn.rollback() - raise NotFoundError(ident) + raise NotFoundError("KCHOBJST0001E", {'item': ident}) return json.loads(jsonstr)
def delete(self, obj_type, ident, ignore_missing=False): @@ -63,7 +63,7 @@ class ObjectStoreSession(object): (obj_type, ident)) if c.rowcount != 1 and not ignore_missing: self.conn.rollback() - raise NotFoundError(ident) + raise NotFoundError("KCHOBJST0001E", {'item': ident}) self.conn.commit()
def store(self, obj_type, ident, data): diff --git a/src/kimchi/template.py b/src/kimchi/template.py index 173e7c6..fd1d591 100644 --- a/src/kimchi/template.py +++ b/src/kimchi/template.py @@ -27,6 +27,7 @@ import json import os
+from kimchi.config import paths from Cheetah.Template import Template from glob import iglob
@@ -53,7 +54,6 @@ def get_lang():
def get_support_languages(): - paths = cherrypy.request.app.root.paths mopath = "%s/*" % paths.mo_dir return [path.rsplit('/', 1)[1] for path in iglob(mopath)]
diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index 8795957..a1410c0 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -29,12 +29,10 @@ import urllib2 from threading import Timer
from cherrypy.lib.reprconf import Parser -from kimchi.config import paths, PluginPaths -from kimchi.exception import TimeoutExpired -
from kimchi.asynctask import AsyncTask -from kimchi.exception import InvalidParameter +from kimchi.config import paths, PluginPaths +from kimchi.exception import InvalidParameter, TimeoutExpired
kimchi_log = cherrypy.log.error_log @@ -45,7 +43,7 @@ def _uri_to_name(collection, uri): expr = '/%s/(.*?)/?$' % collection m = re.match(expr, uri) if not m: - raise InvalidParameter(uri) + raise InvalidParameter("KCHUTILS0001E", {'uri': uri}) return m.group(1)
@@ -169,7 +167,9 @@ def run_command(cmd, timeout=None): msg = ("subprocess is killed by signal.SIGKILL for " "timeout %s seconds" % timeout) kimchi_log.error(msg) - raise TimeoutExpired(msg) + + msg_args = {'cmd': cmd, 'seconds': timeout} + raise TimeoutExpired("KCHUTILS0002E", msg_args)
return out, error, proc.returncode except TimeoutExpired: diff --git a/src/kimchi/vmtemplate.py b/src/kimchi/vmtemplate.py index 58147e3..7aa0a65 100644 --- a/src/kimchi/vmtemplate.py +++ b/src/kimchi/vmtemplate.py @@ -27,7 +27,6 @@ import urllib import urlparse
-from kimchi import isoinfo Is this change related to this patch? from kimchi import osinfo from kimchi.exception import InvalidParameter, IsoFormatError from kimchi.isoinfo import IsoImage @@ -58,7 +57,7 @@ class VMTemplate(object):
iso_prefixes = ['/', 'http', 'https', 'ftp', 'ftps', 'tftp'] if len(filter(iso.startswith, iso_prefixes)) == 0: - raise InvalidParameter("Invalid parameter specified for cdrom.") + raise InvalidParameter("KCHTMPL0006E", {'param': iso})
if not iso.startswith('/'): self.info.update({'iso_stream': True}) @@ -66,8 +65,8 @@ class VMTemplate(object): try: iso_img = IsoImage(iso) iso_distro, iso_version = iso_img.probe() - except IsoFormatError, e: - raise InvalidParameter(e) + except IsoFormatError: + raise InvalidParameter("KCHISO0001E", {'filename': iso})
# Fetch defaults based on the os distro and version os_distro = args.get('os_distro', iso_distro) diff --git a/tests/test_exception.py b/tests/test_exception.py index b64ab94..79c8e4f 100644 --- a/tests/test_exception.py +++ b/tests/test_exception.py @@ -77,8 +77,8 @@ class ExceptionTests(unittest.TestCase): # test 400 missing required parameter req = json.dumps({}) resp = json.loads(request(host, port, '/vms', req, 'POST').read()) - msg = u"Invalid parameter: 'u'template' is a required property'" self.assertEquals('400 Bad Request', resp.get('code')) + msg = u"KCHVM0016E: Specify a template to create a Virtual Machine from" self.assertEquals(msg, resp.get('reason')) self.assertNotIn('call_stack', resp)
@@ -107,7 +107,7 @@ class ExceptionTests(unittest.TestCase): # test 400 missing required parameter req = json.dumps({}) resp = json.loads(request(host, port, '/vms', req, 'POST').read()) - msg = u"Invalid parameter: 'u'template' is a required property'" + msg = u"KCHVM0016E: Specify a template to create a Virtual Machine from" self.assertEquals('400 Bad Request', resp.get('code')) self.assertEquals(msg, resp.get('reason')) self.assertIn('call_stack', resp) diff --git a/tests/test_rest.py b/tests/test_rest.py index 0ed293b..4b58e18 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -568,7 +568,7 @@ class RestTests(unittest.TestCase): resp = self.request('/vms', req, 'POST') self.assertEquals(400, resp.status) resp = json.loads(resp.read()) - self.assertIn('Invalid parameter', resp['reason']) + self.assertIn(u"KCHVM0016E:", resp['reason'])
def test_create_vm_with_bad_template_uri(self): req = json.dumps({'name': 'vm-bad-template', @@ -576,7 +576,7 @@ class RestTests(unittest.TestCase): resp = self.request('/vms', req, 'POST') self.assertEquals(400, resp.status) resp = json.loads(resp.read()) - self.assertIn('Invalid parameter', resp['reason']) + self.assertIn(u"KCHVM0012E", resp['reason'])
def test_get_storagepools(self): storagepools = json.loads(self.request('/storagepools').read()) diff --git a/tests/utils.py b/tests/utils.py index 40dfae2..14c57d4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -155,8 +155,9 @@ def patch_auth(): def _authenticate(username, password, service="passwd"): try: return fake_user[username] == password - except KeyError: - raise OperationFailed('Bad login') + except KeyError, e: + raise OperationFailed("KCHAUTH0001E", {'userid': 'username', + 'code': e.message})
import kimchi.auth kimchi.auth.authenticate = _authenticate I see some parts of the code raising exceptions that are still not following this translation model. For instance, ImportError at src/kimchi/utils.py, and Exception in src/kimchi/config.py and src/kimchi/websocket.py. Shouldn't we translate all exception messages?
Best regards, Leonardo Garcia

On 02/11/2014 01:10 AM, Leonardo Augusto Guimarães Garcia wrote:
On 02/09/2014 08:47 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Update all Kimchi exceptions to translate backend messages. Use message code to get the correct messages in i18n.py and raise a message like: "<code>: <translated-message>"
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/model.py | 12 ++-- src/kimchi/asynctask.py | 4 +- src/kimchi/auth.py | 3 +- src/kimchi/disks.py | 5 +- src/kimchi/distroloader.py | 5 +- src/kimchi/exception.py | 14 ++-- src/kimchi/iscsi.py | 6 +- src/kimchi/isoinfo.py | 17 +++-- src/kimchi/mockmodel.py | 113 +++++++++++++++++++------------- src/kimchi/model/config.py | 2 +- src/kimchi/model/debugreports.py | 18 ++--- src/kimchi/model/host.py | 10 +-- src/kimchi/model/interfaces.py | 4 +- src/kimchi/model/libvirtstoragepool.py | 14 ++-- src/kimchi/model/networks.py | 37 ++++++----- src/kimchi/model/storagepools.py | 39 ++++++----- src/kimchi/model/storageservers.py | 2 +- src/kimchi/model/storagevolumes.py | 37 ++++++----- src/kimchi/model/templates.py | 44 ++++++------- src/kimchi/model/utils.py | 2 +- src/kimchi/model/vmifaces.py | 15 ++--- src/kimchi/model/vms.py | 28 ++++---- src/kimchi/objectstore.py | 4 +- src/kimchi/template.py | 2 +- src/kimchi/utils.py | 12 ++-- src/kimchi/vmtemplate.py | 7 +- tests/test_exception.py | 4 +- tests/test_rest.py | 4 +- tests/utils.py | 5 +- 29 files changed, 255 insertions(+), 214 deletions(-)
diff --git a/plugins/sample/model.py b/plugins/sample/model.py index 184864d..f7ca319 100644 --- a/plugins/sample/model.py +++ b/plugins/sample/model.py @@ -31,7 +31,7 @@ class CirclesModel(object): def create(self, params): name = params['name'] if name in self._circles: - raise InvalidOperation("Circle %s already exists" % name) + raise InvalidOperation("SPCIRCLE0001E", {'name': name}) self._circles[name] = Circle(params['radius']) return name
@@ -48,12 +48,12 @@ class CircleModel(object): try: circle = self._circles[name] except KeyError: - raise NotFoundError("Circle %s not found" % name) + raise NotFoundError("SPCIRC0002E", {'name': name}) return {'radius': circle.radius}
def update(self, name, params): if name not in self._circles: - raise NotFoundError("Circle %s not found" % name) + raise NotFoundError("SPCIRC0002E", {'name': name}) self._circles[name].radius = params['radius'] return name
@@ -71,7 +71,7 @@ class RectanglesModel(object): def create(self, params): name = params['name'] if name in self._rectangles: - raise InvalidOperation("Rectangle %s already exists" % name) + raise InvalidOperation("SPRET0001E", {'name': name}) self._rectangles[name] = Rectangle(params['length'], params['width']) return name
@@ -87,12 +87,12 @@ class RectangleModel(object): try: rectangle = self._rectangles[name] except KeyError: - raise NotFoundError("Rectangle %s not found" % name) + raise NotFoundError("SPRET0002E", {'name': name}) return {'length': rectangle.length, 'width': rectangle.width}
def update(self, name, params): if name not in self._rectangles: - raise NotFoundError("Rectangle %s not found" % name) + raise NotFoundError("SPRET0002E", {'name': name}) try: self._rectangles[name].length = params['length'] except KeyError: diff --git a/src/kimchi/asynctask.py b/src/kimchi/asynctask.py index 4ff76e4..f5cba50 100644 --- a/src/kimchi/asynctask.py +++ b/src/kimchi/asynctask.py @@ -31,8 +31,8 @@ from kimchi.exception import OperationFailed class AsyncTask(object): def __init__(self, id, target_uri, fn, objstore, opaque=None): if objstore is None: - raise OperationFailed("Datastore is not initiated in " - "the model object") + raise OperationFailed("KCHASYNC0001E") + self.id = str(id) self.target_uri = target_uri self.fn = fn diff --git a/src/kimchi/auth.py b/src/kimchi/auth.py index 242fdcf..1cae45d 100644 --- a/src/kimchi/auth.py +++ b/src/kimchi/auth.py @@ -68,7 +68,8 @@ def authenticate(username, password, service="passwd"): try: auth.authenticate() except PAM.error, (resp, code): - raise OperationFailed(resp, code) + msg_args = {'userid': username, 'code': code} + raise OperationFailed("KCHAUTH0001E", msg_args)
return True
diff --git a/src/kimchi/disks.py b/src/kimchi/disks.py index 941aaca..83d5cc6 100644 --- a/src/kimchi/disks.py +++ b/src/kimchi/disks.py @@ -44,7 +44,7 @@ def _get_lsblk_devs(keys, devs=[]): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = lsblk.communicate() if lsblk.returncode != 0: - raise OperationFailed('Error executing lsblk: %s' % err) + raise OperationFailed("KCHDISKS0001E", {'err': err})
return _parse_lsblk_output(out, keys)
@@ -60,8 +60,7 @@ def _get_dev_major_min(name): maj_min = dev['maj:min'] break else: - msg = "Failed to find major and minor number for %s" % name - raise OperationFailed(msg) + raise OperationFailed("KCHDISKS0002E", {'device': name})
return maj_min
diff --git a/src/kimchi/distroloader.py b/src/kimchi/distroloader.py index 98fd764..f0b0208 100644 --- a/src/kimchi/distroloader.py +++ b/src/kimchi/distroloader.py @@ -37,10 +37,11 @@ class DistroLoader(object): self.location = location or config.get_distros_store()
def _get_json_info(self, fname): + msg_args = {'filename': fname} if not os.path.isfile(fname): msg = "DistroLoader: failed to find distro file: %s" % fname kimchi_log.error(msg) - raise NotFoundError(msg) + raise NotFoundError("KCHDL0001E", msg_args) try: with open(fname) as f: data = json.load(f) @@ -48,7 +49,7 @@ class DistroLoader(object): except ValueError: msg = "DistroLoader: failed to parse distro file: %s" % fname kimchi_log.error(msg) - raise OperationFailed(msg) + raise OperationFailed("KCHDL0002E", msg_args)
def get(self): all_json_files = glob.glob("%s/%s" % (self.location, "*.json")) diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py index 7fcce54..952e243 100644 --- a/src/kimchi/exception.py +++ b/src/kimchi/exception.py @@ -49,29 +49,29 @@ class KimchiException(Exception): Exception.__init__(self, pattern)
-class NotFoundError(Exception): +class NotFoundError(KimchiException): pass
-class OperationFailed(Exception): +class OperationFailed(KimchiException): pass
-class MissingParameter(Exception): +class MissingParameter(KimchiException): pass
-class InvalidParameter(Exception): +class InvalidParameter(KimchiException): pass
-class InvalidOperation(Exception): +class InvalidOperation(KimchiException): pass
-class IsoFormatError(Exception): +class IsoFormatError(KimchiException): pass
-class TimeoutExpired(Exception): +class TimeoutExpired(KimchiException): pass diff --git a/src/kimchi/iscsi.py b/src/kimchi/iscsi.py index 35c0b8a..248188c 100644 --- a/src/kimchi/iscsi.py +++ b/src/kimchi/iscsi.py @@ -55,7 +55,8 @@ class TargetClient(object): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = iscsiadm.communicate() if iscsiadm.returncode != 0: - raise OperationFailed('Error executing iscsiadm: %s' % err) + msg_args = {'portal': self.portal, 'err': err} + raise OperationFailed("KCHISCSI0001E", msg_args) return out
def _discover(self): @@ -65,7 +66,8 @@ class TargetClient(object): stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = iscsiadm.communicate() if iscsiadm.returncode != 0: - raise OperationFailed('Error executing iscsiadm: %s' % err) + msg_args = {'portal': self.portal, 'err': err} + raise OperationFailed("KCHISCSI0001E", msg_args) return out
def _run_op(self, op): diff --git a/src/kimchi/isoinfo.py b/src/kimchi/isoinfo.py index a3cd4cd..5629391 100644 --- a/src/kimchi/isoinfo.py +++ b/src/kimchi/isoinfo.py @@ -149,11 +149,11 @@ class IsoImage(object): if check_url_path(self.path): return True
- raise IsoFormatError('ISO %s does not exist' % self.path) + raise IsoFormatError("KCHISO0001E", {'filename': self.path})
def probe(self): if not self.bootable: - raise IsoFormatError("ISO %s not bootable" % self.path) + raise IsoFormatError("KCHISO0002E", {'filename': self.path})
matcher = Matcher(self.volume_id)
@@ -197,7 +197,8 @@ class IsoImage(object): if vd_type == 0: # Found El-Torito Boot Record break if not et_ident.startswith('EL TORITO SPECIFICATION'): - raise IsoFormatError("Invalid El Torito boot record") + raise IsoFormatError("KCHISO0003E", + {'filename': self.path})
offset = IsoImage.SECTOR_SIZE * boot_cat size = IsoImage.EL_TORITO_VALIDATION_ENTRY.size + \ @@ -210,7 +211,8 @@ class IsoImage(object): (hdr_id, platform_id, pad0, ident, csum, key55, keyAA) = self._unpack(fmt, tmp_data) if key55 != 0x55 or keyAA != 0xaa: - raise IsoFormatError("Invalid El Torito validation entry") + raise IsoFormatError("KCHISO0004E", + {'filename': self.path})
fmt = IsoImage.EL_TORITO_BOOT_ENTRY tmp_data = data[ptr:ptr+fmt.size] @@ -221,7 +223,8 @@ class IsoImage(object): elif boot == 0: self.bootable = False else: - raise IsoFormatError("Invalid El Torito boot indicator") + raise IsoFormatError("KCHISO0005E", + {'filename': self.path})
def _scan_primary_vol(self, data): """ @@ -232,9 +235,9 @@ class IsoImage(object): info = self._unpack(IsoImage.VOL_DESC, primary_vol_data) (vd_type, vd_ident, vd_ver, pad0, sys_id, vol_id) = info if vd_type != 1: - raise IsoFormatError("Unexpected volume type for primary volume") + raise IsoFormatError("KCHISO0006E", {'filename': self.path}) if vd_ident != 'CD001' or vd_ver != 1: - raise IsoFormatError("Bad format while reading volume descriptor") + raise IsoFormatError("KCHISO0007E", {'filename': self.path}) self.volume_id = vol_id
def _get_iso_data(self, offset, size): diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index 4e276eb..e5425b2 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -83,7 +83,8 @@ class MockModel(object):
if 'name' in params: if state == 'running' or params['name'] in self.vms_get_list(): - raise InvalidParameter("VM name existed or vm not shutoff.") + msg_args = {'name': dom.name, 'new_name': params['name']} + raise InvalidParameter("KCHVM0003E", msg_args) else: del self._mock_vms[dom.name] dom.name = params['name'] @@ -134,7 +135,7 @@ class MockModel(object): name = get_vm_name(params.get('name'), t_name, self._mock_vms.keys()) if name in self._mock_vms: - raise InvalidOperation("VM already exists") + raise InvalidOperation("KCHVM0001E", {'name': name})
vm_uuid = str(uuid.uuid4()) vm_overrides = dict() @@ -166,7 +167,8 @@ class MockModel(object): def vmscreenshot_lookup(self, name): vm = self._get_vm(name) if vm.info['state'] != 'running': - raise NotFoundError('No screenshot for stopped vm') + raise NotFoundError("KCHVM0004E", {'name': name}) + screenshot = self._mock_screenshots.setdefault( vm.uuid, MockVMScreenshot({'uuid': vm.uuid})) return screenshot.lookup() @@ -185,18 +187,19 @@ class MockModel(object): try: del self._mock_templates[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHTMPL0002E", {'name': name})
def templates_create(self, params): name = params['name'] if name in self._mock_templates: - raise InvalidOperation("Template already exists") + raise InvalidOperation("KCHTMPL0001E", {'name': name}) + for net_name in params.get(u'networks', []): try: self._get_network(net_name) except NotFoundError: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + msg_args = {'network': net_name, 'template': name} + raise InvalidParameter("KCHTMPL0003E", msg_args)
t = MockVMTemplate(params, self) self._mock_templates[name] = t @@ -212,15 +215,16 @@ class MockModel(object): new_storagepool = new_t.get(u'storagepool', '') try: self._get_storagepool(pool_name_from_uri(new_storagepool)) - except Exception as e: - raise InvalidParameter("Storagepool specified is not valid: %s." % e.message) + except Exception: + msg_args = {'pool': new_storagepool, 'template': name} + raise InvalidParameter("KCHTMPL0004E", msg_args)
for net_name in params.get(u'networks', []): try: self._get_network(net_name) except NotFoundError: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + msg_args = {'network': net_name, 'template': name} + raise InvalidParameter("KCHTMPL0003E", msg_args)
self.template_delete(name) try: @@ -243,7 +247,7 @@ class MockModel(object): else: return t except KeyError: - raise NotFoundError() + raise NotFoundError("KCHTMPL0002E", {'name': name})
def debugreport_lookup(self, name): path = config.get_debugreports_path() @@ -251,7 +255,7 @@ class MockModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name', name})
ctime = os.stat(file_target).st_ctime ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) @@ -269,7 +273,7 @@ class MockModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name', name})
os.remove(file_target)
@@ -291,7 +295,7 @@ class MockModel(object): try: return self._mock_vms[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHVM0002E", {'name': name})
def storagepools_create(self, params): try: @@ -304,9 +308,12 @@ class MockModel(object): else: pool.info['autostart'] = False except KeyError, item: - raise MissingParameter(item) + raise MissingParameter("KCHPOOL0004E", + {'item': item, 'name': name}) + if name in self._mock_storagepools or name in (ISO_POOL_NAME,): - raise InvalidOperation("StoragePool already exists") + raise InvalidOperation("KCHPOOL0001E", {'name': name}) + self._mock_storagepools[name] = pool return name
@@ -318,7 +325,8 @@ class MockModel(object): def storagepool_update(self, name, params): autostart = params['autostart'] if autostart not in [True, False]: - raise InvalidOperation("Autostart flag must be true or false") + raise InvalidOperation("KCHPOOL0003E") + storagepool = self._get_storagepool(name) storagepool.info['autostart'] = autostart ident = storagepool.name @@ -342,12 +350,15 @@ class MockModel(object): try: return self._mock_storagepools[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHPOOL0002E", {'name': name})
def storagevolumes_create(self, pool_name, params): pool = self._get_storagepool(pool_name) if pool.info['state'] == 'inactive': - raise InvalidOperation("StoragePool not active") + raise InvalidOperation("KCHVOL0003E", + {'pool': pool_name, + 'volume': params['name']}) + try: name = params['name'] volume = MockStorageVolume(pool, name, params) @@ -356,15 +367,20 @@ class MockModel(object): volume.info['path'] = os.path.join( pool.info['path'], name) except KeyError, item: - raise MissingParameter(item) + raise MissingParameter("KCHVOL0004E", + {'item': item, 'volume': name}) + if name in pool._volumes: - raise InvalidOperation("StorageVolume already exists") + raise InvalidOperation("KCHVOL0001E", {'name': name}) + pool._volumes[name] = volume return name
def storagevolume_lookup(self, pool, name): if self._get_storagepool(pool).info['state'] != 'active': - raise InvalidOperation("StoragePool %s is not active" % pool) + raise InvalidOperation("KCHVOL0005E", {'pool': pool, + 'volume': name}) + storagevolume = self._get_storagevolume(pool, name) return storagevolume.info
@@ -384,8 +400,7 @@ class MockModel(object): def storagevolumes_get_list(self, pool): res = self._get_storagepool(pool) if res.info['state'] == 'inactive': - raise InvalidOperation( - "Unable to list volumes of inactive storagepool %s" % pool) + raise InvalidOperation("KCHVOL0006E", {'pool': pool}) return res._volumes.keys()
def isopool_lookup(self, name): @@ -438,7 +453,7 @@ class MockModel(object): # Avoid inconsistent pool result because of lease between list and lookup pass
- raise NotFoundError("storage server %s not used by kimchi" % server) + raise NotFoundError("KCHSR0001E", {'server': server})
def dummy_interfaces(self): interfaces = {} @@ -461,7 +476,8 @@ class MockModel(object): def networks_create(self, params): name = params['name'] if name in self.networks_get_list(): - raise InvalidOperation("Network %s already exists" % name) + raise InvalidOperation("KCHNET0001E", {'name': name}) + network = MockNetwork(name) connection = params['connection'] network.info['connection'] = connection @@ -469,22 +485,23 @@ class MockModel(object): try: interface = params['interface'] network.info['interface'] = interface - except KeyError, key: - raise MissingParameter(key) + except KeyError: + raise MissingParameter("KCHNET0004E", + {'name': name})
subnet = params.get('subnet', '') if subnet: network.info['subnet'] = subnet try: net = ipaddr.IPNetwork(subnet) - except ValueError, e: - raise InvalidParameter(e) + except ValueError: + msg_args = {'subnet':subnet, 'network': name} + raise InvalidParameter("KCHNET0003E", msg_args)
network.info['dhcp'] = { 'start': str(net.network + net.numhosts / 2), 'stop': str(net.network + net.numhosts - 2)} - if name in self._mock_networks: - raise InvalidOperation("Network already exists") + self._mock_networks[name] = network return name
@@ -492,7 +509,7 @@ class MockModel(object): try: return self._mock_networks[name] except KeyError: - raise NotFoundError("Network '%s'" % name) + raise NotFoundError("KCHNET0002E", {'name': name})
def _get_vms_attach_to_a_network(self, network): vms = [] @@ -523,8 +540,9 @@ class MockModel(object): def vmifaces_create(self, vm, params): if (params["type"] == "network" and params["network"] not in self.networks_get_list()): - raise InvalidParameter("%s is not an available network" % - params["network"]) + msg_args = {'network': params["network"], 'name': vm} + raise InvalidParameter("KCHVMIF0002E", msg_args) + dom = self._get_vm(vm) iface = MockVMIface(params["network"]) ("model" in params.keys() and @@ -544,7 +562,7 @@ class MockModel(object): try: info = dom.ifaces[mac].info except KeyError: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'iface': mac, 'name': vm}) return info
def vmiface_delete(self, vm, mac): @@ -552,7 +570,7 @@ class MockModel(object): try: del dom.ifaces[mac] except KeyError: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'iface': mac, 'name': vm})
def tasks_get_list(self): with self.objstore as session: @@ -573,7 +591,7 @@ class MockModel(object): try: return self._get_storagepool(pool)._volumes[name] except KeyError: - raise NotFoundError() + raise NotFoundError("KCHVOL0002E", {'name': name, 'pool': pool})
def _get_distros(self): distroloader = DistroLoader() @@ -586,7 +604,7 @@ class MockModel(object): try: return self.distros[name] except KeyError: - raise NotFoundError("distro '%s' not found" % name) + raise NotFoundError("KCHDISTRO0001E", {'name': name})
def _gen_debugreport_file(self, ident): return self.add_task('', self._create_log, ident) @@ -638,14 +656,14 @@ class MockModel(object): # Check for running vms before shutdown running_vms = self.vms_get_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Shutdown not allowed: VMs are running!") + raise OperationFailed("KCHHOST0001E") cherrypy.engine.exit()
def host_reboot(self, args=None): # Find running VMs running_vms = self.vms_get_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Reboot not allowed: VMs are running!") + raise OperationFailed("KCHHOST0002E") cherrypy.engine.stop() time.sleep(10) cherrypy.engine.start() @@ -656,8 +674,8 @@ class MockModel(object):
def partition_lookup(self, name): if name not in disks.get_partitions_names(): - raise NotFoundError("Partition %s not found in the host" - % name) + raise NotFoundError("KCHPART0001E", {'name': name}) + return disks.get_partition_details(name)
def config_lookup(self, name): @@ -677,9 +695,12 @@ class MockVMTemplate(VMTemplate): try: pool = self.model._get_storagepool(pool_name) except NotFoundError: - raise InvalidParameter('Storage specified by template does not exist') + msg_args = {'pool': pool_name, 'template': self.name} + raise InvalidParameter("KCHTMPL0004E", msg_args) + if pool.info['state'] != 'active': - raise InvalidParameter('Storage specified by template is not active') + msg_args = {'pool': pool_name, 'template': self.name} + raise InvalidParameter("KCHTMPL0005E", msg_args)
return pool
diff --git a/src/kimchi/model/config.py b/src/kimchi/model/config.py index 0e66e02..9b5814a 100644 --- a/src/kimchi/model/config.py +++ b/src/kimchi/model/config.py @@ -95,4 +95,4 @@ class DistroModel(object): try: return self._distros.distros[name] except KeyError: - raise NotFoundError("Distro '%s' not found." % name) + raise NotFoundError("KCHDISTRO0001E", {'name': name}) diff --git a/src/kimchi/model/debugreports.py b/src/kimchi/model/debugreports.py index a1cb19c..2c5b13a 100644 --- a/src/kimchi/model/debugreports.py +++ b/src/kimchi/model/debugreports.py @@ -59,7 +59,7 @@ class DebugReportsModel(object): if gen_cmd is not None: return add_task('', gen_cmd, self.objstore, name)
- raise OperationFailed("debugreport tool not found") + raise OperationFailed("KCHDR0002E")
@staticmethod def sosreport_generate(cb, name): @@ -68,9 +68,11 @@ class DebugReportsModel(object): retcode = subprocess.call(command, shell=True, stdout=subprocess.PIPE) if retcode < 0: - raise OperationFailed('Command terminated with signal') + raise OperationFailed("KCHDR0003E", {'name': name, + 'err': retcode}) elif retcode > 0: - raise OperationFailed('Command failed: rc = %i' % retcode) + raise OperationFailed("KCHDR0003E", {'name': name, + 'err': retcode}) pattern = '/tmp/sosreport-%s-*' % name for reportFile in glob.glob(pattern): if not fnmatch.fnmatch(reportFile, '*.md5'): @@ -83,8 +85,8 @@ class DebugReportsModel(object): # runs successfully. In future we might have a general name # mangling function in kimchi to format the name before passing # it to sosreport. Then we can delete this exception. - raise OperationFailed('Can not find generated debug report ' - 'named by %s' % pattern) + raise OperationFailed("KCHDR0004E", {'name': pattern}) + ext = output.split('.', 1)[1] path = config.get_debugreports_path() target = os.path.join(path, name) @@ -104,7 +106,7 @@ class DebugReportsModel(object): # and update the task status there log = logging.getLogger('Model') log.warning('Exception in generating debug file: %s', e) - raise OperationFailed(e) + raise OperationFailed("KCHDR0005E", {'name': name, 'err': e})
@staticmethod def get_system_report_tool(): @@ -139,7 +141,7 @@ class DebugReportModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name': name})
ctime = os.stat(file_target).st_ctime ctime = time.strftime("%Y-%m-%d-%H:%M:%S", time.localtime(ctime)) @@ -154,7 +156,7 @@ class DebugReportModel(object): try: file_target = glob.glob(file_pattern)[0] except IndexError: - raise NotFoundError('no such report') + raise NotFoundError("KCHDR0001E", {'name': name})
os.remove(file_target)
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index a3d9e38..80f93db 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -67,7 +67,8 @@ class HostModel(object): # Check for running vms before shutdown running_vms = self._get_vms_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Shutdown not allowed: VMs are running!") + raise OperationFailed("KCHHOST0001E") + kimchi_log.info('Host is going to shutdown.') os.system('shutdown -h now')
@@ -75,7 +76,8 @@ class HostModel(object): # Find running VMs running_vms = self._get_vms_list_by_state('running') if len(running_vms) > 0: - raise OperationFailed("Reboot not allowed: VMs are running!") + raise OperationFailed("KCHHOST0002E") + kimchi_log.info('Host is going to reboot.') os.system('reboot')
@@ -196,6 +198,6 @@ class PartitionModel(object):
def lookup(self, name): if name not in disks.get_partitions_names(): - raise NotFoundError("Partition %s not found in the host" - % name) + raise NotFoundError("KCHPART0001E", {'name': name}) + return disks.get_partition_details(name) diff --git a/src/kimchi/model/interfaces.py b/src/kimchi/model/interfaces.py index 52c6bae..96b1261 100644 --- a/src/kimchi/model/interfaces.py +++ b/src/kimchi/model/interfaces.py @@ -42,5 +42,5 @@ class InterfaceModel(object): def lookup(self, name): try: return netinfo.get_interface_info(name) - except ValueError, e: - raise NotFoundError(e) + except ValueError: + raise NotFoundError("KCHIFACE0001E", {'name': name}) diff --git a/src/kimchi/model/libvirtstoragepool.py b/src/kimchi/model/libvirtstoragepool.py index f4dbf2e..f9b395c 100644 --- a/src/kimchi/model/libvirtstoragepool.py +++ b/src/kimchi/model/libvirtstoragepool.py @@ -38,7 +38,7 @@ class StoragePoolDef(object): for klass in cls.__subclasses__(): if poolArgs['type'] == klass.poolType: return klass(poolArgs) - raise OperationFailed('Unsupported pool type: %s' % poolArgs['type']) + raise OperationFailed("KCHPOOL0014E", {'type': poolArgs['type']})
def __init__(self, poolArgs): self.poolArgs = poolArgs @@ -56,7 +56,7 @@ class StoragePoolDef(object): idempotent''' # TODO: When add new pool type, should also add the related test in # tests/test_storagepool.py - raise OperationFailed('self.xml is not implemented: %s' % self) + raise OperationFailed("KCHPOOL0015E", {'pool': self})
class DirPoolDef(StoragePoolDef): @@ -101,8 +101,7 @@ class NetfsPoolDef(StoragePoolDef): run_command(mount_cmd, 30) rollback.prependDefer(run_command, umount_cmd) except TimeoutExpired: - err = "Export path %s may block during nfs mount" - raise InvalidParameter(err % export_path) + raise InvalidParameter("KCHPOOL0012E", {'path': export_path})
with open("/proc/mounts", "rb") as f: rawMounts = f.read() @@ -113,8 +112,7 @@ class NetfsPoolDef(StoragePoolDef): mounted = True
if not mounted: - err = "Export path %s mount failed during nfs mount" - raise InvalidParameter(err % export_path) + raise InvalidParameter("KCHPOOL0013E", {'path': export_path})
@property def xml(self): @@ -181,8 +179,8 @@ class IscsiPoolDef(StoragePoolDef): def prepare(self, conn): source = self.poolArgs['source'] if not TargetClient(**source).validate(): - raise OperationFailed("Can not login to iSCSI host %s target %s" % - (source['host'], source['target'])) + msg_args = {'host': source['host'], 'target': source['target']} + raise OperationFailed("KCHISCSI0002E", msg_args) self._prepare_auth(conn)
def _prepare_auth(self, conn): diff --git a/src/kimchi/model/networks.py b/src/kimchi/model/networks.py index b164141..05105df 100644 --- a/src/kimchi/model/networks.py +++ b/src/kimchi/model/networks.py @@ -39,7 +39,7 @@ class NetworksModel(object): conn = self.conn.get() name = params['name'] if name in self.get_list(): - raise InvalidOperation("Network %s already exists" % name) + raise InvalidOperation("KCHNET0001E", {'name': name})
connection = params["connection"] # set forward mode, isolated do not need forward @@ -60,7 +60,8 @@ class NetworksModel(object): network = conn.networkDefineXML(xml) network.setAutostart(True) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHNET0008E", + {'name': name, 'err': e.get_error_message()})
return name
@@ -80,13 +81,13 @@ class NetworksModel(object): subnet and net_addrs.append(ipaddr.IPNetwork(subnet)) netaddr = knetwork.get_one_free_network(net_addrs) if not netaddr: - raise OperationFailed("can not find a free IP address for " - "network '%s'" % params['name']) + raise OperationFailed("KCHNET0009E", {'name': params['name']})
try: ip = ipaddr.IPNetwork(netaddr) - except ValueError as e: - raise InvalidParameter("%s" % e) + except ValueError: + raise InvalidParameter("KCHNET0003E", {'subent': netaddr, + 'network': params['name']})
if ip.ip == ip.network: ip.ip = ip.ip + 1 @@ -101,10 +102,11 @@ class NetworksModel(object): try: iface = params['interface'] if iface in self.get_all_networks_interfaces(): - raise InvalidParameter("interface '%s' already in use." % - iface) - except KeyError, e: - raise MissingParameter(e) + msg_args = {'iface': iface, 'network': params['name']} + raise InvalidParameter("KCHNET0006E", msg_args) + except KeyError: + raise MissingParameter("KCHNET0004E", {'name': params['name']}) + if netinfo.is_bridge(iface): params['bridge'] = iface elif netinfo.is_bare_nic(iface) or netinfo.is_bonding(iface): @@ -115,8 +117,7 @@ class NetworksModel(object): self._create_vlan_tagged_bridge(str(iface), str(params['vlan_id'])) else: - raise InvalidParameter("the interface should be bare nic, " - "bonding or bridge device.") + raise InvalidParameter("KCHNET0007E")
def get_all_networks_interfaces(self): net_names = self.get_list() @@ -144,7 +145,8 @@ class NetworksModel(object): vlan_tagged_br.create() except libvirt.libvirtError as e: conn.changeRollback() - raise OperationFailed(e.message) + raise OperationFailed("KCHNET0010E", {'iface': interface, + 'err': e.message}) else: conn.changeCommit() return br_name @@ -211,8 +213,8 @@ class NetworkModel(object): def delete(self, name): network = self._get_network(name) if network.isActive(): - raise InvalidOperation( - "Unable to delete the active network %s" % name) + raise InvalidOperation("KCHNET0005E", {'name': name}) + self._remove_vlan_tagged_bridge(network) network.undefine()
@@ -220,9 +222,8 @@ class NetworkModel(object): conn = self.conn.get() try: return conn.networkLookupByName(name) - except libvirt.libvirtError as e: - raise NotFoundError("Network '%s' not found: %s" % - (name, e.get_error_message())) + except libvirt.libvirtError: + raise NotFoundError("KCHNET0002E", {'name': name})
@staticmethod def get_network_from_xml(xml): diff --git a/src/kimchi/model/storagepools.py b/src/kimchi/model/storagepools.py index 233a8a7..fa73ce9 100644 --- a/src/kimchi/model/storagepools.py +++ b/src/kimchi/model/storagepools.py @@ -55,7 +55,8 @@ class StoragePoolsModel(object): names += conn.listDefinedStoragePools() return sorted(names) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0006E", + {'err': e.get_error_message()})
def create(self, params): task_id = None @@ -63,19 +64,19 @@ class StoragePoolsModel(object): try: name = params['name'] if name in (ISO_POOL_NAME, ): - raise InvalidOperation("StoragePool already exists") + raise InvalidOperation("KCHPOOL0001E", {'name': name})
if params['type'] == 'kimchi-iso': task_id = self._do_deep_scan(params) poolDef = StoragePoolDef.create(params) poolDef.prepare(conn) xml = poolDef.xml - except KeyError, key: - raise MissingParameter(key) + except KeyError, item: + raise MissingParameter("KCHPOOL0004E", + {'item': item, 'name': name})
if name in self.get_list(): - err = "The name %s has been used by a pool" - raise InvalidOperation(err % name) + raise InvalidOperation("KCHPOOL0001E", {'name': name})
try: if task_id: @@ -92,9 +93,9 @@ class StoragePoolsModel(object): # disable autostart for others pool.setAutostart(0) except libvirt.libvirtError as e: - msg = "Problem creating Storage Pool: %s" - kimchi_log.error(msg, e) - raise OperationFailed(e.get_error_message()) + kimchi_log.error("Problem creating Storage Pool: %s", e) + raise OperationFailed("KCHPOOL0007E", + {'name': name, 'err': e.get_error_message()}) return name
def _clean_scan(self, pool_name): @@ -144,7 +145,7 @@ class StoragePoolModel(object): return conn.storagePoolLookupByName(name) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_POOL: - raise NotFoundError("Storage Pool '%s' not found" % name) + raise NotFoundError("KCHTMPL0002E", {'name': name}) else: raise
@@ -156,7 +157,8 @@ class StoragePoolModel(object): else: return 0 except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0008E", + {'name': pool, 'err': e.get_error_message()})
def _get_storage_source(self, pool_type, pool_xml): source = {} @@ -203,7 +205,8 @@ class StoragePoolModel(object): def update(self, name, params): autostart = params['autostart'] if autostart not in [True, False]: - raise InvalidOperation("Autostart flag must be true or false") + raise InvalidOperation("KCHPOOL0003E") + pool = self.get_storagepool(name, self.conn) if autostart: pool.setAutostart(1) @@ -217,24 +220,26 @@ class StoragePoolModel(object): try: pool.create(0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0009E", + {'name': name, 'err': e.get_error_message()})
def deactivate(self, name): pool = self.get_storagepool(name, self.conn) try: pool.destroy() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0010E", + {'name': name, 'err': e.get_error_message()})
def delete(self, name): pool = self.get_storagepool(name, self.conn) if pool.isActive(): - err = "Unable to delete the active storagepool %s" - raise InvalidOperation(err % name) + raise InvalidOperation("KCHPOOL0005E", {'name': name}) try: pool.undefine() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHPOOL0011E", + {'name': name, 'err': e.get_error_message()})
class IsoPoolModel(object): diff --git a/src/kimchi/model/storageservers.py b/src/kimchi/model/storageservers.py index 6a7c14a..26e1f6f 100644 --- a/src/kimchi/model/storageservers.py +++ b/src/kimchi/model/storageservers.py @@ -75,4 +75,4 @@ class StorageServerModel(object): # lookup pass
- raise NotFoundError('server %s does not used by kimchi' % server) + raise NotFoundError("KCHSR0001E", {'server': server}) diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py index 8440a76..e3f00ca 100644 --- a/src/kimchi/model/storagevolumes.py +++ b/src/kimchi/model/storagevolumes.py @@ -57,29 +57,33 @@ class StorageVolumesModel(object): params.setdefault('allocation', 0) params.setdefault('format', 'qcow2')
+ name = params['name'] try: pool = StoragePoolModel.get_storagepool(pool, self.conn) - name = params['name'] xml = vol_xml % params - except KeyError, key: - raise MissingParameter(key) + except KeyError, item: + raise MissingParameter("KCHVOL0004E", {'item': item, + 'volume': name})
try: pool.createXML(xml, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0007E", + {'name': name, 'pool': pool, + 'err': e.get_error_message()}) return name
- def get_list(self, pool): - pool = StoragePoolModel.get_storagepool(pool, self.conn) + def get_list(self, pool_name): + pool = StoragePoolModel.get_storagepool(pool_name, self.conn) if not pool.isActive(): - err = "Unable to list volumes in inactive storagepool %s" - raise InvalidOperation(err % pool.name()) + raise InvalidOperation("KCHVOL0006E", {'pool': pool_name}) try: pool.refresh(0) return pool.listVolumes() except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0008E", + {'pool': pool_name, + 'err': e.get_error_message()})
class StorageVolumeModel(object): @@ -89,13 +93,13 @@ class StorageVolumeModel(object): def _get_storagevolume(self, pool, name): pool = StoragePoolModel.get_storagepool(pool, self.conn) if not pool.isActive(): - err = "Unable to list volumes in inactive storagepool %s" - raise InvalidOperation(err % pool.name()) + raise InvalidOperation("KCHVOL0006E", {'name': pool}) try: return pool.storageVolLookupByName(name) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL: - raise NotFoundError("Storage Volume '%s' not found" % name) + raise NotFoundError("KCHVOL0002E", {'name': name, + 'pool': pool}) else: raise
@@ -131,14 +135,16 @@ class StorageVolumeModel(object): try: volume.wipePattern(libvirt.VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0009E", + {'name': name, 'err': e.get_error_message()})
def delete(self, pool, name): volume = self._get_storagevolume(pool, name) try: volume.delete(0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0010E", + {'name': name, 'err': e.get_error_message()})
def resize(self, pool, name, size): size = size << 20 @@ -146,7 +152,8 @@ class StorageVolumeModel(object): try: volume.resize(size, 0) except libvirt.libvirtError as e: - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVOL0011E", + {'name': name, 'err': e.get_error_message()})
class IsoVolumesModel(object): diff --git a/src/kimchi/model/templates.py b/src/kimchi/model/templates.py index 03632a6..0eb7faa 100644 --- a/src/kimchi/model/templates.py +++ b/src/kimchi/model/templates.py @@ -25,7 +25,7 @@ import copy import libvirt
from kimchi import xmlutils -from kimchi.exception import InvalidOperation, InvalidParameter, NotFoundError +from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.utils import pool_name_from_uri from kimchi.vmtemplate import VMTemplate
@@ -44,20 +44,20 @@ class TemplatesModel(object): pool_name = pool_name_from_uri(pool_uri) try: conn.storagePoolLookupByName(pool_name) - except Exception as e: - err = "Storagepool specified is not valid: %s." - raise InvalidParameter(err % e.message) + except Exception: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': name})
for net_name in params.get(u'networks', []): try: conn.networkLookupByName(net_name) - except Exception, e: - raise InvalidParameter("Network '%s' specified by template " - "does not exist." % net_name) + except Exception: + raise InvalidParameter("KCHTMPL0003E", {'network': net_name, + 'template': name})
with self.objstore as session: if name in session.get_list('template'): - raise InvalidOperation("Template already exists") + raise InvalidOperation("KCHTMPL0001E", {'name': name}) t = LibvirtVMTemplate(params, scan=True) session.store('template', name, t.info) return name @@ -100,17 +100,17 @@ class TemplateModel(object): try: conn = self.conn.get() conn.storagePoolLookupByName(pool_name) - except Exception as e: - err = "Storagepool specified is not valid: %s." - raise InvalidParameter(err % e.message) + except Exception: + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': name})
for net_name in params.get(u'networks', []): try: conn = self.conn.get() conn.networkLookupByName(net_name) - except Exception, e: - raise InvalidParameter("Network '%s' specified by template " - "does not exist" % net_name) + except Exception: + raise InvalidParameter("KCHTMPL0003E", {'network': net_name, + 'template': name})
self.delete(name) try: @@ -133,12 +133,12 @@ class LibvirtVMTemplate(VMTemplate): conn = self.conn.get() pool = conn.storagePoolLookupByName(pool_name) except libvirt.libvirtError: - err = 'Storage specified by template does not exist' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0004E", {'pool': pool_name, + 'template': self.name})
if not pool.isActive(): - err = 'Storage specified by template is not active' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0005E", {'pool': pool_name, + 'template': self.name})
return pool
@@ -149,12 +149,12 @@ class LibvirtVMTemplate(VMTemplate): conn = self.conn.get() network = conn.networkLookupByName(name) except libvirt.libvirtError: - err = 'Network specified by template does not exist' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0003E", {'network': name, + 'template': self.name})
if not network.isActive(): - err = 'Network specified by template is not active' - raise InvalidParameter(err) + raise InvalidParameter("KCHTMPL0007E", {'network': name, + 'template': self.name})
def _get_storage_path(self): pool = self._storage_validate() diff --git a/src/kimchi/model/utils.py b/src/kimchi/model/utils.py index a27b867..b642f05 100644 --- a/src/kimchi/model/utils.py +++ b/src/kimchi/model/utils.py @@ -30,4 +30,4 @@ def get_vm_name(vm_name, t_name, name_list): vm_name = "%s-vm-%i" % (t_name, i) if vm_name not in name_list: return vm_name - raise OperationFailed("Unable to choose a VM name") + raise OperationFailed("KCHUTILS0003E") diff --git a/src/kimchi/model/vmifaces.py b/src/kimchi/model/vmifaces.py index f3eddb2..f526e0d 100644 --- a/src/kimchi/model/vmifaces.py +++ b/src/kimchi/model/vmifaces.py @@ -52,13 +52,12 @@ class VMIfacesModel(object): networks = conn.listNetworks() + conn.listDefinedNetworks()
if params["type"] == "network" and params["network"] not in networks: - raise InvalidParameter("%s is not an available network" % - params["network"]) + raise InvalidParameter("KCHVMIF0002E", + {'name': vm, 'network': params["network"]})
dom = VMModel.get_vm(vm, self.conn) if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - raise InvalidOperation("do not support hot plugging attach " - "guest interface") + raise InvalidOperation("KCHVMIF0003E")
macs = (iface.mac.get('address') for iface in self.get_vmifaces(vm, self.conn)) @@ -108,7 +107,7 @@ class VMIfaceModel(object):
iface = self._get_vmiface(vm, mac) if iface is None: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac})
info['type'] = iface.attrib['type'] info['mac'] = iface.mac.get('address') @@ -126,10 +125,10 @@ class VMIfaceModel(object): iface = self._get_vmiface(vm, mac)
if DOM_STATE_MAP[dom.info()[0]] != "shutoff": - raise InvalidOperation("do not support hot plugging detach " - "guest interface") + raise InvalidOperation("KCHVMIF0003E") + if iface is None: - raise NotFoundError('iface: "%s"' % mac) + raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface': mac})
dom.detachDeviceFlags(etree.tostring(iface), libvirt.VIR_DOMAIN_AFFECT_CURRENT) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index d4384a1..d9e4f20 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -163,7 +163,7 @@ class VMsModel(object): name = get_vm_name(params.get('name'), t_name, vm_list) # incoming text, from js json, is unicode, do not need decode if name in vm_list: - raise InvalidOperation("VM already exists") + raise InvalidOperation("KCHVM0001E", {'name': name})
vm_overrides = dict() pool_uri = params.get('storagepool') @@ -173,8 +173,7 @@ class VMsModel(object): vm_overrides)
if not self.caps.qemu_stream and t.info.get('iso_stream', False): - err = "Remote ISO image is not supported by this server." - raise InvalidOperation(err) + raise InvalidOperation("KCHVM0005E")
t.validate() vol_list = t.fork_vm_storage(vm_uuid) @@ -201,7 +200,8 @@ class VMsModel(object): for v in vol_list: vol = conn.storageVolLookupByPath(v['path']) vol.delete(0) - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVM0007E", {'name': name, + 'err': e.get_error_message()})
return name
@@ -237,15 +237,16 @@ class VMModel(object): try: if 'name' in params: if state == 'running': - err = "VM name only can be updated when vm is powered off." - raise InvalidParameter(err) + msg_args = {'name': dom.name(), 'new_name': params['name']} + raise InvalidParameter("KCHVM0003E", msg_args) else: dom.undefine() conn = self.conn.get() dom = conn.defineXML(new_xml) except libvirt.libvirtError as e: dom = conn.defineXML(old_xml) - raise OperationFailed(e.get_error_message()) + raise OperationFailed("KCHVM0008E", {'name': dom.name(), + 'err': e.get_error_message()}) return dom
def _live_vm_update(self, dom, params): @@ -308,8 +309,8 @@ class VMModel(object): except NotFoundError: return False except Exception, e: - err = "Unable to retrieve VM '%s': %s" - raise OperationFailed(err % (name, e.message)) + raise OperationFailed("KCHVM0009E", {'name': name, + 'err': e.message})
@staticmethod def get_vm(name, conn): @@ -319,7 +320,7 @@ class VMModel(object): return conn.lookupByName(name.encode("utf-8")) except libvirt.libvirtError as e: if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: - raise NotFoundError("Virtual Machine '%s' not found" % name) + raise NotFoundError("KCHVM0002E", {'name': name}) else: raise
@@ -384,8 +385,7 @@ class VMModel(object): if graphics_port is not None: vnc.add_proxy_token(name, graphics_port) else: - raise OperationFailed("Only able to connect to running vm's vnc " - "graphics.") + raise OperationFailed("KCHVM0010E", {'name': name})
def _vmscreenshot_delete(self, vm_uuid): screenshot = VMScreenshotModel.get_screenshot(vm_uuid, self.objstore, @@ -405,7 +405,7 @@ class VMScreenshotModel(object): d_info = dom.info() vm_uuid = dom.UUIDString() if DOM_STATE_MAP[d_info[0]] != 'running': - raise NotFoundError('No screenshot for stopped vm') + raise NotFoundError("KCHVM0004E", {'name': name})
screenshot = self.get_screenshot(vm_uuid, self.objstore, self.conn) img_path = screenshot.lookup() @@ -448,7 +448,7 @@ class LibvirtVMScreenshot(VMScreenshot): stream.abort() except: pass - raise NotFoundError("Screenshot not supported for %s" % vm_name) + raise NotFoundError("KCHVM0006E", {'name': vm_name}) else: stream.finish() finally: diff --git a/src/kimchi/objectstore.py b/src/kimchi/objectstore.py index 7b567f3..5cb8ae1 100644 --- a/src/kimchi/objectstore.py +++ b/src/kimchi/objectstore.py @@ -54,7 +54,7 @@ class ObjectStoreSession(object): jsonstr = res.fetchall()[0][0] except IndexError: self.conn.rollback() - raise NotFoundError(ident) + raise NotFoundError("KCHOBJST0001E", {'item': ident}) return json.loads(jsonstr)
def delete(self, obj_type, ident, ignore_missing=False): @@ -63,7 +63,7 @@ class ObjectStoreSession(object): (obj_type, ident)) if c.rowcount != 1 and not ignore_missing: self.conn.rollback() - raise NotFoundError(ident) + raise NotFoundError("KCHOBJST0001E", {'item': ident}) self.conn.commit()
def store(self, obj_type, ident, data): diff --git a/src/kimchi/template.py b/src/kimchi/template.py index 173e7c6..fd1d591 100644 --- a/src/kimchi/template.py +++ b/src/kimchi/template.py @@ -27,6 +27,7 @@ import json import os
+from kimchi.config import paths from Cheetah.Template import Template from glob import iglob
@@ -53,7 +54,6 @@ def get_lang():
def get_support_languages(): - paths = cherrypy.request.app.root.paths mopath = "%s/*" % paths.mo_dir return [path.rsplit('/', 1)[1] for path in iglob(mopath)]
diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index 8795957..a1410c0 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -29,12 +29,10 @@ import urllib2 from threading import Timer
from cherrypy.lib.reprconf import Parser -from kimchi.config import paths, PluginPaths -from kimchi.exception import TimeoutExpired -
from kimchi.asynctask import AsyncTask -from kimchi.exception import InvalidParameter +from kimchi.config import paths, PluginPaths +from kimchi.exception import InvalidParameter, TimeoutExpired
kimchi_log = cherrypy.log.error_log @@ -45,7 +43,7 @@ def _uri_to_name(collection, uri): expr = '/%s/(.*?)/?$' % collection m = re.match(expr, uri) if not m: - raise InvalidParameter(uri) + raise InvalidParameter("KCHUTILS0001E", {'uri': uri}) return m.group(1)
@@ -169,7 +167,9 @@ def run_command(cmd, timeout=None): msg = ("subprocess is killed by signal.SIGKILL for " "timeout %s seconds" % timeout) kimchi_log.error(msg) - raise TimeoutExpired(msg) + + msg_args = {'cmd': cmd, 'seconds': timeout} + raise TimeoutExpired("KCHUTILS0002E", msg_args)
return out, error, proc.returncode except TimeoutExpired: diff --git a/src/kimchi/vmtemplate.py b/src/kimchi/vmtemplate.py index 58147e3..7aa0a65 100644 --- a/src/kimchi/vmtemplate.py +++ b/src/kimchi/vmtemplate.py @@ -27,7 +27,6 @@ import urllib import urlparse
-from kimchi import isoinfo Is this change related to this patch?
Seems I removed an useless import. I will revert and send a separated patch for that.
from kimchi import osinfo from kimchi.exception import InvalidParameter, IsoFormatError from kimchi.isoinfo import IsoImage @@ -58,7 +57,7 @@ class VMTemplate(object):
iso_prefixes = ['/', 'http', 'https', 'ftp', 'ftps', 'tftp'] if len(filter(iso.startswith, iso_prefixes)) == 0: - raise InvalidParameter("Invalid parameter specified for cdrom.") + raise InvalidParameter("KCHTMPL0006E", {'param': iso})
if not iso.startswith('/'): self.info.update({'iso_stream': True}) @@ -66,8 +65,8 @@ class VMTemplate(object): try: iso_img = IsoImage(iso) iso_distro, iso_version = iso_img.probe() - except IsoFormatError, e: - raise InvalidParameter(e) + except IsoFormatError: + raise InvalidParameter("KCHISO0001E", {'filename': iso})
# Fetch defaults based on the os distro and version os_distro = args.get('os_distro', iso_distro) diff --git a/tests/test_exception.py b/tests/test_exception.py index b64ab94..79c8e4f 100644 --- a/tests/test_exception.py +++ b/tests/test_exception.py @@ -77,8 +77,8 @@ class ExceptionTests(unittest.TestCase): # test 400 missing required parameter req = json.dumps({}) resp = json.loads(request(host, port, '/vms', req, 'POST').read()) - msg = u"Invalid parameter: 'u'template' is a required property'" self.assertEquals('400 Bad Request', resp.get('code')) + msg = u"KCHVM0016E: Specify a template to create a Virtual Machine from" self.assertEquals(msg, resp.get('reason')) self.assertNotIn('call_stack', resp)
@@ -107,7 +107,7 @@ class ExceptionTests(unittest.TestCase): # test 400 missing required parameter req = json.dumps({}) resp = json.loads(request(host, port, '/vms', req, 'POST').read()) - msg = u"Invalid parameter: 'u'template' is a required property'" + msg = u"KCHVM0016E: Specify a template to create a Virtual Machine from" self.assertEquals('400 Bad Request', resp.get('code')) self.assertEquals(msg, resp.get('reason')) self.assertIn('call_stack', resp) diff --git a/tests/test_rest.py b/tests/test_rest.py index 0ed293b..4b58e18 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -568,7 +568,7 @@ class RestTests(unittest.TestCase): resp = self.request('/vms', req, 'POST') self.assertEquals(400, resp.status) resp = json.loads(resp.read()) - self.assertIn('Invalid parameter', resp['reason']) + self.assertIn(u"KCHVM0016E:", resp['reason'])
def test_create_vm_with_bad_template_uri(self): req = json.dumps({'name': 'vm-bad-template', @@ -576,7 +576,7 @@ class RestTests(unittest.TestCase): resp = self.request('/vms', req, 'POST') self.assertEquals(400, resp.status) resp = json.loads(resp.read()) - self.assertIn('Invalid parameter', resp['reason']) + self.assertIn(u"KCHVM0012E", resp['reason'])
def test_get_storagepools(self): storagepools = json.loads(self.request('/storagepools').read()) diff --git a/tests/utils.py b/tests/utils.py index 40dfae2..14c57d4 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -155,8 +155,9 @@ def patch_auth(): def _authenticate(username, password, service="passwd"): try: return fake_user[username] == password - except KeyError: - raise OperationFailed('Bad login') + except KeyError, e: + raise OperationFailed("KCHAUTH0001E", {'userid': 'username', + 'code': e.message})
import kimchi.auth kimchi.auth.authenticate = _authenticate I see some parts of the code raising exceptions that are still not following this translation model. For instance, ImportError at src/kimchi/utils.py, and Exception in src/kimchi/config.py and src/kimchi/websocket.py. Shouldn't we translate all exception messages?
The translated messages are those shown to the user. Which means they need to be raise through Kimchi exceptions (all those in src/kimchi/exception.py) Any other exception needs to converted to the Kimchi exceptions. For example: def raise_common_exception(): raise Exception() If this message will be shown to the user it needs to be: try: raise_common_exception() except: raise OperarionFailed(<translatable-msg>) I will check all those causes you pointed out to verify if they are follow this principle.
Best regards,
Leonardo Garcia

From: Aline Manera <alinefm@br.ibm.com> As the backend messages will be translated on backend, the i18n.py file need to be added to POTFILES.in Also update gen-pot to properly add the translatable messages to .pot file. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- po/POTFILES.in | 1 + po/gen-pot.in | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 3627f42..4ff7eaa 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -16,3 +16,4 @@ ui/pages/tabs/storage.html.tmpl ui/pages/template-add.html.tmpl ui/pages/template-edit.html.tmpl ui/pages/vnc_auto.html.tmpl +src/kimchi/i18n.py diff --git a/po/gen-pot.in b/po/gen-pot.in index a845bae..0e3cd10 100644 --- a/po/gen-pot.in +++ b/po/gen-pot.in @@ -1,3 +1,9 @@ #!/bin/bash -for src in $@; do cat $src | @CHEETAH@ compile - ;done | xgettext --no-location -o kimchi.pot -L Python - +for src in $@; do + if [ ${src: -3} == ".py" ]; then + cat $src + else + cat $src | @CHEETAH@ compile - + fi +done | xgettext --no-location -o kimchi.pot -L Python - -- 1.7.10.4

Reviewed-by: Leonardo Garcia <lagarcia@br.ibm.com> On 02/09/2014 08:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
As the backend messages will be translated on backend, the i18n.py file need to be added to POTFILES.in Also update gen-pot to properly add the translatable messages to .pot file.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- po/POTFILES.in | 1 + po/gen-pot.in | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/po/POTFILES.in b/po/POTFILES.in index 3627f42..4ff7eaa 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -16,3 +16,4 @@ ui/pages/tabs/storage.html.tmpl ui/pages/template-add.html.tmpl ui/pages/template-edit.html.tmpl ui/pages/vnc_auto.html.tmpl +src/kimchi/i18n.py diff --git a/po/gen-pot.in b/po/gen-pot.in index a845bae..0e3cd10 100644 --- a/po/gen-pot.in +++ b/po/gen-pot.in @@ -1,3 +1,9 @@ #!/bin/bash
-for src in $@; do cat $src | @CHEETAH@ compile - ;done | xgettext --no-location -o kimchi.pot -L Python - +for src in $@; do + if [ ${src: -3} == ".py" ]; then + cat $src + else + cat $src | @CHEETAH@ compile - + fi +done | xgettext --no-location -o kimchi.pot -L Python -

From: Aline Manera <alinefm@br.ibm.com> Instead of using UI message, we can display the messages from backend as they are also translated to the current language Also associate a code to the UI messages and display error messages like: <code>: <msg> For that, create a new function kimchi.message.error.code to display those messages. The function kimchi.message.error will be used to display error messages came from backend (that are already in format <code>: <msg>) Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- ui/js/src/kimchi.api.js | 4 +- ui/js/src/kimchi.guest_add_main.js | 7 +- ui/js/src/kimchi.guest_main.js | 32 +++--- ui/js/src/kimchi.host.js | 46 ++++---- ui/js/src/kimchi.line-chart.js | 2 +- ui/js/src/kimchi.login_window.js | 8 +- ui/js/src/kimchi.main.js | 6 +- ui/js/src/kimchi.message.js | 4 + ui/js/src/kimchi.network.js | 22 ++-- ui/js/src/kimchi.report_add_main.js | 8 +- ui/js/src/kimchi.storage_main.js | 18 ++-- ui/js/src/kimchi.storagepool_add_main.js | 28 ++--- ui/js/src/kimchi.template_add_main.js | 18 ++-- ui/js/src/kimchi.template_main.js | 16 +-- ui/js/widgets/filter-select.js | 4 +- ui/js/widgets/select-menu.js | 4 +- ui/pages/i18n.html.tmpl | 172 ++++++++++++++---------------- 17 files changed, 194 insertions(+), 205 deletions(-) diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 63ddd88..6433fe0 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -307,7 +307,7 @@ var kimchi = { window.open(url); }); }).error(function() { - kimchi.message.error(i18n['msg.fail.get.config']); + kimchi.message.error.code('KCHAPI6002E'); }); }, @@ -330,7 +330,7 @@ var kimchi = { window.open(url); }); }).error(function() { - kimchi.message.error(i18n['msg.fail.get.config']); + kimchi.message.error.code('KCHAPI6002E'); }); }, diff --git a/ui/js/src/kimchi.guest_add_main.js b/ui/js/src/kimchi.guest_add_main.js index 2085562..7ada1e3 100644 --- a/ui/js/src/kimchi.guest_add_main.js +++ b/ui/js/src/kimchi.guest_add_main.js @@ -44,8 +44,8 @@ kimchi.guest_add_main = function() { $('#prompt-choose-template').addClass('hidden'); $('#prompt-create-template').removeClass('hidden'); - }, function() { - kimchi.message.error(i18n['temp.msg.fail.list']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }; @@ -72,8 +72,7 @@ kimchi.guest_add_main = function() { var reason = jqXHR && jqXHR['responseJSON'] && jqXHR['responseJSON']['reason']; - reason = reason ? ': ' + reason : ''; - kimchi.message.error(i18n['vm.msg.fail.create.vm'] + reason); + kimchi.message.error(reason); }); return false; diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 8467f3f..99cb84a 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -25,8 +25,8 @@ kimchi.initVmButtonsAction = function() { $(this).addClass('loading'); kimchi.startVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.start']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { event.preventDefault(); @@ -40,8 +40,8 @@ kimchi.initVmButtonsAction = function() { $(this).addClass('loading'); kimchi.stopVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.stop']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { event.preventDefault(); @@ -79,14 +79,14 @@ kimchi.initVmButtonsAction = function() { if ('running' === $(this).data('vmstate')) { kimchi.resetVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.reset']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { kimchi.startVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.start']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } }); @@ -94,16 +94,16 @@ kimchi.initVmButtonsAction = function() { $(".vm-delete").on("click", function(event) { var vm = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.vm.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHVM6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { kimchi.deleteVM(vm.data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.delete']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }, function() { }); @@ -214,8 +214,8 @@ kimchi.listVmsAuto = function() { } kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); - }, function() { - kimchi.message.error(i18n['msg.fail.list.guests']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); }); }; diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index e9279fb..a5c341b 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -31,10 +31,10 @@ kimchi.host_main = function() { reportGrid = new kimchi.widget.Grid({ container: 'available-reports-grid-container', id: reportGridID, - title: i18n['msg.host.debugreport.title'], + title: i18n['KCHDR6002M'], toolbarButtons: [{ id: reportGridID + '-generate-button', - label: i18n['msg.host.debugreport.generate'], + label: i18n['KCHDR6006M'], onClick: function(event) { kimchi.window.open('report-add.html', { close: function() { @@ -44,13 +44,13 @@ kimchi.host_main = function() { } }, { id: reportGridID + '-rename-button', - label: i18n['msg.host.debugreport.rename'], + label: i18n['KCHDR6008M'], disabled: true, onClick: function(event) { } }, { id: reportGridID + '-remove-button', - label: i18n['msg.host.debugreport.remove'], + label: i18n['KCHDR6009M'], disabled: true, onClick: function(event) { var report = reportGrid.getSelected(); @@ -59,10 +59,10 @@ kimchi.host_main = function() { } var settings = { - title : i18n['msg.host.debugreport.confirm.title'], - content : i18n['msg.host.debugreport.confirm.content'], - confirm : i18n['msg.confirm'], - cancel : i18n['msg.cancel'] + title : i18n['KCHAPI6004M'], + content : i18n['KCHDR6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { @@ -76,7 +76,7 @@ kimchi.host_main = function() { } }, { id: reportGridID + '-download-button', - label: i18n['msg.host.debugreport.download'], + label: i18n['KCHDR6010M'], disabled: true, onClick: function(event) { var report = reportGrid.getSelected(); @@ -102,15 +102,15 @@ kimchi.host_main = function() { }], fields: [{ name: 'name', - label: i18n['msg.host.debugreport.name'], + label: i18n['KCHDR6003M'], 'class': 'debug-report-name' }, { name: 'file', - label: i18n['msg.host.debugreport.file'], + label: i18n['KCHDR6004M'], 'class': 'debug-report-file' }, { name: 'time', - label: i18n['msg.host.debugreport.time'], + label: i18n['KCHDR6005M'], 'class': 'debug-report-time' }], data: reports @@ -135,10 +135,10 @@ kimchi.host_main = function() { var restartButtonID = '#host-button-restart'; var shutdownHost = function(params) { var settings = { - title : i18n['msg.host.shutdown.confirm.title'], - content : i18n['msg.host.shutdown.confirm.content'], - confirm : i18n['msg.confirm'], - cancel : i18n['msg.cancel'] + title : i18n['KCHAPI6004M'], + content : i18n['KCHHOST6008M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { @@ -149,7 +149,7 @@ kimchi.host_main = function() { kimchi.listVMs(function(vms) { for(var i = 0; i < vms.length; i++) { if(vms[i]['state'] === 'running') { - kimchi.message.warn(i18n['msg.host.shutdown.vmrunning']); + kimchi.message.error.code('KCHHOST6001E'); $(shutdownButtonID).prop('disabled', false); $(restartButtonID).prop('disabled', false); return; @@ -220,7 +220,7 @@ kimchi.host_main = function() { cpu: { u: { type: 'percent', - legend: i18n['msg.host.chartlegend.cpu'], + legend: i18n['KCHHOST6002M'], points: [] } }, @@ -229,7 +229,7 @@ kimchi.host_main = function() { type: 'value', base: 2, fixed: 2, - legend: i18n['msg.host.chartlegend.memory.available'], + legend: i18n['KCHHOST6003M'], points: [] } }, @@ -239,7 +239,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.disk.read'], + legend: i18n['KCHHOST6004M'], points: [] }, w: { @@ -247,7 +247,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.disk.write'], + legend: i18n['KCHHOST6005M'], 'class': 'disk-write', points: [] } @@ -258,7 +258,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.network.received'], + legend: i18n['KCHHOST6006M'], points: [] }, s: { @@ -266,7 +266,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.network.sent'], + legend: i18n['KCHHOST6007M'], 'class': 'network-sent', points: [] } diff --git a/ui/js/src/kimchi.line-chart.js b/ui/js/src/kimchi.line-chart.js index 3685677..4e59cb4 100644 --- a/ui/js/src/kimchi.line-chart.js +++ b/ui/js/src/kimchi.line-chart.js @@ -110,7 +110,7 @@ kimchi.widget.LineChart = function(params) { ); } - var maxValueLabel = i18n['msg.host.chartaxis.max'] + ' ' + + var maxValueLabel = i18n['KCHHOST6001M'] + ' ' + (type === 'value' ? kimchi.formatMeasurement(maxValue, formatSettings) : '100%'); diff --git a/ui/js/src/kimchi.login_window.js b/ui/js/src/kimchi.login_window.js index 6396a1e..59de389 100644 --- a/ui/js/src/kimchi.login_window.js +++ b/ui/js/src/kimchi.login_window.js @@ -42,7 +42,7 @@ kimchi.login_main = function() { for(var i = 0; i < idsArray.length; i++) { var id = idsArray[i]; if (!$('#' + id).val()) { - $('#' + id + '-msg').text(i18n['msg.login.requiredfield']); + $('#' + id + '-msg').text(i18n['KCHAUTH6002E']); placeCursor(id); return false; } @@ -75,7 +75,7 @@ kimchi.login_main = function() { return false; } - $('#btn-login').text(i18n['msg.login.loggingin']).prop('disabled', true); + $('#btn-login').text(i18n['KCHAUTH6002M']).prop('disabled', true); var userID = $('#user-id').val(); userID && kimchi.user.setUserID(userID); @@ -95,8 +95,8 @@ kimchi.login_main = function() { kimchi.user.showUser(true); kimchi.window.close(); }, function() { - $('#message-container').text(i18n['msg.login.failed']); - $('#btn-login').prop('disabled', false).text(i18n['msg.login.login']); + $('#message-container').text(i18n['KCHAUTH6001E']); + $('#btn-login').prop('disabled', false).text(i18n['KCHAUTH6001M']); placeCursor('user-id'); }); diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js index cc8afee..5387495 100644 --- a/ui/js/src/kimchi.main.js +++ b/ui/js/src/kimchi.main.js @@ -46,7 +46,7 @@ kimchi.main = function() { */ var tab = $('#nav-menu a[href="' + url + '"]'); if (tab.length === 0) { - kimchi.message.error(i18n['msg.err.uri.invalid']); + kimchi.message.error.code('KCHAPI6001E'); location.hash = ''; return; } @@ -138,8 +138,8 @@ kimchi.main = function() { $('#btn-logout').on('click', function() { kimchi.logout(function() { updatePage(); - }, function() { - kimchi.message.error(i18n['msg.logout.failed']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }); }; diff --git a/ui/js/src/kimchi.message.js b/ui/js/src/kimchi.message.js index 770f999..844febc 100644 --- a/ui/js/src/kimchi.message.js +++ b/ui/js/src/kimchi.message.js @@ -107,6 +107,10 @@ kimchi.message.warn = function(msg) { kimchi.message.error = function(msg) { kimchi.message(msg, 'error'); }; +kimchi.message.error.code = function(code) { + msg = code + ": " + i18n[code] + kimchi.message(msg, 'error'); +}; kimchi.message.success = function(msg) { kimchi.message(msg, 'success'); }; diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js index 0a3026f..c1f87ce 100644 --- a/ui/js/src/kimchi.network.js +++ b/ui/js/src/kimchi.network.js @@ -54,10 +54,10 @@ kimchi.addNetworkItem = function(network) { kimchi.getNetworkItemHtml = function(network) { if(!network.interface) { - network.interface = i18n["value_unavailable"]; + network.interface = i18n["KCHNET6001M"]; } if(!network.addrSpace) { - network.addrSpace = i18n["value_unavailable"]; + network.addrSpace = i18n["KCHNET6001M"]; } if(i18n["network_type_" + network.type]) { network.type = i18n["network_type_" + network.type]; @@ -104,10 +104,10 @@ kimchi.addNetworkActions = function(network) { }); } else if ($(evt.currentTarget).attr("nwAct") === "delete") { kimchi.confirm({ - title : i18n['msg_warning'], - content : i18n['network_action_confirm'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6006M'], + content : i18n['KCHNET6002M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }, function() { kimchi.deleteNetwork(network.name, function() { $(evt.currentTarget).parents(".item").remove(); @@ -143,15 +143,15 @@ kimchi.initNetworkCreation = function() { if ($("#enableVlan").prop("checked")) { data.vlan_id = network.vlan_id; if (!(data.vlan_id >=1 && data.vlan_id <= 4094)) { - kimchi.message.error(i18n['msg.invalid.vlan_id']); + kimchi.message.error.code('KCHNET6001E'); return; } } } kimchi.createNetwork(data, function(result) { network.state = result.state === "active" ? "up" : "down"; - network.interface = result.interface ? result.interface : i18n["value_unavailable"]; - network.addrSpace = result.subnet ? result.subnet : i18n["value_unavailable"]; + network.interface = result.interface ? result.interface : i18n["KCHNET6001M"]; + network.addrSpace = result.subnet ? result.subnet : i18n["KCHNET6001M"]; kimchi.addNetworkItem(network); $("#networkConfig").dialog("close"); }); @@ -176,7 +176,7 @@ kimchi.initNetworkDialog = function() { }, buttons : [ { id : "networkFormOk", - text : i18n.action_create, + text : i18n.KCHAPI6005M, class: "ui-button-primary", disabled: true, click : function() { @@ -196,7 +196,7 @@ kimchi.openNetworkDialog = function(okCallback) { kimchi.setDefaultNetworkType(result.length!==0); }); $("#networkConfig").dialog({ - title : i18n.network_dialog_title_create + title : i18n.KCHNET6003M }); $("#networkFormOk").on("click", function() { okCallback(); diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js index 9826c38..f893d85 100644 --- a/ui/js/src/kimchi.report_add_main.js +++ b/ui/js/src/kimchi.report_add_main.js @@ -16,7 +16,7 @@ kimchi.report_add_main = function() { var formData = addReportForm.serializeObject(); errorMessage.text(''); submitButton - .text(i18n['msg.host.debugreport.generating']) + .text(i18n['KCHDR6007M']) .prop('disabled', true); nameTextbox.prop('disabled', true); kimchi.createReport(formData, function(result) { @@ -25,10 +25,10 @@ kimchi.report_add_main = function() { result: result }); }, function(result) { - result && result['message'] && - $('#report-error-message').text(result['message']); + result && result['reason'] && + $('#report-error-message').text(result['reason']); submitButton - .text(i18n['msg.host.debugreport.generate']) + .text(i18n['KCHDR6006M']) .prop('disabled', false); nameTextbox.prop('disabled', false).focus(); }); diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js index 5605f4b..d65da0b 100644 --- a/ui/js/src/kimchi.storage_main.js +++ b/ui/js/src/kimchi.storage_main.js @@ -36,8 +36,8 @@ kimchi.doListStoragePools = function() { } else { $('#storagepoolsList').html(''); } - }, function() { - kimchi.message.error(i18n['kimchi.list.storage.fail.msg']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } @@ -79,10 +79,10 @@ kimchi.storageBindClick = function() { $('.pool-delete').on('click', function(event) { var $pool = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.storagepool.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { var poolName = $pool.data('name'); @@ -159,14 +159,14 @@ kimchi.doListVolumes = function(poolObj) { }); volumeDiv.html(listHtml); } else { - volumeDiv.html("<div class='pool-empty'>" + i18n['msg.kimchi.storage.pool.empty'] + "</div>"); + volumeDiv.html("<div class='pool-empty'>" + i18n['KCHPOOL6002M'] + "</div>"); } poolObj.removeClass('in'); kimchi.changeArrow(handleArrow); slide.slideDown('slow'); } - }, function() { - kimchi.message.error(i18n['msg.kimchi.list.volume.fail']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js index e5922b3..ac97e1a 100644 --- a/ui/js/src/kimchi.storagepool_add_main.js +++ b/ui/js/src/kimchi.storagepool_add_main.js @@ -141,11 +141,11 @@ kimchi.validateForm = function() { var name = $('#poolId').val(); var poolType = $("#poolTypeInputId").val(); if ('' === name) { - kimchi.message.error(i18n['msg.pool.edit.name.blank']); + kimchi.message.error.code('KCHPOOL6001E'); return false; } if (!/^[\w-]+$/.test(name)) { - kimchi.message.error(i18n['msg.validate.pool.edit.name']); + kimchi.message.error.code('KCHPOOL6004E'); return false; } if (poolType === "dir") { @@ -164,11 +164,11 @@ kimchi.validateForm = function() { kimchi.validateDirForm = function () { var path = $('#pathId').val(); if ('' === path) { - kimchi.message.error(i18n['msg.pool.edit.path.blank']); + kimchi.message.error.code('KCHPOOL6002E'); return false; } if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(path)) { - kimchi.message.error(i18n['msg.validate.pool.edit.path']); + kimchi.message.error.code('KCHAPI6003E'); return false; } return true; @@ -181,11 +181,11 @@ kimchi.validateNfsForm = function () { return false; } if ('' === nfspath) { - kimchi.message.error(i18n['msg.pool.edit.nfspath.blank']); + kimchi.message.error.code('KCHPOOL6003E'); return false; } if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(nfspath)) { - kimchi.message.error(i18n['msg.validate.pool.edit.nfspath']); + kimchi.message.error.code('KCHPOOL6005E'); return false; } return true; @@ -198,7 +198,7 @@ kimchi.validateIscsiForm = function() { return false; } if ('' === iscsiTarget) { - kimchi.message.error(i18n['msg.pool.edit.iscsitarget.blank']); + kimchi.message.error.code('KCHPOOL6007E'); return false; } return true; @@ -206,11 +206,11 @@ kimchi.validateIscsiForm = function() { kimchi.validateServer = function(serverField) { if ('' === serverField) { - kimchi.message.error(i18n['msg.pool.edit.server.blank']); + kimchi.message.error.code('KCHPOOL6008E'); return false; } if(!kimchi.isServer(serverField)) { - kimchi.message.error(i18n['msg.validate.pool.edit.server']); + kimchi.message.error.code('KCHPOOL6009E'); return false; } return true; @@ -218,7 +218,7 @@ kimchi.validateServer = function(serverField) { kimchi.validateLogicalForm = function () { if ($("input[name=devices]:checked").length === 0) { - kimchi.message.error(i18n['msg.validate.pool.edit.logical.device']); + kimchi.message.error.code('KCHPOOL6006E'); return false; } else { return true; @@ -263,10 +263,10 @@ kimchi.addPool = function(event) { } if (poolType === 'logical') { var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.logicalpool.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6003M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { kimchi.createStoragePool(formData, function() { diff --git a/ui/js/src/kimchi.template_add_main.js b/ui/js/src/kimchi.template_add_main.js index 85e73a2..1b1f413 100644 --- a/ui/js/src/kimchi.template_add_main.js +++ b/ui/js/src/kimchi.template_add_main.js @@ -72,7 +72,7 @@ kimchi.template_add_main = function() { $('#iso-search').click(function() { var settings = { - content : i18n['msg.template.iso.search.confirm'] + content : i18n['KCHTMPL6002M'] }; kimchi.confirm(settings, function() { $('#iso-search').hide(); @@ -83,7 +83,7 @@ kimchi.template_add_main = function() { $('#iso-more').click(function() { var settings = { - content : i18n['msg.template.iso.search.confirm'] + content : i18n['KCHTMPL6002M'] }; kimchi.confirm(settings, function() { $('#iso-more').hide(); @@ -119,7 +119,7 @@ kimchi.template_add_main = function() { showLocalIsoField(isos); } else { if (isFinished) { - kimchi.message.warn(i18n['msg.fail.template.no.iso']); + kimchi.message.warn(i18n['KCHTMPL6001W']); } } if (isFinished) { @@ -214,11 +214,11 @@ kimchi.template_add_main = function() { $('#btn-template-file-create').click(function() { var isoFile = $('#iso-file').val(); if (!kimchi.is_iso_file(isoFile)) { - kimchi.message.error(i18n['msg.invalid.iso']); + kimchi.message.error.code('KCHTMPL6002E'); return; } if (!kimchi.template_check_path(isoFile)) { - kimchi.message.error(i18n['msg.invalid.path']); + kimchi.message.error.code('KCHAPI6003E'); return; } var data = { @@ -274,7 +274,7 @@ kimchi.template_add_main = function() { $('#list-remote-iso').html(html); $('#remote-iso-field').show(); } else { - kimchi.message.warn(i18n['msg.fail.template.no.iso']); + kimchi.message.warn(i18n['KCHTMPL6001W']); } }; @@ -330,7 +330,7 @@ kimchi.template_add_main = function() { $('#btn-template-url-create').click(function() { var isoUrl = $('#iso-url').val(); if (!kimchi.template_check_url(isoUrl)) { - kimchi.message.error(i18n['msg.invalid.url']); + kimchi.message.error.code('KCHAPI6004E'); return; } var data = { @@ -365,7 +365,7 @@ kimchi.template_add_main = function() { }; kimchi.createTemplate(data, function() { successNum++; - kimchi.message.success(i18n['msg.success.create.template'] + ': ' + isoInfo.name); + kimchi.message.success(i18n['KCHTMPL6001M'] + ': ' + isoInfo.name); $('input[value="' + isoInfo.isoId + '"]').prop('checked', false); $('.check-all>input').prop('checked', false); kimchi.doListTemplates(); @@ -374,7 +374,7 @@ kimchi.template_add_main = function() { kimchi.window.close(); } }, function(err) { - kimchi.message.error(i18n['msg.fail.create.template'] + ': ' + isoInfo.name + '<br>' + err.responseJSON.reason); + kimchi.message.error(err.responseJSON.reason); }); }; if (formData.iso instanceof Array) { diff --git a/ui/js/src/kimchi.template_main.js b/ui/js/src/kimchi.template_main.js index ffc7306..0904e71 100644 --- a/ui/js/src/kimchi.template_main.js +++ b/ui/js/src/kimchi.template_main.js @@ -33,8 +33,8 @@ kimchi.doListTemplates = function() { $('#templateList').html(''); $('#noTemplates').show(); } - }, function() { - kimchi.message.error(i18n['kimchi.list.template.fail.msg']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }; @@ -47,17 +47,17 @@ kimchi.bindClick = function() { $('.template-delete').on('click', function(event) { var $template = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.template.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHTMPL6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { var templateName = $template.data('template'); kimchi.deleteTemplate(templateName, function() { kimchi.doListTemplates(); - }, function() { - kimchi.message.error(i18n['fail.delete.template']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }, function() { }); diff --git a/ui/js/widgets/filter-select.js b/ui/js/widgets/filter-select.js index 44030a1..9e024cf 100644 --- a/ui/js/widgets/filter-select.js +++ b/ui/js/widgets/filter-select.js @@ -55,7 +55,7 @@ that.listControl.html(''); var items = that._dataList(options); if (items.length === 0) { - that.listControl.html(i18n['msg.no.mapping.result']); + that.listControl.html(i18n['KCHAPI6005E']); } else { $.each(items, function(index, item) { that.listControl.append(item); @@ -75,7 +75,7 @@ }); if (that.listControl.html() === '') { that.target.addClass("invalid-field"); - that.listControl.html(i18n['msg.no.mapping.result']); + that.listControl.html(i18n['KCHAPI6005E']); } else { that.target.removeClass("invalid-field"); } diff --git a/ui/js/widgets/select-menu.js b/ui/js/widgets/select-menu.js index c9a1b87..c213f3c 100644 --- a/ui/js/widgets/select-menu.js +++ b/ui/js/widgets/select-menu.js @@ -62,7 +62,7 @@ } }); } else { - kimchi.message.error(i18n['selectmenu.data.error']); + kimchi.message.code.error('KCHAPI6006E'); } }, @@ -83,4 +83,4 @@ $.Widget.prototype.destroy.call(this); } }); -}(jQuery)); \ No newline at end of file +}(jQuery)); diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl index d63d4e9..540c07c 100644 --- a/ui/pages/i18n.html.tmpl +++ b/ui/pages/i18n.html.tmpl @@ -36,99 +36,85 @@ <body> <script> var i18n = { - 'temp.msg.fail.list': "$_("Failed to list the template")", - 'temp.msg.choose.temp': "$_("Please choose a template")", - 'vm.msg.fail.create.vm': "$_("Failed to create vm")", - 'msg.login.failed': "$_("The username or password you entered is incorrect. Please try again.")", - 'msg.login.requiredfield': "$_("This field is required.")", - 'msg.login.login': "$_("Log in")", - 'msg.login.loggingin': "$_("Logging in...")", - 'msg.err.uri.invalid': "$_("Invalid URL. Redireced to home page.")", - 'msg.404.gotohomepage': "$_("Go to Homepage")", - 'msg.fail.start': "$_("Failed to start")", - 'msg.fail.stop': "$_("Failed to stop")", - 'msg.fail.reset': "$_("Failed to reset")", - 'msg.fail.delete': "$_("Failed to delete")", - 'msg.fail.list.guests': "$_("Failed to list guests")", - 'msg.fail.create.template': "$_("Failed to create template")", - 'msg.success.create.template': "$_("Create template successfully")", - 'msg.fail.template.no.iso': "$_("No iso found")", - 'msg.fail.template.scan': "$_("Failed to scan")", - 'msg.fail.template.distr': "$_("Failed to list iso distributions")", - 'msg.confirm.delete.title': "$_("Delete Confirmation")", - 'msg.confirm': "$_("OK")", - 'msg.cancel': "$_("Cancel")", - 'msg.confirm.delete.confirm': "$_("OK")", - 'msg.confirm.delete.cancel': "$_("Cancel")", - 'msg.host.chartaxis.max': "$_("Max:")", - 'msg.host.chartlegend.cpu': "$_("Utilization")", - 'msg.host.chartlegend.memory.available': "$_("Available")", - 'msg.host.chartlegend.disk.read': "$_("Read Rate")", - 'msg.host.chartlegend.disk.write': "$_("Write Rate")", - 'msg.host.chartlegend.network.received': "$_("Received")", - 'msg.host.chartlegend.network.sent': "$_("Sent")", - 'msg.host.debugreport.confirm.title': "$_("Confirm")", - 'msg.host.debugreport.confirm.content': "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")", - 'msg.host.debugreport.title': "$_("Debug Reports")", - 'msg.host.debugreport.name': "$_("Name")", - 'msg.host.debugreport.file': "$_("File Path")", - 'msg.host.debugreport.time': "$_("Generated Time")", - 'msg.host.debugreport.generate': "$_("Generate")", - 'msg.host.debugreport.generating': "$_("Generating...")", - 'msg.host.debugreport.rename': "$_("Rename")", - 'msg.host.debugreport.remove': "$_("Remove")", - 'msg.host.debugreport.download': "$_("Download")", - 'msg.host.shutdown.vmrunning': "$_("Some VM(s) are running!")", - 'msg.host.shutdown.confirm.title': "$_("Confirm")", - 'msg.host.shutdown.confirm.content': "$_("Shutting down or restarting host will cause unsaved work lost. Continue to shut down/restarting?")", - 'msg.vm.confirm.delete': "$_("This will delete the VM and its virtual disks. " - "This operation cannot be undone. " - "Would you like to continue?")", - 'msg.template.confirm.delete': "$_("This will permanently delete the Template. " - "Would you like to continue?")", - 'msg.template.iso.search.confirm': "It will take long time. Do you want to continue?", - 'msg.fail.get.config': "$_("Failed to get application configuration")", - 'msg.invalid.path': "$_("This is not a valid linux path")", - 'msg.invalid.url': "$_("This is not a valid url.")", - 'msg.invalid.vlan_id': "$_("The VLAN id must be between 1 and 4094.")", - 'msg.invalid.iso': "$_("This is not a valid ISO file.")", - 'msg.storagepool.confirm.delete':"$_("This will permanently delete the Storage Pool. Would you like to continue?")", - 'msg.pool.edit.name.blank':"$_("The storage pool name can not be blank.")", - 'msg.pool.edit.path.blank':"$_("The storage pool path can not be blank.")", - 'msg.pool.edit.nfspath.blank':"$_("NFS server mount path can not be blank.")", - 'msg.validate.pool.edit.name':"$_("Invalid Storage Pool name. It may only contain letters, numbers, underscores, and hyphens.")", - 'msg.validate.pool.edit.path':"$_("This is not a real linux path.")", - 'msg.validate.pool.edit.nfspath':"$_("Invalid nfs mount path.")", - 'msg.validate.pool.edit.logical.device':"$_("No logical device selected.")", - 'msg.kimchi.storage.pool.empty':"$_("This storage pool is empty.")", - 'msg.kimchi.list.volume.fail':"$_("Failed to list the storage pool.")", - 'msg.kimchi.storage.pool.not.active':"$_("The storage pool is not active now.")", - 'fail.delete.template': "$_("Failed to delete template.")", - 'Guests':"$_("Guests")", - 'Host':"$_("Host")", - 'Templates':"$_("Templates")", - 'Storage':"$_("Storage")", - 'value_unavailable': "$_("unavailable")", - 'Network':"$_("Network")", - 'network_type_isolated': "$_("isolated")", - 'network_type_nat': "$_("NAT")", - 'network_type_bridged': "$_("bridged")", - 'network_bridged_space': "$_("connected to")", - 'network_action_confirm': "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", - 'network_dialog_title_create': "$_("Create a network")", - 'network_dialog_ok': "$_("OK")", - 'network_dialog_cancel': "$_("Cancel")", - 'action_create': "$_("Create")", - 'msg_warning': "$_("Warning")", - 'msg.logicalpool.confirm.delete': "$_("It will format your disk and you will loose any data in" - " there, are you sure to continue? ")", - 'msg.pool.edit.iscsitarget.blank': "$_("The iSCSI target can not be blank.")", - 'msg.pool.edit.server.blank':"$_("Server name can not be blank.")", - 'msg.validate.pool.edit.server':"$_("This is not a valid Server Name or IP. please, modify it.")", - 'select_default': "$_("Please choose")", - 'msg.no.mapping.result': "$_("No such data exsit.")", - 'msg.no.result' : "$_("No valid result")", - 'selectmenu.data.error' : "$_("options needed.")" + 'KCHAUTH6001E': "$_("The username or password you entered is incorrect. Please try again.")", + 'KCHAUTH6002E': "$_("This field is required.")", + + 'KCHAUTH6001M': "$_("Log in")", + 'KCHAUTH6002M': "$_("Logging in...")", + + 'Host': "$_("Host")", + 'Guests': "$_("Guests")", + 'Templates': "$_("Templates")", + 'Storage': "$_("Storage")", + 'Network': "$_("Network")", + + 'KCHAPI6001E': "$_("Invalid URL. Redireced to home page.")", + 'KCHAPI6002E': "$_("Failed to get application configuration")", + 'KCHAPI6003E': "$_("This is not a valid linux path")", + 'KCHAPI6004E': "$_("This is not a valid url.")", + 'KCHAPI6005E': "$_("No such data exsit.")", + 'KCHAPI6006E': "$_("options needed.")", + + 'KCHAPI6001M': "$_("Delete Confirmation")", + 'KCHAPI6002M': "$_("OK")", + 'KCHAPI6003M': "$_("Cancel")", + 'KCHAPI6004M': "$_("Confirm")", + 'KCHAPI6005M': "$_("Create")", + 'KCHAPI6006M': "$_("Warning")", + + 'KCHTMPL6001M': "$_("Create template successfully")", + + 'KCHTMPL6001W': "$_("No iso found")", + + 'KCHTMPL6002E': "$_("This is not a valid ISO file.")", + + 'KCHTMPL6001M': "$_("This will permanently delete the Template. Would you like to continue?")", + 'KCHTMPL6002M': "$_("It will take long time. Do you want to continue?")", + + 'KCHHOST6001E': "$_("Unable to shut down system as there are some VM(s) running!")", + + 'KCHHOST6001M': "$_("Max:")", + 'KCHHOST6002M': "$_("Utilization")", + 'KCHHOST6003M': "$_("Available")", + 'KCHHOST6004M': "$_("Read Rate")", + 'KCHHOST6005M': "$_("Write Rate")", + 'KCHHOST6006M': "$_("Received")", + 'KCHHOST6007M': "$_("Sent")", + 'KCHHOST6008M': "$_("Shutting down or restarting host will cause unsaved work lost. Continue to shut down/restarting?")", + + 'KCHDR6001M': "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")", + 'KCHDR6002M': "$_("Debug Reports")", + 'KCHDR6003M': "$_("Name")", + 'KCHDR6004M': "$_("File Path")", + 'KCHDR6005M': "$_("Generated Time")", + 'KCHDR6006M': "$_("Generate")", + 'KCHDR6007M': "$_("Generating...")", + 'KCHDR6008M': "$_("Rename")", + 'KCHDR6009M': "$_("Remove")", + 'KCHDR6010M': "$_("Download")", + + + 'KCHVM6001M': "$_("This will delete the VM and its virtual disks. This operation cannot be undone. Would you like to continue?")", + + 'KCHNET6001E': "$_("The VLAN id must be between 1 and 4094.")", + + 'KCHNET6001M': "$_("unavailable")", + 'KCHNET6002M': "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", + 'KCHNET6003M': "$_("Create a network")", + + 'KCHPOOL6001M': "$_("This will permanently delete the Storage Pool. Would you like to continue?")", + 'KCHPOOL6002M': "$_("This storage pool is empty.")", + 'KCHPOOL6003M': "$_("It will format your disk and you will loose any data in there, are you sure to continue? ")", + + 'KCHPOOL6001E': "$_("The Storage Pool name can not be blank.")", + 'KCHPOOL6002E': "$_("The Storage Pool path can not be blank.")", + 'KCHPOOL6003E': "$_("NFS server mount path can not be blank.")", + 'KCHPOOL6004E': "$_("Invalid Storage Pool name. It may only contain letters, numbers, underscores, and hyphens.")", + 'KCHPOOL6005E': "$_("Invalid NFS mount path.")", + 'KCHPOOL6006E': "$_("No logical device selected.")", + 'KCHPOOL6007E': "$_("The iSCSI target can not be blank.")", + 'KCHPOOL6008E': "$_("Server name can not be blank.")", + 'KCHPOOL6009E': "$_("This is not a valid Server Name or IP. please, modify it.")" }; </script> </body> -- 1.7.10.4

On 02/09/2014 08:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Instead of using UI message, we can display the messages from backend as they are also translated to the current language
Also associate a code to the UI messages and display error messages like: <code>: <msg> For that, create a new function kimchi.message.error.code to display those messages. The function kimchi.message.error will be used to display error messages came from backend (that are already in format <code>: <msg>)
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- ui/js/src/kimchi.api.js | 4 +- ui/js/src/kimchi.guest_add_main.js | 7 +- ui/js/src/kimchi.guest_main.js | 32 +++--- ui/js/src/kimchi.host.js | 46 ++++---- ui/js/src/kimchi.line-chart.js | 2 +- ui/js/src/kimchi.login_window.js | 8 +- ui/js/src/kimchi.main.js | 6 +- ui/js/src/kimchi.message.js | 4 + ui/js/src/kimchi.network.js | 22 ++-- ui/js/src/kimchi.report_add_main.js | 8 +- ui/js/src/kimchi.storage_main.js | 18 ++-- ui/js/src/kimchi.storagepool_add_main.js | 28 ++--- ui/js/src/kimchi.template_add_main.js | 18 ++-- ui/js/src/kimchi.template_main.js | 16 +-- ui/js/widgets/filter-select.js | 4 +- ui/js/widgets/select-menu.js | 4 +- ui/pages/i18n.html.tmpl | 172 ++++++++++++++---------------- 17 files changed, 194 insertions(+), 205 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 63ddd88..6433fe0 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -307,7 +307,7 @@ var kimchi = { window.open(url); }); }).error(function() { - kimchi.message.error(i18n['msg.fail.get.config']); + kimchi.message.error.code('KCHAPI6002E'); }); },
@@ -330,7 +330,7 @@ var kimchi = { window.open(url); }); }).error(function() { - kimchi.message.error(i18n['msg.fail.get.config']); + kimchi.message.error.code('KCHAPI6002E'); }); },
diff --git a/ui/js/src/kimchi.guest_add_main.js b/ui/js/src/kimchi.guest_add_main.js index 2085562..7ada1e3 100644 --- a/ui/js/src/kimchi.guest_add_main.js +++ b/ui/js/src/kimchi.guest_add_main.js @@ -44,8 +44,8 @@ kimchi.guest_add_main = function() {
$('#prompt-choose-template').addClass('hidden'); $('#prompt-create-template').removeClass('hidden'); - }, function() { - kimchi.message.error(i18n['temp.msg.fail.list']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); };
@@ -72,8 +72,7 @@ kimchi.guest_add_main = function() { var reason = jqXHR && jqXHR['responseJSON'] && jqXHR['responseJSON']['reason']; - reason = reason ? ': ' + reason : ''; - kimchi.message.error(i18n['vm.msg.fail.create.vm'] + reason); + kimchi.message.error(reason); });
return false; diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 8467f3f..99cb84a 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -25,8 +25,8 @@ kimchi.initVmButtonsAction = function() { $(this).addClass('loading'); kimchi.startVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.start']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { event.preventDefault(); @@ -40,8 +40,8 @@ kimchi.initVmButtonsAction = function() { $(this).addClass('loading'); kimchi.stopVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.stop']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { event.preventDefault(); @@ -79,14 +79,14 @@ kimchi.initVmButtonsAction = function() { if ('running' === $(this).data('vmstate')) { kimchi.resetVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.reset']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { kimchi.startVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.start']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } }); @@ -94,16 +94,16 @@ kimchi.initVmButtonsAction = function() { $(".vm-delete").on("click", function(event) { var vm = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.vm.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHVM6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { kimchi.deleteVM(vm.data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.delete']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }, function() { }); @@ -214,8 +214,8 @@ kimchi.listVmsAuto = function() { }
kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); - }, function() { - kimchi.message.error(i18n['msg.fail.list.guests']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); }); }; diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index e9279fb..a5c341b 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -31,10 +31,10 @@ kimchi.host_main = function() { reportGrid = new kimchi.widget.Grid({ container: 'available-reports-grid-container', id: reportGridID, - title: i18n['msg.host.debugreport.title'], + title: i18n['KCHDR6002M'], toolbarButtons: [{ id: reportGridID + '-generate-button', - label: i18n['msg.host.debugreport.generate'], + label: i18n['KCHDR6006M'], onClick: function(event) { kimchi.window.open('report-add.html', { close: function() { @@ -44,13 +44,13 @@ kimchi.host_main = function() { } }, { id: reportGridID + '-rename-button', - label: i18n['msg.host.debugreport.rename'], + label: i18n['KCHDR6008M'], disabled: true, onClick: function(event) { } }, { id: reportGridID + '-remove-button', - label: i18n['msg.host.debugreport.remove'], + label: i18n['KCHDR6009M'], disabled: true, onClick: function(event) { var report = reportGrid.getSelected(); @@ -59,10 +59,10 @@ kimchi.host_main = function() { }
var settings = { - title : i18n['msg.host.debugreport.confirm.title'], - content : i18n['msg.host.debugreport.confirm.content'], - confirm : i18n['msg.confirm'], - cancel : i18n['msg.cancel'] + title : i18n['KCHAPI6004M'], + content : i18n['KCHDR6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] };
kimchi.confirm(settings, function() { @@ -76,7 +76,7 @@ kimchi.host_main = function() { } }, { id: reportGridID + '-download-button', - label: i18n['msg.host.debugreport.download'], + label: i18n['KCHDR6010M'], disabled: true, onClick: function(event) { var report = reportGrid.getSelected(); @@ -102,15 +102,15 @@ kimchi.host_main = function() { }], fields: [{ name: 'name', - label: i18n['msg.host.debugreport.name'], + label: i18n['KCHDR6003M'], 'class': 'debug-report-name' }, { name: 'file', - label: i18n['msg.host.debugreport.file'], + label: i18n['KCHDR6004M'], 'class': 'debug-report-file' }, { name: 'time', - label: i18n['msg.host.debugreport.time'], + label: i18n['KCHDR6005M'], 'class': 'debug-report-time' }], data: reports @@ -135,10 +135,10 @@ kimchi.host_main = function() { var restartButtonID = '#host-button-restart'; var shutdownHost = function(params) { var settings = { - title : i18n['msg.host.shutdown.confirm.title'], - content : i18n['msg.host.shutdown.confirm.content'], - confirm : i18n['msg.confirm'], - cancel : i18n['msg.cancel'] + title : i18n['KCHAPI6004M'], + content : i18n['KCHHOST6008M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] };
kimchi.confirm(settings, function() { @@ -149,7 +149,7 @@ kimchi.host_main = function() { kimchi.listVMs(function(vms) { for(var i = 0; i < vms.length; i++) { if(vms[i]['state'] === 'running') { - kimchi.message.warn(i18n['msg.host.shutdown.vmrunning']); + kimchi.message.error.code('KCHHOST6001E'); $(shutdownButtonID).prop('disabled', false); $(restartButtonID).prop('disabled', false); return; @@ -220,7 +220,7 @@ kimchi.host_main = function() { cpu: { u: { type: 'percent', - legend: i18n['msg.host.chartlegend.cpu'], + legend: i18n['KCHHOST6002M'], points: [] } }, @@ -229,7 +229,7 @@ kimchi.host_main = function() { type: 'value', base: 2, fixed: 2, - legend: i18n['msg.host.chartlegend.memory.available'], + legend: i18n['KCHHOST6003M'], points: [] } }, @@ -239,7 +239,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.disk.read'], + legend: i18n['KCHHOST6004M'], points: [] }, w: { @@ -247,7 +247,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.disk.write'], + legend: i18n['KCHHOST6005M'], 'class': 'disk-write', points: [] } @@ -258,7 +258,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.network.received'], + legend: i18n['KCHHOST6006M'], points: [] }, s: { @@ -266,7 +266,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.network.sent'], + legend: i18n['KCHHOST6007M'], 'class': 'network-sent', points: [] } diff --git a/ui/js/src/kimchi.line-chart.js b/ui/js/src/kimchi.line-chart.js index 3685677..4e59cb4 100644 --- a/ui/js/src/kimchi.line-chart.js +++ b/ui/js/src/kimchi.line-chart.js @@ -110,7 +110,7 @@ kimchi.widget.LineChart = function(params) { ); }
- var maxValueLabel = i18n['msg.host.chartaxis.max'] + ' ' + + var maxValueLabel = i18n['KCHHOST6001M'] + ' ' + (type === 'value' ? kimchi.formatMeasurement(maxValue, formatSettings) : '100%'); diff --git a/ui/js/src/kimchi.login_window.js b/ui/js/src/kimchi.login_window.js index 6396a1e..59de389 100644 --- a/ui/js/src/kimchi.login_window.js +++ b/ui/js/src/kimchi.login_window.js @@ -42,7 +42,7 @@ kimchi.login_main = function() { for(var i = 0; i < idsArray.length; i++) { var id = idsArray[i]; if (!$('#' + id).val()) { - $('#' + id + '-msg').text(i18n['msg.login.requiredfield']); + $('#' + id + '-msg').text(i18n['KCHAUTH6002E']); placeCursor(id); return false; } @@ -75,7 +75,7 @@ kimchi.login_main = function() { return false; }
- $('#btn-login').text(i18n['msg.login.loggingin']).prop('disabled', true); + $('#btn-login').text(i18n['KCHAUTH6002M']).prop('disabled', true);
var userID = $('#user-id').val(); userID && kimchi.user.setUserID(userID); @@ -95,8 +95,8 @@ kimchi.login_main = function() { kimchi.user.showUser(true); kimchi.window.close(); }, function() { - $('#message-container').text(i18n['msg.login.failed']); - $('#btn-login').prop('disabled', false).text(i18n['msg.login.login']); + $('#message-container').text(i18n['KCHAUTH6001E']); + $('#btn-login').prop('disabled', false).text(i18n['KCHAUTH6001M']); placeCursor('user-id'); });
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js index cc8afee..5387495 100644 --- a/ui/js/src/kimchi.main.js +++ b/ui/js/src/kimchi.main.js @@ -46,7 +46,7 @@ kimchi.main = function() { */ var tab = $('#nav-menu a[href="' + url + '"]'); if (tab.length === 0) { - kimchi.message.error(i18n['msg.err.uri.invalid']); + kimchi.message.error.code('KCHAPI6001E'); location.hash = ''; return; } @@ -138,8 +138,8 @@ kimchi.main = function() { $('#btn-logout').on('click', function() { kimchi.logout(function() { updatePage(); - }, function() { - kimchi.message.error(i18n['msg.logout.failed']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }); }; diff --git a/ui/js/src/kimchi.message.js b/ui/js/src/kimchi.message.js index 770f999..844febc 100644 --- a/ui/js/src/kimchi.message.js +++ b/ui/js/src/kimchi.message.js @@ -107,6 +107,10 @@ kimchi.message.warn = function(msg) { kimchi.message.error = function(msg) { kimchi.message(msg, 'error'); }; +kimchi.message.error.code = function(code) { + msg = code + ": " + i18n[code] + kimchi.message(msg, 'error'); +}; kimchi.message.success = function(msg) { kimchi.message(msg, 'success'); }; diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js index 0a3026f..c1f87ce 100644 --- a/ui/js/src/kimchi.network.js +++ b/ui/js/src/kimchi.network.js @@ -54,10 +54,10 @@ kimchi.addNetworkItem = function(network) {
kimchi.getNetworkItemHtml = function(network) { if(!network.interface) { - network.interface = i18n["value_unavailable"]; + network.interface = i18n["KCHNET6001M"]; } if(!network.addrSpace) { - network.addrSpace = i18n["value_unavailable"]; + network.addrSpace = i18n["KCHNET6001M"]; } if(i18n["network_type_" + network.type]) { network.type = i18n["network_type_" + network.type]; @@ -104,10 +104,10 @@ kimchi.addNetworkActions = function(network) { }); } else if ($(evt.currentTarget).attr("nwAct") === "delete") { kimchi.confirm({ - title : i18n['msg_warning'], - content : i18n['network_action_confirm'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6006M'], + content : i18n['KCHNET6002M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }, function() { kimchi.deleteNetwork(network.name, function() { $(evt.currentTarget).parents(".item").remove(); @@ -143,15 +143,15 @@ kimchi.initNetworkCreation = function() { if ($("#enableVlan").prop("checked")) { data.vlan_id = network.vlan_id; if (!(data.vlan_id >=1 && data.vlan_id <= 4094)) { - kimchi.message.error(i18n['msg.invalid.vlan_id']); + kimchi.message.error.code('KCHNET6001E'); return; } } } kimchi.createNetwork(data, function(result) { network.state = result.state === "active" ? "up" : "down"; - network.interface = result.interface ? result.interface : i18n["value_unavailable"]; - network.addrSpace = result.subnet ? result.subnet : i18n["value_unavailable"]; + network.interface = result.interface ? result.interface : i18n["KCHNET6001M"]; + network.addrSpace = result.subnet ? result.subnet : i18n["KCHNET6001M"]; kimchi.addNetworkItem(network); $("#networkConfig").dialog("close"); }); @@ -176,7 +176,7 @@ kimchi.initNetworkDialog = function() { }, buttons : [ { id : "networkFormOk", - text : i18n.action_create, + text : i18n.KCHAPI6005M, class: "ui-button-primary", disabled: true, click : function() { @@ -196,7 +196,7 @@ kimchi.openNetworkDialog = function(okCallback) { kimchi.setDefaultNetworkType(result.length!==0); }); $("#networkConfig").dialog({ - title : i18n.network_dialog_title_create + title : i18n.KCHNET6003M }); $("#networkFormOk").on("click", function() { okCallback(); diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js index 9826c38..f893d85 100644 --- a/ui/js/src/kimchi.report_add_main.js +++ b/ui/js/src/kimchi.report_add_main.js @@ -16,7 +16,7 @@ kimchi.report_add_main = function() { var formData = addReportForm.serializeObject(); errorMessage.text(''); submitButton - .text(i18n['msg.host.debugreport.generating']) + .text(i18n['KCHDR6007M']) .prop('disabled', true); nameTextbox.prop('disabled', true); kimchi.createReport(formData, function(result) { @@ -25,10 +25,10 @@ kimchi.report_add_main = function() { result: result }); }, function(result) { - result && result['message'] && - $('#report-error-message').text(result['message']); + result && result['reason'] && + $('#report-error-message').text(result['reason']); submitButton - .text(i18n['msg.host.debugreport.generate']) + .text(i18n['KCHDR6006M']) .prop('disabled', false); nameTextbox.prop('disabled', false).focus(); }); diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js index 5605f4b..d65da0b 100644 --- a/ui/js/src/kimchi.storage_main.js +++ b/ui/js/src/kimchi.storage_main.js @@ -36,8 +36,8 @@ kimchi.doListStoragePools = function() { } else { $('#storagepoolsList').html(''); } - }, function() { - kimchi.message.error(i18n['kimchi.list.storage.fail.msg']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); });
} @@ -79,10 +79,10 @@ kimchi.storageBindClick = function() { $('.pool-delete').on('click', function(event) { var $pool = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.storagepool.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { var poolName = $pool.data('name'); @@ -159,14 +159,14 @@ kimchi.doListVolumes = function(poolObj) { }); volumeDiv.html(listHtml); } else { - volumeDiv.html("<div class='pool-empty'>" + i18n['msg.kimchi.storage.pool.empty'] + "</div>"); + volumeDiv.html("<div class='pool-empty'>" + i18n['KCHPOOL6002M'] + "</div>"); } poolObj.removeClass('in'); kimchi.changeArrow(handleArrow); slide.slideDown('slow'); } - }, function() { - kimchi.message.error(i18n['msg.kimchi.list.volume.fail']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js index e5922b3..ac97e1a 100644 --- a/ui/js/src/kimchi.storagepool_add_main.js +++ b/ui/js/src/kimchi.storagepool_add_main.js @@ -141,11 +141,11 @@ kimchi.validateForm = function() { var name = $('#poolId').val(); var poolType = $("#poolTypeInputId").val(); if ('' === name) { - kimchi.message.error(i18n['msg.pool.edit.name.blank']); + kimchi.message.error.code('KCHPOOL6001E'); return false; } if (!/^[\w-]+$/.test(name)) { - kimchi.message.error(i18n['msg.validate.pool.edit.name']); + kimchi.message.error.code('KCHPOOL6004E'); return false; } if (poolType === "dir") { @@ -164,11 +164,11 @@ kimchi.validateForm = function() { kimchi.validateDirForm = function () { var path = $('#pathId').val(); if ('' === path) { - kimchi.message.error(i18n['msg.pool.edit.path.blank']); + kimchi.message.error.code('KCHPOOL6002E'); return false; } if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(path)) { - kimchi.message.error(i18n['msg.validate.pool.edit.path']); + kimchi.message.error.code('KCHAPI6003E'); return false; } return true; @@ -181,11 +181,11 @@ kimchi.validateNfsForm = function () { return false; } if ('' === nfspath) { - kimchi.message.error(i18n['msg.pool.edit.nfspath.blank']); + kimchi.message.error.code('KCHPOOL6003E'); return false; } if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(nfspath)) { - kimchi.message.error(i18n['msg.validate.pool.edit.nfspath']); + kimchi.message.error.code('KCHPOOL6005E'); return false; } return true; @@ -198,7 +198,7 @@ kimchi.validateIscsiForm = function() { return false; } if ('' === iscsiTarget) { - kimchi.message.error(i18n['msg.pool.edit.iscsitarget.blank']); + kimchi.message.error.code('KCHPOOL6007E'); return false; } return true; @@ -206,11 +206,11 @@ kimchi.validateIscsiForm = function() {
kimchi.validateServer = function(serverField) { if ('' === serverField) { - kimchi.message.error(i18n['msg.pool.edit.server.blank']); + kimchi.message.error.code('KCHPOOL6008E'); return false; } if(!kimchi.isServer(serverField)) { - kimchi.message.error(i18n['msg.validate.pool.edit.server']); + kimchi.message.error.code('KCHPOOL6009E'); return false; } return true; @@ -218,7 +218,7 @@ kimchi.validateServer = function(serverField) {
kimchi.validateLogicalForm = function () { if ($("input[name=devices]:checked").length === 0) { - kimchi.message.error(i18n['msg.validate.pool.edit.logical.device']); + kimchi.message.error.code('KCHPOOL6006E'); return false; } else { return true; @@ -263,10 +263,10 @@ kimchi.addPool = function(event) { } if (poolType === 'logical') { var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.logicalpool.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6003M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { kimchi.createStoragePool(formData, function() { diff --git a/ui/js/src/kimchi.template_add_main.js b/ui/js/src/kimchi.template_add_main.js index 85e73a2..1b1f413 100644 --- a/ui/js/src/kimchi.template_add_main.js +++ b/ui/js/src/kimchi.template_add_main.js @@ -72,7 +72,7 @@ kimchi.template_add_main = function() {
$('#iso-search').click(function() { var settings = { - content : i18n['msg.template.iso.search.confirm'] + content : i18n['KCHTMPL6002M'] }; kimchi.confirm(settings, function() { $('#iso-search').hide(); @@ -83,7 +83,7 @@ kimchi.template_add_main = function() {
$('#iso-more').click(function() { var settings = { - content : i18n['msg.template.iso.search.confirm'] + content : i18n['KCHTMPL6002M'] }; kimchi.confirm(settings, function() { $('#iso-more').hide(); @@ -119,7 +119,7 @@ kimchi.template_add_main = function() { showLocalIsoField(isos); } else { if (isFinished) { - kimchi.message.warn(i18n['msg.fail.template.no.iso']); + kimchi.message.warn(i18n['KCHTMPL6001W']); } } if (isFinished) { @@ -214,11 +214,11 @@ kimchi.template_add_main = function() { $('#btn-template-file-create').click(function() { var isoFile = $('#iso-file').val(); if (!kimchi.is_iso_file(isoFile)) { - kimchi.message.error(i18n['msg.invalid.iso']); + kimchi.message.error.code('KCHTMPL6002E'); return; } if (!kimchi.template_check_path(isoFile)) { - kimchi.message.error(i18n['msg.invalid.path']); + kimchi.message.error.code('KCHAPI6003E'); return; } var data = { @@ -274,7 +274,7 @@ kimchi.template_add_main = function() { $('#list-remote-iso').html(html); $('#remote-iso-field').show(); } else { - kimchi.message.warn(i18n['msg.fail.template.no.iso']); + kimchi.message.warn(i18n['KCHTMPL6001W']); } };
@@ -330,7 +330,7 @@ kimchi.template_add_main = function() { $('#btn-template-url-create').click(function() { var isoUrl = $('#iso-url').val(); if (!kimchi.template_check_url(isoUrl)) { - kimchi.message.error(i18n['msg.invalid.url']); + kimchi.message.error.code('KCHAPI6004E'); return; } var data = { @@ -365,7 +365,7 @@ kimchi.template_add_main = function() { }; kimchi.createTemplate(data, function() { successNum++; - kimchi.message.success(i18n['msg.success.create.template'] + ': ' + isoInfo.name); + kimchi.message.success(i18n['KCHTMPL6001M'] + ': ' + isoInfo.name); $('input[value="' + isoInfo.isoId + '"]').prop('checked', false); $('.check-all>input').prop('checked', false); kimchi.doListTemplates(); @@ -374,7 +374,7 @@ kimchi.template_add_main = function() { kimchi.window.close(); } }, function(err) { - kimchi.message.error(i18n['msg.fail.create.template'] + ': ' + isoInfo.name + '<br>' + err.responseJSON.reason); + kimchi.message.error(err.responseJSON.reason); }); }; if (formData.iso instanceof Array) { diff --git a/ui/js/src/kimchi.template_main.js b/ui/js/src/kimchi.template_main.js index ffc7306..0904e71 100644 --- a/ui/js/src/kimchi.template_main.js +++ b/ui/js/src/kimchi.template_main.js @@ -33,8 +33,8 @@ kimchi.doListTemplates = function() { $('#templateList').html(''); $('#noTemplates').show(); } - }, function() { - kimchi.message.error(i18n['kimchi.list.template.fail.msg']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); };
@@ -47,17 +47,17 @@ kimchi.bindClick = function() { $('.template-delete').on('click', function(event) { var $template = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.template.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHTMPL6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { var templateName = $template.data('template'); kimchi.deleteTemplate(templateName, function() { kimchi.doListTemplates(); - }, function() { - kimchi.message.error(i18n['fail.delete.template']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }, function() { }); diff --git a/ui/js/widgets/filter-select.js b/ui/js/widgets/filter-select.js index 44030a1..9e024cf 100644 --- a/ui/js/widgets/filter-select.js +++ b/ui/js/widgets/filter-select.js @@ -55,7 +55,7 @@ that.listControl.html(''); var items = that._dataList(options); if (items.length === 0) { - that.listControl.html(i18n['msg.no.mapping.result']); + that.listControl.html(i18n['KCHAPI6005E']); } else { $.each(items, function(index, item) { that.listControl.append(item); @@ -75,7 +75,7 @@ }); if (that.listControl.html() === '') { that.target.addClass("invalid-field"); - that.listControl.html(i18n['msg.no.mapping.result']); + that.listControl.html(i18n['KCHAPI6005E']); } else { that.target.removeClass("invalid-field"); } diff --git a/ui/js/widgets/select-menu.js b/ui/js/widgets/select-menu.js index c9a1b87..c213f3c 100644 --- a/ui/js/widgets/select-menu.js +++ b/ui/js/widgets/select-menu.js @@ -62,7 +62,7 @@ } }); } else { - kimchi.message.error(i18n['selectmenu.data.error']); + kimchi.message.code.error('KCHAPI6006E'); } },
@@ -83,4 +83,4 @@ $.Widget.prototype.destroy.call(this); } }); -}(jQuery)); \ No newline at end of file +}(jQuery)); diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl index d63d4e9..540c07c 100644 --- a/ui/pages/i18n.html.tmpl +++ b/ui/pages/i18n.html.tmpl @@ -36,99 +36,85 @@ <body> <script> var i18n = { - 'temp.msg.fail.list': "$_("Failed to list the template")", - 'temp.msg.choose.temp': "$_("Please choose a template")", - 'vm.msg.fail.create.vm': "$_("Failed to create vm")", - 'msg.login.failed': "$_("The username or password you entered is incorrect. Please try again.")", - 'msg.login.requiredfield': "$_("This field is required.")", - 'msg.login.login': "$_("Log in")", - 'msg.login.loggingin': "$_("Logging in...")", - 'msg.err.uri.invalid': "$_("Invalid URL. Redireced to home page.")", - 'msg.404.gotohomepage': "$_("Go to Homepage")", - 'msg.fail.start': "$_("Failed to start")", - 'msg.fail.stop': "$_("Failed to stop")", - 'msg.fail.reset': "$_("Failed to reset")", - 'msg.fail.delete': "$_("Failed to delete")", - 'msg.fail.list.guests': "$_("Failed to list guests")", - 'msg.fail.create.template': "$_("Failed to create template")", - 'msg.success.create.template': "$_("Create template successfully")", - 'msg.fail.template.no.iso': "$_("No iso found")", - 'msg.fail.template.scan': "$_("Failed to scan")", - 'msg.fail.template.distr': "$_("Failed to list iso distributions")", - 'msg.confirm.delete.title': "$_("Delete Confirmation")", - 'msg.confirm': "$_("OK")", - 'msg.cancel': "$_("Cancel")", - 'msg.confirm.delete.confirm': "$_("OK")", - 'msg.confirm.delete.cancel': "$_("Cancel")", - 'msg.host.chartaxis.max': "$_("Max:")", - 'msg.host.chartlegend.cpu': "$_("Utilization")", - 'msg.host.chartlegend.memory.available': "$_("Available")", - 'msg.host.chartlegend.disk.read': "$_("Read Rate")", - 'msg.host.chartlegend.disk.write': "$_("Write Rate")", - 'msg.host.chartlegend.network.received': "$_("Received")", - 'msg.host.chartlegend.network.sent': "$_("Sent")", - 'msg.host.debugreport.confirm.title': "$_("Confirm")", - 'msg.host.debugreport.confirm.content': "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")", - 'msg.host.debugreport.title': "$_("Debug Reports")", - 'msg.host.debugreport.name': "$_("Name")", - 'msg.host.debugreport.file': "$_("File Path")", - 'msg.host.debugreport.time': "$_("Generated Time")", - 'msg.host.debugreport.generate': "$_("Generate")", - 'msg.host.debugreport.generating': "$_("Generating...")", - 'msg.host.debugreport.rename': "$_("Rename")", - 'msg.host.debugreport.remove': "$_("Remove")", - 'msg.host.debugreport.download': "$_("Download")", - 'msg.host.shutdown.vmrunning': "$_("Some VM(s) are running!")", - 'msg.host.shutdown.confirm.title': "$_("Confirm")", - 'msg.host.shutdown.confirm.content': "$_("Shutting down or restarting host will cause unsaved work lost. Continue to shut down/restarting?")", - 'msg.vm.confirm.delete': "$_("This will delete the VM and its virtual disks. " - "This operation cannot be undone. " - "Would you like to continue?")", - 'msg.template.confirm.delete': "$_("This will permanently delete the Template. " - "Would you like to continue?")", - 'msg.template.iso.search.confirm': "It will take long time. Do you want to continue?", - 'msg.fail.get.config': "$_("Failed to get application configuration")", - 'msg.invalid.path': "$_("This is not a valid linux path")", - 'msg.invalid.url': "$_("This is not a valid url.")", - 'msg.invalid.vlan_id': "$_("The VLAN id must be between 1 and 4094.")", - 'msg.invalid.iso': "$_("This is not a valid ISO file.")", - 'msg.storagepool.confirm.delete':"$_("This will permanently delete the Storage Pool. Would you like to continue?")", - 'msg.pool.edit.name.blank':"$_("The storage pool name can not be blank.")", - 'msg.pool.edit.path.blank':"$_("The storage pool path can not be blank.")", - 'msg.pool.edit.nfspath.blank':"$_("NFS server mount path can not be blank.")", - 'msg.validate.pool.edit.name':"$_("Invalid Storage Pool name. It may only contain letters, numbers, underscores, and hyphens.")", - 'msg.validate.pool.edit.path':"$_("This is not a real linux path.")", - 'msg.validate.pool.edit.nfspath':"$_("Invalid nfs mount path.")", - 'msg.validate.pool.edit.logical.device':"$_("No logical device selected.")", - 'msg.kimchi.storage.pool.empty':"$_("This storage pool is empty.")", - 'msg.kimchi.list.volume.fail':"$_("Failed to list the storage pool.")", - 'msg.kimchi.storage.pool.not.active':"$_("The storage pool is not active now.")", - 'fail.delete.template': "$_("Failed to delete template.")", - 'Guests':"$_("Guests")", - 'Host':"$_("Host")", - 'Templates':"$_("Templates")", - 'Storage':"$_("Storage")", - 'value_unavailable': "$_("unavailable")", - 'Network':"$_("Network")", - 'network_type_isolated': "$_("isolated")", - 'network_type_nat': "$_("NAT")", - 'network_type_bridged': "$_("bridged")", - 'network_bridged_space': "$_("connected to")", - 'network_action_confirm': "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", - 'network_dialog_title_create': "$_("Create a network")", - 'network_dialog_ok': "$_("OK")", - 'network_dialog_cancel': "$_("Cancel")", - 'action_create': "$_("Create")", - 'msg_warning': "$_("Warning")", - 'msg.logicalpool.confirm.delete': "$_("It will format your disk and you will loose any data in" - " there, are you sure to continue? ")", - 'msg.pool.edit.iscsitarget.blank': "$_("The iSCSI target can not be blank.")", - 'msg.pool.edit.server.blank':"$_("Server name can not be blank.")", - 'msg.validate.pool.edit.server':"$_("This is not a valid Server Name or IP. please, modify it.")", - 'select_default': "$_("Please choose")", - 'msg.no.mapping.result': "$_("No such data exsit.")", - 'msg.no.result' : "$_("No valid result")", - 'selectmenu.data.error' : "$_("options needed.")" + 'KCHAUTH6001E': "$_("The username or password you entered is incorrect. Please try again.")", + 'KCHAUTH6002E': "$_("This field is required.")", + + 'KCHAUTH6001M': "$_("Log in")", + 'KCHAUTH6002M': "$_("Logging in...")", + + 'Host': "$_("Host")", + 'Guests': "$_("Guests")", + 'Templates': "$_("Templates")", + 'Storage': "$_("Storage")", + 'Network': "$_("Network")", + + 'KCHAPI6001E': "$_("Invalid URL. Redireced to home page.")", + 'KCHAPI6002E': "$_("Failed to get application configuration")", + 'KCHAPI6003E': "$_("This is not a valid linux path")", + 'KCHAPI6004E': "$_("This is not a valid url.")", + 'KCHAPI6005E': "$_("No such data exsit.")", + 'KCHAPI6006E': "$_("options needed.")", + + 'KCHAPI6001M': "$_("Delete Confirmation")", + 'KCHAPI6002M': "$_("OK")", + 'KCHAPI6003M': "$_("Cancel")", + 'KCHAPI6004M': "$_("Confirm")", + 'KCHAPI6005M': "$_("Create")", + 'KCHAPI6006M': "$_("Warning")", + + 'KCHTMPL6001M': "$_("Create template successfully")", + + 'KCHTMPL6001W': "$_("No iso found")", + + 'KCHTMPL6002E': "$_("This is not a valid ISO file.")", + + 'KCHTMPL6001M': "$_("This will permanently delete the Template. Would you like to continue?")", At least this code is being used more than once: KCHTMPL6001M.
Also, don't we have same messages here and in /src/kimchi/i18n.py? I think we should have only one repository for messages in the code that could be used for both backend and frontend.
+ 'KCHTMPL6002M': "$_("It will take long time. Do you want to continue?")", + + 'KCHHOST6001E': "$_("Unable to shut down system as there are some VM(s) running!")", + + 'KCHHOST6001M': "$_("Max:")", + 'KCHHOST6002M': "$_("Utilization")", + 'KCHHOST6003M': "$_("Available")", + 'KCHHOST6004M': "$_("Read Rate")", + 'KCHHOST6005M': "$_("Write Rate")", + 'KCHHOST6006M': "$_("Received")", + 'KCHHOST6007M': "$_("Sent")", + 'KCHHOST6008M': "$_("Shutting down or restarting host will cause unsaved work lost. Continue to shut down/restarting?")", + + 'KCHDR6001M': "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")", + 'KCHDR6002M': "$_("Debug Reports")", + 'KCHDR6003M': "$_("Name")", + 'KCHDR6004M': "$_("File Path")", + 'KCHDR6005M': "$_("Generated Time")", + 'KCHDR6006M': "$_("Generate")", + 'KCHDR6007M': "$_("Generating...")", + 'KCHDR6008M': "$_("Rename")", + 'KCHDR6009M': "$_("Remove")", + 'KCHDR6010M': "$_("Download")", + + + 'KCHVM6001M': "$_("This will delete the VM and its virtual disks. This operation cannot be undone. Would you like to continue?")", + + 'KCHNET6001E': "$_("The VLAN id must be between 1 and 4094.")", + + 'KCHNET6001M': "$_("unavailable")", + 'KCHNET6002M': "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", + 'KCHNET6003M': "$_("Create a network")", + + 'KCHPOOL6001M': "$_("This will permanently delete the Storage Pool. Would you like to continue?")", + 'KCHPOOL6002M': "$_("This storage pool is empty.")", + 'KCHPOOL6003M': "$_("It will format your disk and you will loose any data in there, are you sure to continue? ")", + + 'KCHPOOL6001E': "$_("The Storage Pool name can not be blank.")", + 'KCHPOOL6002E': "$_("The Storage Pool path can not be blank.")", + 'KCHPOOL6003E': "$_("NFS server mount path can not be blank.")", + 'KCHPOOL6004E': "$_("Invalid Storage Pool name. It may only contain letters, numbers, underscores, and hyphens.")", + 'KCHPOOL6005E': "$_("Invalid NFS mount path.")", + 'KCHPOOL6006E': "$_("No logical device selected.")", + 'KCHPOOL6007E': "$_("The iSCSI target can not be blank.")", + 'KCHPOOL6008E': "$_("Server name can not be blank.")", + 'KCHPOOL6009E': "$_("This is not a valid Server Name or IP. please, modify it.")" }; </script> </body> Messages in ui/js/kimchi.min.js have not been adapted to this new reference paradigm.
Best regards, Leonardo Garcia

On 02/11/2014 01:11 AM, Leonardo Augusto Guimarães Garcia wrote:
On 02/09/2014 08:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Instead of using UI message, we can display the messages from backend as they are also translated to the current language
Also associate a code to the UI messages and display error messages like: <code>: <msg> For that, create a new function kimchi.message.error.code to display those messages. The function kimchi.message.error will be used to display error messages came from backend (that are already in format <code>: <msg>)
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- ui/js/src/kimchi.api.js | 4 +- ui/js/src/kimchi.guest_add_main.js | 7 +- ui/js/src/kimchi.guest_main.js | 32 +++--- ui/js/src/kimchi.host.js | 46 ++++---- ui/js/src/kimchi.line-chart.js | 2 +- ui/js/src/kimchi.login_window.js | 8 +- ui/js/src/kimchi.main.js | 6 +- ui/js/src/kimchi.message.js | 4 + ui/js/src/kimchi.network.js | 22 ++-- ui/js/src/kimchi.report_add_main.js | 8 +- ui/js/src/kimchi.storage_main.js | 18 ++-- ui/js/src/kimchi.storagepool_add_main.js | 28 ++--- ui/js/src/kimchi.template_add_main.js | 18 ++-- ui/js/src/kimchi.template_main.js | 16 +-- ui/js/widgets/filter-select.js | 4 +- ui/js/widgets/select-menu.js | 4 +- ui/pages/i18n.html.tmpl | 172 ++++++++++++++---------------- 17 files changed, 194 insertions(+), 205 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js index 63ddd88..6433fe0 100644 --- a/ui/js/src/kimchi.api.js +++ b/ui/js/src/kimchi.api.js @@ -307,7 +307,7 @@ var kimchi = { window.open(url); }); }).error(function() { - kimchi.message.error(i18n['msg.fail.get.config']); + kimchi.message.error.code('KCHAPI6002E'); }); },
@@ -330,7 +330,7 @@ var kimchi = { window.open(url); }); }).error(function() { - kimchi.message.error(i18n['msg.fail.get.config']); + kimchi.message.error.code('KCHAPI6002E'); }); },
diff --git a/ui/js/src/kimchi.guest_add_main.js b/ui/js/src/kimchi.guest_add_main.js index 2085562..7ada1e3 100644 --- a/ui/js/src/kimchi.guest_add_main.js +++ b/ui/js/src/kimchi.guest_add_main.js @@ -44,8 +44,8 @@ kimchi.guest_add_main = function() {
$('#prompt-choose-template').addClass('hidden'); $('#prompt-create-template').removeClass('hidden'); - }, function() { - kimchi.message.error(i18n['temp.msg.fail.list']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); };
@@ -72,8 +72,7 @@ kimchi.guest_add_main = function() { var reason = jqXHR && jqXHR['responseJSON'] && jqXHR['responseJSON']['reason']; - reason = reason ? ': ' + reason : ''; - kimchi.message.error(i18n['vm.msg.fail.create.vm'] + reason); + kimchi.message.error(reason); });
return false; diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 8467f3f..99cb84a 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -25,8 +25,8 @@ kimchi.initVmButtonsAction = function() { $(this).addClass('loading'); kimchi.startVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.start']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { event.preventDefault(); @@ -40,8 +40,8 @@ kimchi.initVmButtonsAction = function() { $(this).addClass('loading'); kimchi.stopVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.stop']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { event.preventDefault(); @@ -79,14 +79,14 @@ kimchi.initVmButtonsAction = function() { if ('running' === $(this).data('vmstate')) { kimchi.resetVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.reset']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } else { kimchi.startVM($(this).data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.start']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); } }); @@ -94,16 +94,16 @@ kimchi.initVmButtonsAction = function() { $(".vm-delete").on("click", function(event) { var vm = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.vm.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHVM6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { kimchi.deleteVM(vm.data('vm'), function(result) { kimchi.listVmsAuto(); - }, function() { - kimchi.message.error(i18n['msg.fail.delete']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }, function() { }); @@ -214,8 +214,8 @@ kimchi.listVmsAuto = function() { }
kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); - }, function() { - kimchi.message.error(i18n['msg.fail.list.guests']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); kimchi.vmTimeout = window.setTimeout("kimchi.listVmsAuto();", 5000); }); }; diff --git a/ui/js/src/kimchi.host.js b/ui/js/src/kimchi.host.js index e9279fb..a5c341b 100644 --- a/ui/js/src/kimchi.host.js +++ b/ui/js/src/kimchi.host.js @@ -31,10 +31,10 @@ kimchi.host_main = function() { reportGrid = new kimchi.widget.Grid({ container: 'available-reports-grid-container', id: reportGridID, - title: i18n['msg.host.debugreport.title'], + title: i18n['KCHDR6002M'], toolbarButtons: [{ id: reportGridID + '-generate-button', - label: i18n['msg.host.debugreport.generate'], + label: i18n['KCHDR6006M'], onClick: function(event) { kimchi.window.open('report-add.html', { close: function() { @@ -44,13 +44,13 @@ kimchi.host_main = function() { } }, { id: reportGridID + '-rename-button', - label: i18n['msg.host.debugreport.rename'], + label: i18n['KCHDR6008M'], disabled: true, onClick: function(event) { } }, { id: reportGridID + '-remove-button', - label: i18n['msg.host.debugreport.remove'], + label: i18n['KCHDR6009M'], disabled: true, onClick: function(event) { var report = reportGrid.getSelected(); @@ -59,10 +59,10 @@ kimchi.host_main = function() { }
var settings = { - title : i18n['msg.host.debugreport.confirm.title'], - content : i18n['msg.host.debugreport.confirm.content'], - confirm : i18n['msg.confirm'], - cancel : i18n['msg.cancel'] + title : i18n['KCHAPI6004M'], + content : i18n['KCHDR6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] };
kimchi.confirm(settings, function() { @@ -76,7 +76,7 @@ kimchi.host_main = function() { } }, { id: reportGridID + '-download-button', - label: i18n['msg.host.debugreport.download'], + label: i18n['KCHDR6010M'], disabled: true, onClick: function(event) { var report = reportGrid.getSelected(); @@ -102,15 +102,15 @@ kimchi.host_main = function() { }], fields: [{ name: 'name', - label: i18n['msg.host.debugreport.name'], + label: i18n['KCHDR6003M'], 'class': 'debug-report-name' }, { name: 'file', - label: i18n['msg.host.debugreport.file'], + label: i18n['KCHDR6004M'], 'class': 'debug-report-file' }, { name: 'time', - label: i18n['msg.host.debugreport.time'], + label: i18n['KCHDR6005M'], 'class': 'debug-report-time' }], data: reports @@ -135,10 +135,10 @@ kimchi.host_main = function() { var restartButtonID = '#host-button-restart'; var shutdownHost = function(params) { var settings = { - title : i18n['msg.host.shutdown.confirm.title'], - content : i18n['msg.host.shutdown.confirm.content'], - confirm : i18n['msg.confirm'], - cancel : i18n['msg.cancel'] + title : i18n['KCHAPI6004M'], + content : i18n['KCHHOST6008M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] };
kimchi.confirm(settings, function() { @@ -149,7 +149,7 @@ kimchi.host_main = function() { kimchi.listVMs(function(vms) { for(var i = 0; i < vms.length; i++) { if(vms[i]['state'] === 'running') { - kimchi.message.warn(i18n['msg.host.shutdown.vmrunning']); + kimchi.message.error.code('KCHHOST6001E'); $(shutdownButtonID).prop('disabled', false); $(restartButtonID).prop('disabled', false); return; @@ -220,7 +220,7 @@ kimchi.host_main = function() { cpu: { u: { type: 'percent', - legend: i18n['msg.host.chartlegend.cpu'], + legend: i18n['KCHHOST6002M'], points: [] } }, @@ -229,7 +229,7 @@ kimchi.host_main = function() { type: 'value', base: 2, fixed: 2, - legend: i18n['msg.host.chartlegend.memory.available'], + legend: i18n['KCHHOST6003M'], points: [] } }, @@ -239,7 +239,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.disk.read'], + legend: i18n['KCHHOST6004M'], points: [] }, w: { @@ -247,7 +247,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.disk.write'], + legend: i18n['KCHHOST6005M'], 'class': 'disk-write', points: [] } @@ -258,7 +258,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.network.received'], + legend: i18n['KCHHOST6006M'], points: [] }, s: { @@ -266,7 +266,7 @@ kimchi.host_main = function() { base: 2, fixed: 2, unit: 'B/s', - legend: i18n['msg.host.chartlegend.network.sent'], + legend: i18n['KCHHOST6007M'], 'class': 'network-sent', points: [] } diff --git a/ui/js/src/kimchi.line-chart.js b/ui/js/src/kimchi.line-chart.js index 3685677..4e59cb4 100644 --- a/ui/js/src/kimchi.line-chart.js +++ b/ui/js/src/kimchi.line-chart.js @@ -110,7 +110,7 @@ kimchi.widget.LineChart = function(params) { ); }
- var maxValueLabel = i18n['msg.host.chartaxis.max'] + ' ' + + var maxValueLabel = i18n['KCHHOST6001M'] + ' ' + (type === 'value' ? kimchi.formatMeasurement(maxValue, formatSettings) : '100%'); diff --git a/ui/js/src/kimchi.login_window.js b/ui/js/src/kimchi.login_window.js index 6396a1e..59de389 100644 --- a/ui/js/src/kimchi.login_window.js +++ b/ui/js/src/kimchi.login_window.js @@ -42,7 +42,7 @@ kimchi.login_main = function() { for(var i = 0; i < idsArray.length; i++) { var id = idsArray[i]; if (!$('#' + id).val()) { - $('#' + id + '-msg').text(i18n['msg.login.requiredfield']); + $('#' + id + '-msg').text(i18n['KCHAUTH6002E']); placeCursor(id); return false; } @@ -75,7 +75,7 @@ kimchi.login_main = function() { return false; }
- $('#btn-login').text(i18n['msg.login.loggingin']).prop('disabled', true); + $('#btn-login').text(i18n['KCHAUTH6002M']).prop('disabled', true);
var userID = $('#user-id').val(); userID && kimchi.user.setUserID(userID); @@ -95,8 +95,8 @@ kimchi.login_main = function() { kimchi.user.showUser(true); kimchi.window.close(); }, function() { - $('#message-container').text(i18n['msg.login.failed']); - $('#btn-login').prop('disabled', false).text(i18n['msg.login.login']); + $('#message-container').text(i18n['KCHAUTH6001E']); + $('#btn-login').prop('disabled', false).text(i18n['KCHAUTH6001M']); placeCursor('user-id'); });
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js index cc8afee..5387495 100644 --- a/ui/js/src/kimchi.main.js +++ b/ui/js/src/kimchi.main.js @@ -46,7 +46,7 @@ kimchi.main = function() { */ var tab = $('#nav-menu a[href="' + url + '"]'); if (tab.length === 0) { - kimchi.message.error(i18n['msg.err.uri.invalid']); + kimchi.message.error.code('KCHAPI6001E'); location.hash = ''; return; } @@ -138,8 +138,8 @@ kimchi.main = function() { $('#btn-logout').on('click', function() { kimchi.logout(function() { updatePage(); - }, function() { - kimchi.message.error(i18n['msg.logout.failed']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }); }; diff --git a/ui/js/src/kimchi.message.js b/ui/js/src/kimchi.message.js index 770f999..844febc 100644 --- a/ui/js/src/kimchi.message.js +++ b/ui/js/src/kimchi.message.js @@ -107,6 +107,10 @@ kimchi.message.warn = function(msg) { kimchi.message.error = function(msg) { kimchi.message(msg, 'error'); }; +kimchi.message.error.code = function(code) { + msg = code + ": " + i18n[code] + kimchi.message(msg, 'error'); +}; kimchi.message.success = function(msg) { kimchi.message(msg, 'success'); }; diff --git a/ui/js/src/kimchi.network.js b/ui/js/src/kimchi.network.js index 0a3026f..c1f87ce 100644 --- a/ui/js/src/kimchi.network.js +++ b/ui/js/src/kimchi.network.js @@ -54,10 +54,10 @@ kimchi.addNetworkItem = function(network) {
kimchi.getNetworkItemHtml = function(network) { if(!network.interface) { - network.interface = i18n["value_unavailable"]; + network.interface = i18n["KCHNET6001M"]; } if(!network.addrSpace) { - network.addrSpace = i18n["value_unavailable"]; + network.addrSpace = i18n["KCHNET6001M"]; } if(i18n["network_type_" + network.type]) { network.type = i18n["network_type_" + network.type]; @@ -104,10 +104,10 @@ kimchi.addNetworkActions = function(network) { }); } else if ($(evt.currentTarget).attr("nwAct") === "delete") { kimchi.confirm({ - title : i18n['msg_warning'], - content : i18n['network_action_confirm'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6006M'], + content : i18n['KCHNET6002M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }, function() { kimchi.deleteNetwork(network.name, function() { $(evt.currentTarget).parents(".item").remove(); @@ -143,15 +143,15 @@ kimchi.initNetworkCreation = function() { if ($("#enableVlan").prop("checked")) { data.vlan_id = network.vlan_id; if (!(data.vlan_id >=1 && data.vlan_id <= 4094)) { - kimchi.message.error(i18n['msg.invalid.vlan_id']); + kimchi.message.error.code('KCHNET6001E'); return; } } } kimchi.createNetwork(data, function(result) { network.state = result.state === "active" ? "up" : "down"; - network.interface = result.interface ? result.interface : i18n["value_unavailable"]; - network.addrSpace = result.subnet ? result.subnet : i18n["value_unavailable"]; + network.interface = result.interface ? result.interface : i18n["KCHNET6001M"]; + network.addrSpace = result.subnet ? result.subnet : i18n["KCHNET6001M"]; kimchi.addNetworkItem(network); $("#networkConfig").dialog("close"); }); @@ -176,7 +176,7 @@ kimchi.initNetworkDialog = function() { }, buttons : [ { id : "networkFormOk", - text : i18n.action_create, + text : i18n.KCHAPI6005M, class: "ui-button-primary", disabled: true, click : function() { @@ -196,7 +196,7 @@ kimchi.openNetworkDialog = function(okCallback) { kimchi.setDefaultNetworkType(result.length!==0); }); $("#networkConfig").dialog({ - title : i18n.network_dialog_title_create + title : i18n.KCHNET6003M }); $("#networkFormOk").on("click", function() { okCallback(); diff --git a/ui/js/src/kimchi.report_add_main.js b/ui/js/src/kimchi.report_add_main.js index 9826c38..f893d85 100644 --- a/ui/js/src/kimchi.report_add_main.js +++ b/ui/js/src/kimchi.report_add_main.js @@ -16,7 +16,7 @@ kimchi.report_add_main = function() { var formData = addReportForm.serializeObject(); errorMessage.text(''); submitButton - .text(i18n['msg.host.debugreport.generating']) + .text(i18n['KCHDR6007M']) .prop('disabled', true); nameTextbox.prop('disabled', true); kimchi.createReport(formData, function(result) { @@ -25,10 +25,10 @@ kimchi.report_add_main = function() { result: result }); }, function(result) { - result && result['message'] && - $('#report-error-message').text(result['message']); + result && result['reason'] && + $('#report-error-message').text(result['reason']); submitButton - .text(i18n['msg.host.debugreport.generate']) + .text(i18n['KCHDR6006M']) .prop('disabled', false); nameTextbox.prop('disabled', false).focus(); }); diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js index 5605f4b..d65da0b 100644 --- a/ui/js/src/kimchi.storage_main.js +++ b/ui/js/src/kimchi.storage_main.js @@ -36,8 +36,8 @@ kimchi.doListStoragePools = function() { } else { $('#storagepoolsList').html(''); } - }, function() { - kimchi.message.error(i18n['kimchi.list.storage.fail.msg']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); });
} @@ -79,10 +79,10 @@ kimchi.storageBindClick = function() { $('.pool-delete').on('click', function(event) { var $pool = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.storagepool.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { var poolName = $pool.data('name'); @@ -159,14 +159,14 @@ kimchi.doListVolumes = function(poolObj) { }); volumeDiv.html(listHtml); } else { - volumeDiv.html("<div class='pool-empty'>" + i18n['msg.kimchi.storage.pool.empty'] + "</div>"); + volumeDiv.html("<div class='pool-empty'>" + i18n['KCHPOOL6002M'] + "</div>"); } poolObj.removeClass('in'); kimchi.changeArrow(handleArrow); slide.slideDown('slow'); } - }, function() { - kimchi.message.error(i18n['msg.kimchi.list.volume.fail']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js index e5922b3..ac97e1a 100644 --- a/ui/js/src/kimchi.storagepool_add_main.js +++ b/ui/js/src/kimchi.storagepool_add_main.js @@ -141,11 +141,11 @@ kimchi.validateForm = function() { var name = $('#poolId').val(); var poolType = $("#poolTypeInputId").val(); if ('' === name) { - kimchi.message.error(i18n['msg.pool.edit.name.blank']); + kimchi.message.error.code('KCHPOOL6001E'); return false; } if (!/^[\w-]+$/.test(name)) { - kimchi.message.error(i18n['msg.validate.pool.edit.name']); + kimchi.message.error.code('KCHPOOL6004E'); return false; } if (poolType === "dir") { @@ -164,11 +164,11 @@ kimchi.validateForm = function() { kimchi.validateDirForm = function () { var path = $('#pathId').val(); if ('' === path) { - kimchi.message.error(i18n['msg.pool.edit.path.blank']); + kimchi.message.error.code('KCHPOOL6002E'); return false; } if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(path)) { - kimchi.message.error(i18n['msg.validate.pool.edit.path']); + kimchi.message.error.code('KCHAPI6003E'); return false; } return true; @@ -181,11 +181,11 @@ kimchi.validateNfsForm = function () { return false; } if ('' === nfspath) { - kimchi.message.error(i18n['msg.pool.edit.nfspath.blank']); + kimchi.message.error.code('KCHPOOL6003E'); return false; } if (!/((\/([0-9a-zA-Z-_\.]+)))$/.test(nfspath)) { - kimchi.message.error(i18n['msg.validate.pool.edit.nfspath']); + kimchi.message.error.code('KCHPOOL6005E'); return false; } return true; @@ -198,7 +198,7 @@ kimchi.validateIscsiForm = function() { return false; } if ('' === iscsiTarget) { - kimchi.message.error(i18n['msg.pool.edit.iscsitarget.blank']); + kimchi.message.error.code('KCHPOOL6007E'); return false; } return true; @@ -206,11 +206,11 @@ kimchi.validateIscsiForm = function() {
kimchi.validateServer = function(serverField) { if ('' === serverField) { - kimchi.message.error(i18n['msg.pool.edit.server.blank']); + kimchi.message.error.code('KCHPOOL6008E'); return false; } if(!kimchi.isServer(serverField)) { - kimchi.message.error(i18n['msg.validate.pool.edit.server']); + kimchi.message.error.code('KCHPOOL6009E'); return false; } return true; @@ -218,7 +218,7 @@ kimchi.validateServer = function(serverField) {
kimchi.validateLogicalForm = function () { if ($("input[name=devices]:checked").length === 0) { - kimchi.message.error(i18n['msg.validate.pool.edit.logical.device']); + kimchi.message.error.code('KCHPOOL6006E'); return false; } else { return true; @@ -263,10 +263,10 @@ kimchi.addPool = function(event) { } if (poolType === 'logical') { var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.logicalpool.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHPOOL6003M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { kimchi.createStoragePool(formData, function() { diff --git a/ui/js/src/kimchi.template_add_main.js b/ui/js/src/kimchi.template_add_main.js index 85e73a2..1b1f413 100644 --- a/ui/js/src/kimchi.template_add_main.js +++ b/ui/js/src/kimchi.template_add_main.js @@ -72,7 +72,7 @@ kimchi.template_add_main = function() {
$('#iso-search').click(function() { var settings = { - content : i18n['msg.template.iso.search.confirm'] + content : i18n['KCHTMPL6002M'] }; kimchi.confirm(settings, function() { $('#iso-search').hide(); @@ -83,7 +83,7 @@ kimchi.template_add_main = function() {
$('#iso-more').click(function() { var settings = { - content : i18n['msg.template.iso.search.confirm'] + content : i18n['KCHTMPL6002M'] }; kimchi.confirm(settings, function() { $('#iso-more').hide(); @@ -119,7 +119,7 @@ kimchi.template_add_main = function() { showLocalIsoField(isos); } else { if (isFinished) { - kimchi.message.warn(i18n['msg.fail.template.no.iso']); + kimchi.message.warn(i18n['KCHTMPL6001W']); } } if (isFinished) { @@ -214,11 +214,11 @@ kimchi.template_add_main = function() { $('#btn-template-file-create').click(function() { var isoFile = $('#iso-file').val(); if (!kimchi.is_iso_file(isoFile)) { - kimchi.message.error(i18n['msg.invalid.iso']); + kimchi.message.error.code('KCHTMPL6002E'); return; } if (!kimchi.template_check_path(isoFile)) { - kimchi.message.error(i18n['msg.invalid.path']); + kimchi.message.error.code('KCHAPI6003E'); return; } var data = { @@ -274,7 +274,7 @@ kimchi.template_add_main = function() { $('#list-remote-iso').html(html); $('#remote-iso-field').show(); } else { - kimchi.message.warn(i18n['msg.fail.template.no.iso']); + kimchi.message.warn(i18n['KCHTMPL6001W']); } };
@@ -330,7 +330,7 @@ kimchi.template_add_main = function() { $('#btn-template-url-create').click(function() { var isoUrl = $('#iso-url').val(); if (!kimchi.template_check_url(isoUrl)) { - kimchi.message.error(i18n['msg.invalid.url']); + kimchi.message.error.code('KCHAPI6004E'); return; } var data = { @@ -365,7 +365,7 @@ kimchi.template_add_main = function() { }; kimchi.createTemplate(data, function() { successNum++; - kimchi.message.success(i18n['msg.success.create.template'] + ': ' + isoInfo.name); + kimchi.message.success(i18n['KCHTMPL6001M'] + ': ' + isoInfo.name); $('input[value="' + isoInfo.isoId + '"]').prop('checked', false); $('.check-all>input').prop('checked', false); kimchi.doListTemplates(); @@ -374,7 +374,7 @@ kimchi.template_add_main = function() { kimchi.window.close(); } }, function(err) { - kimchi.message.error(i18n['msg.fail.create.template'] + ': ' + isoInfo.name + '<br>' + err.responseJSON.reason); + kimchi.message.error(err.responseJSON.reason); }); }; if (formData.iso instanceof Array) { diff --git a/ui/js/src/kimchi.template_main.js b/ui/js/src/kimchi.template_main.js index ffc7306..0904e71 100644 --- a/ui/js/src/kimchi.template_main.js +++ b/ui/js/src/kimchi.template_main.js @@ -33,8 +33,8 @@ kimchi.doListTemplates = function() { $('#templateList').html(''); $('#noTemplates').show(); } - }, function() { - kimchi.message.error(i18n['kimchi.list.template.fail.msg']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); };
@@ -47,17 +47,17 @@ kimchi.bindClick = function() { $('.template-delete').on('click', function(event) { var $template = $(this); var settings = { - title : i18n['msg.confirm.delete.title'], - content : i18n['msg.template.confirm.delete'], - confirm : i18n['msg.confirm.delete.confirm'], - cancel : i18n['msg.confirm.delete.cancel'] + title : i18n['KCHAPI6001M'], + content : i18n['KCHTMPL6001M'], + confirm : i18n['KCHAPI6002M'], + cancel : i18n['KCHAPI6003M'] }; kimchi.confirm(settings, function() { var templateName = $template.data('template'); kimchi.deleteTemplate(templateName, function() { kimchi.doListTemplates(); - }, function() { - kimchi.message.error(i18n['fail.delete.template']); + }, function(err) { + kimchi.message.error(err.responseJSON.reason); }); }, function() { }); diff --git a/ui/js/widgets/filter-select.js b/ui/js/widgets/filter-select.js index 44030a1..9e024cf 100644 --- a/ui/js/widgets/filter-select.js +++ b/ui/js/widgets/filter-select.js @@ -55,7 +55,7 @@ that.listControl.html(''); var items = that._dataList(options); if (items.length === 0) { - that.listControl.html(i18n['msg.no.mapping.result']); + that.listControl.html(i18n['KCHAPI6005E']); } else { $.each(items, function(index, item) { that.listControl.append(item); @@ -75,7 +75,7 @@ }); if (that.listControl.html() === '') { that.target.addClass("invalid-field"); - that.listControl.html(i18n['msg.no.mapping.result']); + that.listControl.html(i18n['KCHAPI6005E']); } else { that.target.removeClass("invalid-field"); } diff --git a/ui/js/widgets/select-menu.js b/ui/js/widgets/select-menu.js index c9a1b87..c213f3c 100644 --- a/ui/js/widgets/select-menu.js +++ b/ui/js/widgets/select-menu.js @@ -62,7 +62,7 @@ } }); } else { - kimchi.message.error(i18n['selectmenu.data.error']); + kimchi.message.code.error('KCHAPI6006E'); } },
@@ -83,4 +83,4 @@ $.Widget.prototype.destroy.call(this); } }); -}(jQuery)); \ No newline at end of file +}(jQuery)); diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl index d63d4e9..540c07c 100644 --- a/ui/pages/i18n.html.tmpl +++ b/ui/pages/i18n.html.tmpl @@ -36,99 +36,85 @@ <body> <script> var i18n = { - 'temp.msg.fail.list': "$_("Failed to list the template")", - 'temp.msg.choose.temp': "$_("Please choose a template")", - 'vm.msg.fail.create.vm': "$_("Failed to create vm")", - 'msg.login.failed': "$_("The username or password you entered is incorrect. Please try again.")", - 'msg.login.requiredfield': "$_("This field is required.")", - 'msg.login.login': "$_("Log in")", - 'msg.login.loggingin': "$_("Logging in...")", - 'msg.err.uri.invalid': "$_("Invalid URL. Redireced to home page.")", - 'msg.404.gotohomepage': "$_("Go to Homepage")", - 'msg.fail.start': "$_("Failed to start")", - 'msg.fail.stop': "$_("Failed to stop")", - 'msg.fail.reset': "$_("Failed to reset")", - 'msg.fail.delete': "$_("Failed to delete")", - 'msg.fail.list.guests': "$_("Failed to list guests")", - 'msg.fail.create.template': "$_("Failed to create template")", - 'msg.success.create.template': "$_("Create template successfully")", - 'msg.fail.template.no.iso': "$_("No iso found")", - 'msg.fail.template.scan': "$_("Failed to scan")", - 'msg.fail.template.distr': "$_("Failed to list iso distributions")", - 'msg.confirm.delete.title': "$_("Delete Confirmation")", - 'msg.confirm': "$_("OK")", - 'msg.cancel': "$_("Cancel")", - 'msg.confirm.delete.confirm': "$_("OK")", - 'msg.confirm.delete.cancel': "$_("Cancel")", - 'msg.host.chartaxis.max': "$_("Max:")", - 'msg.host.chartlegend.cpu': "$_("Utilization")", - 'msg.host.chartlegend.memory.available': "$_("Available")", - 'msg.host.chartlegend.disk.read': "$_("Read Rate")", - 'msg.host.chartlegend.disk.write': "$_("Write Rate")", - 'msg.host.chartlegend.network.received': "$_("Received")", - 'msg.host.chartlegend.network.sent': "$_("Sent")", - 'msg.host.debugreport.confirm.title': "$_("Confirm")", - 'msg.host.debugreport.confirm.content': "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")", - 'msg.host.debugreport.title': "$_("Debug Reports")", - 'msg.host.debugreport.name': "$_("Name")", - 'msg.host.debugreport.file': "$_("File Path")", - 'msg.host.debugreport.time': "$_("Generated Time")", - 'msg.host.debugreport.generate': "$_("Generate")", - 'msg.host.debugreport.generating': "$_("Generating...")", - 'msg.host.debugreport.rename': "$_("Rename")", - 'msg.host.debugreport.remove': "$_("Remove")", - 'msg.host.debugreport.download': "$_("Download")", - 'msg.host.shutdown.vmrunning': "$_("Some VM(s) are running!")", - 'msg.host.shutdown.confirm.title': "$_("Confirm")", - 'msg.host.shutdown.confirm.content': "$_("Shutting down or restarting host will cause unsaved work lost. Continue to shut down/restarting?")", - 'msg.vm.confirm.delete': "$_("This will delete the VM and its virtual disks. " - "This operation cannot be undone. " - "Would you like to continue?")", - 'msg.template.confirm.delete': "$_("This will permanently delete the Template. " - "Would you like to continue?")", - 'msg.template.iso.search.confirm': "It will take long time. Do you want to continue?", - 'msg.fail.get.config': "$_("Failed to get application configuration")", - 'msg.invalid.path': "$_("This is not a valid linux path")", - 'msg.invalid.url': "$_("This is not a valid url.")", - 'msg.invalid.vlan_id': "$_("The VLAN id must be between 1 and 4094.")", - 'msg.invalid.iso': "$_("This is not a valid ISO file.")", - 'msg.storagepool.confirm.delete':"$_("This will permanently delete the Storage Pool. Would you like to continue?")", - 'msg.pool.edit.name.blank':"$_("The storage pool name can not be blank.")", - 'msg.pool.edit.path.blank':"$_("The storage pool path can not be blank.")", - 'msg.pool.edit.nfspath.blank':"$_("NFS server mount path can not be blank.")", - 'msg.validate.pool.edit.name':"$_("Invalid Storage Pool name. It may only contain letters, numbers, underscores, and hyphens.")", - 'msg.validate.pool.edit.path':"$_("This is not a real linux path.")", - 'msg.validate.pool.edit.nfspath':"$_("Invalid nfs mount path.")", - 'msg.validate.pool.edit.logical.device':"$_("No logical device selected.")", - 'msg.kimchi.storage.pool.empty':"$_("This storage pool is empty.")", - 'msg.kimchi.list.volume.fail':"$_("Failed to list the storage pool.")", - 'msg.kimchi.storage.pool.not.active':"$_("The storage pool is not active now.")", - 'fail.delete.template': "$_("Failed to delete template.")", - 'Guests':"$_("Guests")", - 'Host':"$_("Host")", - 'Templates':"$_("Templates")", - 'Storage':"$_("Storage")", - 'value_unavailable': "$_("unavailable")", - 'Network':"$_("Network")", - 'network_type_isolated': "$_("isolated")", - 'network_type_nat': "$_("NAT")", - 'network_type_bridged': "$_("bridged")", - 'network_bridged_space': "$_("connected to")", - 'network_action_confirm': "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", - 'network_dialog_title_create': "$_("Create a network")", - 'network_dialog_ok': "$_("OK")", - 'network_dialog_cancel': "$_("Cancel")", - 'action_create': "$_("Create")", - 'msg_warning': "$_("Warning")", - 'msg.logicalpool.confirm.delete': "$_("It will format your disk and you will loose any data in" - " there, are you sure to continue? ")", - 'msg.pool.edit.iscsitarget.blank': "$_("The iSCSI target can not be blank.")", - 'msg.pool.edit.server.blank':"$_("Server name can not be blank.")", - 'msg.validate.pool.edit.server':"$_("This is not a valid Server Name or IP. please, modify it.")", - 'select_default': "$_("Please choose")", - 'msg.no.mapping.result': "$_("No such data exsit.")", - 'msg.no.result' : "$_("No valid result")", - 'selectmenu.data.error' : "$_("options needed.")" + 'KCHAUTH6001E': "$_("The username or password you entered is incorrect. Please try again.")", + 'KCHAUTH6002E': "$_("This field is required.")", + + 'KCHAUTH6001M': "$_("Log in")", + 'KCHAUTH6002M': "$_("Logging in...")", + + 'Host': "$_("Host")", + 'Guests': "$_("Guests")", + 'Templates': "$_("Templates")", + 'Storage': "$_("Storage")", + 'Network': "$_("Network")", + + 'KCHAPI6001E': "$_("Invalid URL. Redireced to home page.")", + 'KCHAPI6002E': "$_("Failed to get application configuration")", + 'KCHAPI6003E': "$_("This is not a valid linux path")", + 'KCHAPI6004E': "$_("This is not a valid url.")", + 'KCHAPI6005E': "$_("No such data exsit.")", + 'KCHAPI6006E': "$_("options needed.")", + + 'KCHAPI6001M': "$_("Delete Confirmation")", + 'KCHAPI6002M': "$_("OK")", + 'KCHAPI6003M': "$_("Cancel")", + 'KCHAPI6004M': "$_("Confirm")", + 'KCHAPI6005M': "$_("Create")", + 'KCHAPI6006M': "$_("Warning")", + + 'KCHTMPL6001M': "$_("Create template successfully")", + + 'KCHTMPL6001W': "$_("No iso found")", + + 'KCHTMPL6002E': "$_("This is not a valid ISO file.")", + + 'KCHTMPL6001M': "$_("This will permanently delete the Template. Would you like to continue?")", At least this code is being used more than once: KCHTMPL6001M.
Ops... I will fix it on V2.
Also, don't we have same messages here and in /src/kimchi/i18n.py? I think we should have only one repository for messages in the code that could be used for both backend and frontend.
The idea is having backend and frontend independents. So we can replace them easily and also package them separated.
+ 'KCHTMPL6002M': "$_("It will take long time. Do you want to continue?")", + + 'KCHHOST6001E': "$_("Unable to shut down system as there are some VM(s) running!")", + + 'KCHHOST6001M': "$_("Max:")", + 'KCHHOST6002M': "$_("Utilization")", + 'KCHHOST6003M': "$_("Available")", + 'KCHHOST6004M': "$_("Read Rate")", + 'KCHHOST6005M': "$_("Write Rate")", + 'KCHHOST6006M': "$_("Received")", + 'KCHHOST6007M': "$_("Sent")", + 'KCHHOST6008M': "$_("Shutting down or restarting host will cause unsaved work lost. Continue to shut down/restarting?")", + + 'KCHDR6001M': "$_("Debug report will be removed permanently and can't be recovered. Do you want to continue?")", + 'KCHDR6002M': "$_("Debug Reports")", + 'KCHDR6003M': "$_("Name")", + 'KCHDR6004M': "$_("File Path")", + 'KCHDR6005M': "$_("Generated Time")", + 'KCHDR6006M': "$_("Generate")", + 'KCHDR6007M': "$_("Generating...")", + 'KCHDR6008M': "$_("Rename")", + 'KCHDR6009M': "$_("Remove")", + 'KCHDR6010M': "$_("Download")", + + + 'KCHVM6001M': "$_("This will delete the VM and its virtual disks. This operation cannot be undone. Would you like to continue?")", + + 'KCHNET6001E': "$_("The VLAN id must be between 1 and 4094.")", + + 'KCHNET6001M': "$_("unavailable")", + 'KCHNET6002M': "$_("This action will interrupt network connectivity for any virtual machine that depend on this network.")", + 'KCHNET6003M': "$_("Create a network")", + + 'KCHPOOL6001M': "$_("This will permanently delete the Storage Pool. Would you like to continue?")", + 'KCHPOOL6002M': "$_("This storage pool is empty.")", + 'KCHPOOL6003M': "$_("It will format your disk and you will loose any data in there, are you sure to continue? ")", + + 'KCHPOOL6001E': "$_("The Storage Pool name can not be blank.")", + 'KCHPOOL6002E': "$_("The Storage Pool path can not be blank.")", + 'KCHPOOL6003E': "$_("NFS server mount path can not be blank.")", + 'KCHPOOL6004E': "$_("Invalid Storage Pool name. It may only contain letters, numbers, underscores, and hyphens.")", + 'KCHPOOL6005E': "$_("Invalid NFS mount path.")", + 'KCHPOOL6006E': "$_("No logical device selected.")", + 'KCHPOOL6007E': "$_("The iSCSI target can not be blank.")", + 'KCHPOOL6008E': "$_("Server name can not be blank.")", + 'KCHPOOL6009E': "$_("This is not a valid Server Name or IP. please, modify it.")" }; </script> </body> Messages in ui/js/kimchi.min.js have not been adapted to this new reference paradigm.
This file ui/js/kimchi.min.js is a compilation with all .js files used in Kimchi. To update it you need to build (make) then it will be generated again and with this patch set modifications.
Best regards,
Leonardo Garcia

From: Aline Manera <alinefm@br.ibm.com> Update po files to include new messages from i18n.py Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- po/en_US.po | 686 ++++++++++++++++++++++++++++++++++++++++++++++----------- po/kimchi.pot | 624 ++++++++++++++++++++++++++++++++++++++++++--------- po/pt_BR.po | 684 +++++++++++++++++++++++++++++++++++++++++++++----------- po/zh_CN.po | 678 +++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 2174 insertions(+), 498 deletions(-) diff --git a/po/en_US.po b/po/en_US.po index 77e0677..309f315 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-01-20 18:46-0200\n" +"POT-Creation-Date: 2014-02-09 20:37-0200\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -105,15 +105,6 @@ msgstr "Edit" msgid "Delete" msgstr "Delete" -msgid "Failed to list the template" -msgstr "Failed to list the template" - -msgid "Please choose a template" -msgstr "Please choose a template" - -msgid "Failed to create vm" -msgstr "Failed to create vm" - msgid "The username or password you entered is incorrect. Please try again." msgstr "The username or password you entered is incorrect. Please try again." @@ -126,26 +117,50 @@ msgstr "Log in" msgid "Logging in..." msgstr "Logging in..." +msgid "Host" +msgstr "Host" + +msgid "Guests" +msgstr "Guests" + +msgid "Templates" +msgstr "Templates" + +msgid "Storage" +msgstr "Storage" + +msgid "Network" +msgstr "Network" + msgid "Invalid URL. Redireced to home page." msgstr "Invalid URL. Redireced to home page." -msgid "Failed to start" -msgstr "Failed to start" +msgid "Failed to get application configuration" +msgstr "Failed to get application configuration" + +msgid "This is not a valid linux path" +msgstr "This is not a valid linux path." + +msgid "This is not a valid url." +msgstr "This is not a valid url." + +msgid "No such data exsit." +msgstr "" -msgid "Failed to stop" -msgstr "Failed to stop" +msgid "options needed." +msgstr "" -msgid "Failed to reset" -msgstr "Failed to reset" +msgid "Delete Confirmation" +msgstr "Delete Confirmation" -msgid "Failed to delete" -msgstr "Failed to delete" +msgid "OK" +msgstr "OK" -msgid "Failed to list guests" -msgstr "Failed to list guests" +msgid "Confirm" +msgstr "Confirm" -msgid "Failed to create template" -msgstr "Failed to create template" +msgid "Warning" +msgstr "Warning" msgid "Create template successfully" msgstr "Create template successfully" @@ -153,17 +168,17 @@ msgstr "Create template successfully" msgid "No iso found" msgstr "No iso found" -msgid "Failed to scan" -msgstr "Failed to scan" +msgid "This is not a valid ISO file." +msgstr "This is not a valid ISO file." -msgid "Failed to list iso distributions" -msgstr "Failed to list iso distributions" +msgid "This will permanently delete the Template. Would you like to continue?" +msgstr "This will permanently delete the Template. Would you like to continue?" -msgid "Delete Confirmation" -msgstr "Delete Confirmation" +msgid "It will take long time. Do you want to continue?" +msgstr "" -msgid "OK" -msgstr "OK" +msgid "Unable to shut down system as there are some VM(s) running!" +msgstr "" msgid "Max:" msgstr "Max:" @@ -186,8 +201,12 @@ msgstr "Received" msgid "Sent" msgstr "Sent" -msgid "Confirm" -msgstr "Confirm" +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" msgid "" "Debug report will be removed permanently and can't be recovered. Do you want " @@ -220,16 +239,6 @@ msgstr "Remove" msgid "Download" msgstr "Download" -msgid "Some VM(s) are running!" -msgstr "Some VM(s) are running!" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" - msgid "" "This will delete the VM and its virtual disks. This operation cannot be " "undone. Would you like to continue?" @@ -237,96 +246,12 @@ msgstr "" "This will delete the VM and its virtual disks. This operation cannot be " "undone. Would you like to continue?" -msgid "This will permanently delete the Template. Would you like to continue?" -msgstr "This will permanently delete the Template. Would you like to continue?" - -msgid "Failed to get application configuration" -msgstr "Failed to get application configuration" - -msgid "This is not a valid linux path" -msgstr "This is not a valid linux path." - -msgid "This is not a valid url." -msgstr "This is not a valid url." - msgid "The VLAN id must be between 1 and 4094." msgstr "The VLAN id must be between 1 and 4094." -msgid "This is not a valid ISO file." -msgstr "This is not a valid ISO file." - -msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" -msgstr "" -"This will permanently delete the Storage Pool. Would you like to continue?" - -msgid "The storage pool name can not be blank." -msgstr "The storage pool name can not be blank." - -msgid "The storage pool path can not be blank." -msgstr "The storage pool path can not be blank." - -msgid "NFS server mount path can not be blank." -msgstr "NFS server mount path can not be blank." - -msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " -"underscores, and hyphens." -msgstr "" -"Invalid Storage Pool name. It may only contain letters, numbers, " -"underscores, and hyphens." - -msgid "This is not a real linux path." -msgstr "This is not a real linux path." - -msgid "Invalid nfs mount path." -msgstr "Invalid nfs mount path." - -msgid "No logical device selected." -msgstr "No logical device selected." - -msgid "This storage pool is empty." -msgstr "This storage pool is empty." - -msgid "Failed to list the storage pool." -msgstr "Failed to list the storage pool" - -msgid "The storage pool is not active now." -msgstr "The storage pool is not active now." - -msgid "Failed to delete template." -msgstr "Failed to delete template." - -msgid "Guests" -msgstr "Guests" - -msgid "Host" -msgstr "Host" - -msgid "Templates" -msgstr "Templates" - -msgid "Storage" -msgstr "Storage" - msgid "unavailable" msgstr "unavailable" -msgid "Network" -msgstr "Network" - -msgid "isolated" -msgstr "isolated" - -msgid "NAT" -msgstr "NAT" - -msgid "bridged" -msgstr "bridged" - -msgid "connected to" -msgstr "connected to" - msgid "" "This action will interrupt network connectivity for any virtual machine that " "depend on this network." @@ -337,8 +262,13 @@ msgstr "" msgid "Create a network" msgstr "Create a network" -msgid "Warning" -msgstr "Warning" +msgid "" +"This will permanently delete the Storage Pool. Would you like to continue?" +msgstr "" +"This will permanently delete the Storage Pool. Would you like to continue?" + +msgid "This storage pool is empty." +msgstr "This storage pool is empty." msgid "" "It will format your disk and you will loose any data in there, are you sure " @@ -347,6 +277,26 @@ msgstr "" "It will format your disk and you will loose any data in there, are you sure " "to continue? " +msgid "The Storage Pool name can not be blank." +msgstr "" + +msgid "The Storage Pool path can not be blank." +msgstr "" + +msgid "NFS server mount path can not be blank." +msgstr "NFS server mount path can not be blank." + +msgid "" +"Invalid Storage Pool name. It may only contain letters, numbers, " +"underscores, and hyphens." +msgstr "" + +msgid "Invalid NFS mount path." +msgstr "" + +msgid "No logical device selected." +msgstr "No logical device selected." + msgid "The iSCSI target can not be blank." msgstr "The iSCSI target can not be blank." @@ -412,17 +362,17 @@ msgstr "" "Kimchi will try to create the directory when it does not already exist in " "your system." -msgid "NFS server IP" -msgstr "NFS server IP" +msgid "NFS Server IP" +msgstr "" -msgid "NFS server IP or hostname. It should not be empty." -msgstr "NFS server IP or hostname. It should not be empty." +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" msgid "NFS Path" msgstr "NFS Path" -msgid "The nfs exported path on nfs server" -msgstr "The nfs exported path on nfs server" +msgid "The nfs exported path on nfs server." +msgstr "" msgid "Device Path" msgstr "Device Path" @@ -630,3 +580,471 @@ msgstr "CDROM" msgid "Storage Pool" msgstr "Storage Pool" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +msgid "Datastore is not initiated in the model object." +msgstr "" + +#, python-format +msgid "Authentication failed for user '%(userid)s'. [Error code: %(code)s]" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "" + +#, python-format +msgid "Unable to parse distro file: %(filename)s.Make sure, it is a json file." +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "" + +#, python-format +msgid "Unable to find ISO file ISO %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" + +msgid "Virtual machine $(name)s already exists" +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s already " +"exists or it is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" + +msgid "Remote ISO image is not supported by this server." +msgstr "" + +#, python-format +msgid "Screenshot not supported for virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to rename virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)" +msgstr "" + +#, python-format +msgid "Unable to connect to powered off machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string" +msgstr "" + +#, python-format +msgid "Invalid template URI: %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI: %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are spice or vnc" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" + +msgid "Specify a template to create a Virtual Machine from" +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" + +msgid "Do not support guest interface hot plug attachment" +msgstr "" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "" + +#, python-format +msgid "Template %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Storage Pool %(pool)s specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "Storage Pool %(pool)s specified for template %(template)s is not active" +msgstr "" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for cdrom." +msgstr "" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" + +msgid "Template name must be a string" +msgstr "" + +msgid "Template icon must be a path to the image" +msgstr "" + +msgid "Template distribution must be a string" +msgstr "" + +msgid "Template distribution version must be a string" +msgstr "" + +msgid "The number of CPUs must be a integer" +msgstr "" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for Template" +msgstr "" + +msgid "Specify an ISO image as CDROM to create a Template" +msgstr "" + +msgid "All networks for the Template must be specified in a list." +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s does not exist" +msgstr "" + +msgid "Autostart flag must be true or false" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create the Storage Pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active Storage Pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to list Storage Pools. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to create Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to activate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to deactivate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" + +#, python-format +msgid "Unsupported Storage Pool type: %(type)s" +msgstr "" + +#, python-format +msgid "Error while getting xml for Storage Pool %(pool)s" +msgstr "" + +msgid "Storage Pool name must be a string" +msgstr "" + +msgid "Supported Storage Pool types are dir, netfs, logical and kimchi-iso" +msgstr "" + +msgid "Storage Pool path must be a string" +msgstr "" + +msgid "Storage Pool host must be a IP or hostname" +msgstr "" + +msgid "Storage Pool devices must be the full path to the block device" +msgstr "" + +msgid "Storage Pool devices parameter must be a list" +msgstr "" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" + +msgid "Login username of the iSCSI target must be a string" +msgstr "" + +msgid "Login password of the iSCSI target must be a string" +msgstr "" + +msgid "Specify name and type to create a Storage Pool" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s does not exist in Storage Pool %(pool)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create Storage Volume %(volume)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s " +"is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes because Storage Pool %(pool)s is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to wipe Storage Volumes %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to resize Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" + +msgid "Interface should be bare nic, bonding or bridge device." +msgstr "" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "" + +msgid "" +"Unable to create VLAN tagged bridge using interface %(iface)s. Details: " +"%(err)" +msgstr "" + +msgid "Network name must be a string" +msgstr "" + +msgid "Supported network types are isolated, nat and bridge" +msgstr "" + +msgid "Network subnet must be a string with ip address and prefix or netmask" +msgstr "" + +msgid "Network interface must be a string" +msgstr "" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "" + +msgid "Specify name and type to create a Network" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "" + +msgid "Debug report tool not found in system" +msgstr "" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Can not find generated debug report named %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" + +#, python-format +msgid "Unable to find %(item)s in datastore" +msgstr "" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "" + +#, python-format +msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +msgstr "" + +msgid "Unable to choose a virutal machine name" +msgstr "" diff --git a/po/kimchi.pot b/po/kimchi.pot index 836b013..f105d14 100755 --- a/po/kimchi.pot +++ b/po/kimchi.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-01-20 18:46-0200\n" +"POT-Creation-Date: 2014-02-09 20:37-0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -103,46 +103,61 @@ msgstr "" msgid "Delete" msgstr "" -msgid "Failed to list the template" +msgid "The username or password you entered is incorrect. Please try again." msgstr "" -msgid "Please choose a template" +msgid "This field is required." msgstr "" -msgid "Failed to create vm" +msgid "Log in" msgstr "" -msgid "The username or password you entered is incorrect. Please try again." +msgid "Logging in..." msgstr "" -msgid "This field is required." +msgid "Host" msgstr "" -msgid "Log in" +msgid "Guests" msgstr "" -msgid "Logging in..." +msgid "Templates" +msgstr "" + +msgid "Storage" +msgstr "" + +msgid "Network" msgstr "" msgid "Invalid URL. Redireced to home page." msgstr "" -msgid "Failed to start" +msgid "Failed to get application configuration" +msgstr "" + +msgid "This is not a valid linux path" msgstr "" -msgid "Failed to stop" +msgid "This is not a valid url." msgstr "" -msgid "Failed to reset" +msgid "No such data exsit." msgstr "" -msgid "Failed to delete" +msgid "options needed." msgstr "" -msgid "Failed to list guests" +msgid "Delete Confirmation" msgstr "" -msgid "Failed to create template" +msgid "OK" +msgstr "" + +msgid "Confirm" +msgstr "" + +msgid "Warning" msgstr "" msgid "Create template successfully" @@ -151,16 +166,16 @@ msgstr "" msgid "No iso found" msgstr "" -msgid "Failed to scan" +msgid "This is not a valid ISO file." msgstr "" -msgid "Failed to list iso distributions" +msgid "This will permanently delete the Template. Would you like to continue?" msgstr "" -msgid "Delete Confirmation" +msgid "It will take long time. Do you want to continue?" msgstr "" -msgid "OK" +msgid "Unable to shut down system as there are some VM(s) running!" msgstr "" msgid "Max:" @@ -184,7 +199,9 @@ msgstr "" msgid "Sent" msgstr "" -msgid "Confirm" +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" msgstr "" msgid "" @@ -216,120 +233,55 @@ msgstr "" msgid "Download" msgstr "" -msgid "Some VM(s) are running!" -msgstr "" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" - msgid "" "This will delete the VM and its virtual disks. This operation cannot be " "undone. Would you like to continue?" msgstr "" -msgid "This will permanently delete the Template. Would you like to continue?" -msgstr "" - -msgid "Failed to get application configuration" -msgstr "" - -msgid "This is not a valid linux path" -msgstr "" - -msgid "This is not a valid url." -msgstr "" - msgid "The VLAN id must be between 1 and 4094." msgstr "" -msgid "This is not a valid ISO file." +msgid "unavailable" msgstr "" msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "" - -msgid "The storage pool path can not be blank." +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." msgstr "" -msgid "NFS server mount path can not be blank." +msgid "Create a network" msgstr "" msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " -"underscores, and hyphens." -msgstr "" - -msgid "This is not a real linux path." -msgstr "" - -msgid "Invalid nfs mount path." -msgstr "" - -msgid "No logical device selected." +"This will permanently delete the Storage Pool. Would you like to continue?" msgstr "" msgid "This storage pool is empty." msgstr "" -msgid "Failed to list the storage pool." -msgstr "" - -msgid "The storage pool is not active now." -msgstr "" - -msgid "Failed to delete template." -msgstr "" - -msgid "Guests" -msgstr "" - -msgid "Host" -msgstr "" - -msgid "Templates" -msgstr "" - -msgid "Storage" -msgstr "" - -msgid "unavailable" -msgstr "" - -msgid "Network" -msgstr "" - -msgid "isolated" +msgid "" +"It will format your disk and you will loose any data in there, are you sure " +"to continue? " msgstr "" -msgid "NAT" +msgid "The Storage Pool name can not be blank." msgstr "" -msgid "bridged" +msgid "The Storage Pool path can not be blank." msgstr "" -msgid "connected to" +msgid "NFS server mount path can not be blank." msgstr "" msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" - -msgid "Create a network" +"Invalid Storage Pool name. It may only contain letters, numbers, " +"underscores, and hyphens." msgstr "" -msgid "Warning" +msgid "Invalid NFS mount path." msgstr "" -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " +msgid "No logical device selected." msgstr "" msgid "The iSCSI target can not be blank." @@ -390,16 +342,16 @@ msgid "" "your system." msgstr "" -msgid "NFS server IP" +msgid "NFS Server IP" msgstr "" -msgid "NFS server IP or hostname. It should not be empty." +msgid "NFS server IP or hostname. It can be input or chosen from history." msgstr "" msgid "NFS Path" msgstr "" -msgid "The nfs exported path on nfs server" +msgid "The nfs exported path on nfs server." msgstr "" msgid "Device Path" @@ -608,3 +560,471 @@ msgstr "" msgid "Storage Pool" msgstr "" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +msgid "Datastore is not initiated in the model object." +msgstr "" + +#, python-format +msgid "Authentication failed for user '%(userid)s'. [Error code: %(code)s]" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "" + +#, python-format +msgid "Unable to parse distro file: %(filename)s.Make sure, it is a json file." +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "" + +#, python-format +msgid "Unable to find ISO file ISO %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" + +msgid "Virtual machine $(name)s already exists" +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s already " +"exists or it is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" + +msgid "Remote ISO image is not supported by this server." +msgstr "" + +#, python-format +msgid "Screenshot not supported for virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to rename virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)" +msgstr "" + +#, python-format +msgid "Unable to connect to powered off machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string" +msgstr "" + +#, python-format +msgid "Invalid template URI: %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI: %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are spice or vnc" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" + +msgid "Specify a template to create a Virtual Machine from" +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" + +msgid "Do not support guest interface hot plug attachment" +msgstr "" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "" + +#, python-format +msgid "Template %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Storage Pool %(pool)s specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "Storage Pool %(pool)s specified for template %(template)s is not active" +msgstr "" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for cdrom." +msgstr "" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" + +msgid "Template name must be a string" +msgstr "" + +msgid "Template icon must be a path to the image" +msgstr "" + +msgid "Template distribution must be a string" +msgstr "" + +msgid "Template distribution version must be a string" +msgstr "" + +msgid "The number of CPUs must be a integer" +msgstr "" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for Template" +msgstr "" + +msgid "Specify an ISO image as CDROM to create a Template" +msgstr "" + +msgid "All networks for the Template must be specified in a list." +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s does not exist" +msgstr "" + +msgid "Autostart flag must be true or false" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create the Storage Pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active Storage Pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to list Storage Pools. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to create Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to activate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to deactivate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" + +#, python-format +msgid "Unsupported Storage Pool type: %(type)s" +msgstr "" + +#, python-format +msgid "Error while getting xml for Storage Pool %(pool)s" +msgstr "" + +msgid "Storage Pool name must be a string" +msgstr "" + +msgid "Supported Storage Pool types are dir, netfs, logical and kimchi-iso" +msgstr "" + +msgid "Storage Pool path must be a string" +msgstr "" + +msgid "Storage Pool host must be a IP or hostname" +msgstr "" + +msgid "Storage Pool devices must be the full path to the block device" +msgstr "" + +msgid "Storage Pool devices parameter must be a list" +msgstr "" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" + +msgid "Login username of the iSCSI target must be a string" +msgstr "" + +msgid "Login password of the iSCSI target must be a string" +msgstr "" + +msgid "Specify name and type to create a Storage Pool" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s does not exist in Storage Pool %(pool)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create Storage Volume %(volume)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s " +"is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes because Storage Pool %(pool)s is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to wipe Storage Volumes %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to resize Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" + +msgid "Interface should be bare nic, bonding or bridge device." +msgstr "" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "" + +msgid "" +"Unable to create VLAN tagged bridge using interface %(iface)s. Details: " +"%(err)" +msgstr "" + +msgid "Network name must be a string" +msgstr "" + +msgid "Supported network types are isolated, nat and bridge" +msgstr "" + +msgid "Network subnet must be a string with ip address and prefix or netmask" +msgstr "" + +msgid "Network interface must be a string" +msgstr "" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "" + +msgid "Specify name and type to create a Network" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "" + +msgid "Debug report tool not found in system" +msgstr "" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Can not find generated debug report named %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" + +#, python-format +msgid "Unable to find %(item)s in datastore" +msgstr "" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "" + +#, python-format +msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +msgstr "" + +msgid "Unable to choose a virutal machine name" +msgstr "" diff --git a/po/pt_BR.po b/po/pt_BR.po index 724e339..d68a80e 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-01-20 18:46-0200\n" +"POT-Creation-Date: 2014-02-09 20:37-0200\n" "PO-Revision-Date: 2013-06-27 10:48+0000\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: Aline Manera <alinefm@br.ibm.com>\n" @@ -121,15 +121,6 @@ msgstr "Editar" msgid "Delete" msgstr "Remover" -msgid "Failed to list the template" -msgstr "Erro ao listar os modelos" - -msgid "Please choose a template" -msgstr "Por favor, escolha um modelo" - -msgid "Failed to create vm" -msgstr "Erro ao criar a máquina virtual" - msgid "The username or password you entered is incorrect. Please try again." msgstr "" "O usuário ou senha que você entrou está incorreto. Por favor, tente " @@ -144,26 +135,50 @@ msgstr "Entrar" msgid "Logging in..." msgstr "Entrando" +msgid "Host" +msgstr "Hospedeiro" + +msgid "Guests" +msgstr "Máquinas Virtuais" + +msgid "Templates" +msgstr "Modelos" + +msgid "Storage" +msgstr "Storage" + +msgid "Network" +msgstr "Redes" + msgid "Invalid URL. Redireced to home page." msgstr "URL inválida. Redirecionado para a Página Inicial." -msgid "Failed to start" -msgstr "Erro ao iniciar" +msgid "Failed to get application configuration" +msgstr "Erro ao carregar as configurações da aplicação" + +msgid "This is not a valid linux path" +msgstr "Esse não é um caminho válido no linux" + +msgid "This is not a valid url." +msgstr "Esse não é uma URL válida." + +msgid "No such data exsit." +msgstr "" -msgid "Failed to stop" -msgstr "Erro ao parar" +msgid "options needed." +msgstr "" -msgid "Failed to reset" -msgstr "Erro ao reiniciar" +msgid "Delete Confirmation" +msgstr "Confirmação de remoção" -msgid "Failed to delete" -msgstr "Erro ao remover" +msgid "OK" +msgstr "OK" -msgid "Failed to list guests" -msgstr "Erro ao listar as máquinas virtuais" +msgid "Confirm" +msgstr "Confirmar" -msgid "Failed to create template" -msgstr "Erro ao criar modelo" +msgid "Warning" +msgstr "Aviso" msgid "Create template successfully" msgstr "Modelo criado com sucesso" @@ -171,17 +186,17 @@ msgstr "Modelo criado com sucesso" msgid "No iso found" msgstr "Nenhuma ISO encontrada" -msgid "Failed to scan" -msgstr "Erro ao escanear" +msgid "This is not a valid ISO file." +msgstr "Esse não é um arquivo ISO válido." -msgid "Failed to list iso distributions" -msgstr "Erro ao listar distribuições ISO" +msgid "This will permanently delete the Template. Would you like to continue?" +msgstr "Isso removerá o Modelo permanentemente. Gostaria de continuar?" -msgid "Delete Confirmation" -msgstr "Confirmação de remoção" +msgid "It will take long time. Do you want to continue?" +msgstr "" -msgid "OK" -msgstr "OK" +msgid "Unable to shut down system as there are some VM(s) running!" +msgstr "" msgid "Max:" msgstr "Máximo:" @@ -204,8 +219,12 @@ msgstr "Recebido" msgid "Sent" msgstr "Enviado" -msgid "Confirm" -msgstr "Confirmar" +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"Desligando ou reiniciando do hospedeiro causará na perda de trabalhos não " +"salvos. Continuar o processo de desligar/reiniciar?" msgid "" "Debug report will be removed permanently and can't be recovered. Do you want " @@ -238,16 +257,6 @@ msgstr "Remover" msgid "Download" msgstr "Baixar" -msgid "Some VM(s) are running!" -msgstr "Alguma(s) máquina(s) virtual(is) está(ão) rodando!" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"Desligando ou reiniciando do hospedeiro causará na perda de trabalhos não " -"salvos. Continuar o processo de desligar/reiniciar?" - msgid "" "This will delete the VM and its virtual disks. This operation cannot be " "undone. Would you like to continue?" @@ -255,95 +264,12 @@ msgstr "" "Isso removerá a máquina virtual e seus discos virtuais. A operação não pode " "ser desfeita. Gostaria de continuar?" -msgid "This will permanently delete the Template. Would you like to continue?" -msgstr "Isso removerá o Modelo permanentemente. Gostaria de continuar?" - -msgid "Failed to get application configuration" -msgstr "Erro ao carregar as configurações da aplicação" - -msgid "This is not a valid linux path" -msgstr "Esse não é um caminho válido no linux" - -msgid "This is not a valid url." -msgstr "Esse não é uma URL válida." - msgid "The VLAN id must be between 1 and 4094." msgstr "VLAN id deve ser um número entre 1 e 4094." -msgid "This is not a valid ISO file." -msgstr "Esse não é um arquivo ISO válido." - -msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" -msgstr "Isso removerá permanentemente o Storage Pool. Gostaria de continuar?" - -msgid "The storage pool name can not be blank." -msgstr "O nome do storage pool não pode ser em branco." - -msgid "The storage pool path can not be blank." -msgstr "O caminho do storage pool não pde ser em branco." - -msgid "NFS server mount path can not be blank." -msgstr "Caminho de montagem do servidor de NFS não pode ficar em branco." - -msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " -"underscores, and hyphens." -msgstr "" -"Nome do Storage Pool inválido. Só pode conter letras, números, underscores, " -"e hífens." - -msgid "This is not a real linux path." -msgstr "Esse não é um caminho real no linux." - -msgid "Invalid nfs mount path." -msgstr "Caminho de montagem NFS inválido." - -msgid "No logical device selected." -msgstr "Nenhum dispositivo lógico selecionado." - -msgid "This storage pool is empty." -msgstr "Esse storage pool está vazio." - -msgid "Failed to list the storage pool." -msgstr "Erro ao listar o storage pool." - -msgid "The storage pool is not active now." -msgstr "O storage pool não está ativo agora." - -msgid "Failed to delete template." -msgstr "Erro ao remover modelo." - -msgid "Guests" -msgstr "Máquinas Virtuais" - -msgid "Host" -msgstr "Hospedeiro" - -msgid "Templates" -msgstr "Modelos" - -msgid "Storage" -msgstr "Storage" - msgid "unavailable" msgstr "indisponível" -msgid "Network" -msgstr "Redes" - -msgid "isolated" -msgstr "isolado" - -msgid "NAT" -msgstr "NAT" - -msgid "bridged" -msgstr "bridged" - -msgid "connected to" -msgstr "conectado a" - msgid "" "This action will interrupt network connectivity for any virtual machine that " "depend on this network." @@ -354,8 +280,12 @@ msgstr "" msgid "Create a network" msgstr "Criar uma rede" -msgid "Warning" -msgstr "Aviso" +msgid "" +"This will permanently delete the Storage Pool. Would you like to continue?" +msgstr "Isso removerá permanentemente o Storage Pool. Gostaria de continuar?" + +msgid "This storage pool is empty." +msgstr "Esse storage pool está vazio." msgid "" "It will format your disk and you will loose any data in there, are you sure " @@ -364,6 +294,26 @@ msgstr "" "Isso formatará seu disco e você perderá toda informação, você tem certeza " "que quer continuar?" +msgid "The Storage Pool name can not be blank." +msgstr "" + +msgid "The Storage Pool path can not be blank." +msgstr "" + +msgid "NFS server mount path can not be blank." +msgstr "Caminho de montagem do servidor de NFS não pode ficar em branco." + +msgid "" +"Invalid Storage Pool name. It may only contain letters, numbers, " +"underscores, and hyphens." +msgstr "" + +msgid "Invalid NFS mount path." +msgstr "" + +msgid "No logical device selected." +msgstr "Nenhum dispositivo lógico selecionado." + msgid "The iSCSI target can not be blank." msgstr "" @@ -426,17 +376,17 @@ msgid "" "your system." msgstr "" -msgid "NFS server IP" -msgstr "Endereço IP do servidor NFS" +msgid "NFS Server IP" +msgstr "" -msgid "NFS server IP or hostname. It should not be empty." -msgstr "Endereço IP ou nome do servidor NFS. Não deve ser vazio. " +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" msgid "NFS Path" msgstr "Caminho do NFS" -msgid "The nfs exported path on nfs server" -msgstr "O caminho exportado no servidor NFS" +msgid "The nfs exported path on nfs server." +msgstr "" msgid "Device Path" msgstr "Caminho do dispositivo" @@ -644,3 +594,471 @@ msgstr "CD-ROM" msgid "Storage Pool" msgstr "Nome do Storage Pool" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +msgid "Datastore is not initiated in the model object." +msgstr "" + +#, python-format +msgid "Authentication failed for user '%(userid)s'. [Error code: %(code)s]" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "" + +#, python-format +msgid "Unable to parse distro file: %(filename)s.Make sure, it is a json file." +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "" + +#, python-format +msgid "Unable to find ISO file ISO %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" + +msgid "Virtual machine $(name)s already exists" +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s already " +"exists or it is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" + +msgid "Remote ISO image is not supported by this server." +msgstr "" + +#, python-format +msgid "Screenshot not supported for virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to rename virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)" +msgstr "" + +#, python-format +msgid "Unable to connect to powered off machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string" +msgstr "" + +#, python-format +msgid "Invalid template URI: %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI: %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are spice or vnc" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" + +msgid "Specify a template to create a Virtual Machine from" +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" + +msgid "Do not support guest interface hot plug attachment" +msgstr "" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "" + +#, python-format +msgid "Template %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Storage Pool %(pool)s specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "Storage Pool %(pool)s specified for template %(template)s is not active" +msgstr "" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for cdrom." +msgstr "" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" + +msgid "Template name must be a string" +msgstr "" + +msgid "Template icon must be a path to the image" +msgstr "" + +msgid "Template distribution must be a string" +msgstr "" + +msgid "Template distribution version must be a string" +msgstr "" + +msgid "The number of CPUs must be a integer" +msgstr "" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for Template" +msgstr "" + +msgid "Specify an ISO image as CDROM to create a Template" +msgstr "" + +msgid "All networks for the Template must be specified in a list." +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s does not exist" +msgstr "" + +msgid "Autostart flag must be true or false" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create the Storage Pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active Storage Pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to list Storage Pools. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to create Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to activate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to deactivate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" + +#, python-format +msgid "Unsupported Storage Pool type: %(type)s" +msgstr "" + +#, python-format +msgid "Error while getting xml for Storage Pool %(pool)s" +msgstr "" + +msgid "Storage Pool name must be a string" +msgstr "" + +msgid "Supported Storage Pool types are dir, netfs, logical and kimchi-iso" +msgstr "" + +msgid "Storage Pool path must be a string" +msgstr "" + +msgid "Storage Pool host must be a IP or hostname" +msgstr "" + +msgid "Storage Pool devices must be the full path to the block device" +msgstr "" + +msgid "Storage Pool devices parameter must be a list" +msgstr "" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" + +msgid "Login username of the iSCSI target must be a string" +msgstr "" + +msgid "Login password of the iSCSI target must be a string" +msgstr "" + +msgid "Specify name and type to create a Storage Pool" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s does not exist in Storage Pool %(pool)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create Storage Volume %(volume)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s " +"is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes because Storage Pool %(pool)s is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to wipe Storage Volumes %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to resize Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" + +msgid "Interface should be bare nic, bonding or bridge device." +msgstr "" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "" + +msgid "" +"Unable to create VLAN tagged bridge using interface %(iface)s. Details: " +"%(err)" +msgstr "" + +msgid "Network name must be a string" +msgstr "" + +msgid "Supported network types are isolated, nat and bridge" +msgstr "" + +msgid "Network subnet must be a string with ip address and prefix or netmask" +msgstr "" + +msgid "Network interface must be a string" +msgstr "" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "" + +msgid "Specify name and type to create a Network" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "" + +msgid "Debug report tool not found in system" +msgstr "" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Can not find generated debug report named %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" + +#, python-format +msgid "Unable to find %(item)s in datastore" +msgstr "" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "" + +#, python-format +msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +msgstr "" + +msgid "Unable to choose a virutal machine name" +msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index 34f7aca..4fbb64e 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-01-20 18:46-0200\n" +"POT-Creation-Date: 2014-02-09 20:37-0200\n" "PO-Revision-Date: 2013-06-27 10:48+0000\n" "Last-Translator: ShaoHe Feng <shaohef@linux.vnet.ibm.com>\n" "Language-Team: ShaoHe Feng <shaohef@linux.vnet.ibm.com>\n" @@ -119,15 +119,6 @@ msgstr "编辑" msgid "Delete" msgstr "删除" -msgid "Failed to list the template" -msgstr "展示模板列表失败" - -msgid "Please choose a template" -msgstr "请选择模板" - -msgid "Failed to create vm" -msgstr "虚拟机创建失败" - msgid "The username or password you entered is incorrect. Please try again." msgstr "用户名或密码错误,请重新输入。" @@ -140,26 +131,50 @@ msgstr "登录" msgid "Logging in..." msgstr "登录中..." +msgid "Host" +msgstr "主机" + +msgid "Guests" +msgstr "客户机" + +msgid "Templates" +msgstr "模板" + +msgid "Storage" +msgstr "存储" + +msgid "Network" +msgstr "网络" + msgid "Invalid URL. Redireced to home page." msgstr "无效的URL,已重定向到首页" -msgid "Failed to start" -msgstr "启动失败" +msgid "Failed to get application configuration" +msgstr "获取应用配置失败" -msgid "Failed to stop" -msgstr "停止失败" +msgid "This is not a valid linux path" +msgstr "这不是一个有效的LINUX路径" -msgid "Failed to reset" -msgstr "重启失败" +msgid "This is not a valid url." +msgstr "这不是一个有效的URL" -msgid "Failed to delete" -msgstr "删除失败" +msgid "No such data exsit." +msgstr "" -msgid "Failed to list guests" -msgstr "客户机列表加载失败" +msgid "options needed." +msgstr "" -msgid "Failed to create template" -msgstr "模板创建失败" +msgid "Delete Confirmation" +msgstr "删除确认" + +msgid "OK" +msgstr "确定" + +msgid "Confirm" +msgstr "确认" + +msgid "Warning" +msgstr "警告" msgid "Create template successfully" msgstr "创建模板成功" @@ -167,17 +182,17 @@ msgstr "创建模板成功" msgid "No iso found" msgstr "没有发现ISO文件" -msgid "Failed to scan" -msgstr "扫描失败" +msgid "This is not a valid ISO file." +msgstr "这不是一个有效的ISO文件" -msgid "Failed to list iso distributions" -msgstr "加载ISO列表失败" +msgid "This will permanently delete the Template. Would you like to continue?" +msgstr "本操作将会永久删除模板,是否继续?" -msgid "Delete Confirmation" -msgstr "删除确认" +msgid "It will take long time. Do you want to continue?" +msgstr "" -msgid "OK" -msgstr "确定" +msgid "Unable to shut down system as there are some VM(s) running!" +msgstr "" msgid "Max:" msgstr "最大:" @@ -200,8 +215,10 @@ msgstr "接收" msgid "Sent" msgstr "发送" -msgid "Confirm" -msgstr "确认" +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "关闭或者重启主机会导致没有保存的工作丢失。继续关机/重启?" msgid "" "Debug report will be removed permanently and can't be recovered. Do you want " @@ -232,106 +249,17 @@ msgstr "删除" msgid "Download" msgstr "下载" -msgid "Some VM(s) are running!" -msgstr "有虚拟机在运行!" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "关闭或者重启主机会导致没有保存的工作丢失。继续关机/重启?" - msgid "" "This will delete the VM and its virtual disks. This operation cannot be " "undone. Would you like to continue?" msgstr "您正在删除虚拟机,本操作将不能恢复,是否继续?" -msgid "This will permanently delete the Template. Would you like to continue?" -msgstr "本操作将会永久删除模板,是否继续?" - -msgid "Failed to get application configuration" -msgstr "获取应用配置失败" - -msgid "This is not a valid linux path" -msgstr "这不是一个有效的LINUX路径" - -msgid "This is not a valid url." -msgstr "这不是一个有效的URL" - msgid "The VLAN id must be between 1 and 4094." msgstr "" -msgid "This is not a valid ISO file." -msgstr "这不是一个有效的ISO文件" - -msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" -msgstr "本操作将会永久删除存储池,是否继续?" - -msgid "The storage pool name can not be blank." -msgstr "存储池的名字不能为空" - -msgid "The storage pool path can not be blank." -msgstr "存储池的路径不能为空" - -msgid "NFS server mount path can not be blank." -msgstr "NFS服务器挂载路径不能为空" - -msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " -"underscores, and hyphens." -msgstr "无效的存储池名字,它应该只包括字母,数字,下划线及连接符" - -msgid "This is not a real linux path." -msgstr "这不是一个符合要求的LINUX路径" - -msgid "Invalid nfs mount path." -msgstr "无效的nfs挂载路径" - -msgid "No logical device selected." -msgstr "" - -msgid "This storage pool is empty." -msgstr "这个存储池为空" - -msgid "Failed to list the storage pool." -msgstr "展示模板列表失败" - -msgid "The storage pool is not active now." -msgstr "存储池没有被启用" - -msgid "Failed to delete template." -msgstr "删除模版失败" - -msgid "Guests" -msgstr "客户机" - -msgid "Host" -msgstr "主机" - -msgid "Templates" -msgstr "模板" - -msgid "Storage" -msgstr "存储" - msgid "unavailable" msgstr "无法获取" -msgid "Network" -msgstr "网络" - -msgid "isolated" -msgstr "隔离" - -msgid "NAT" -msgstr "NAT" - -msgid "bridged" -msgstr "桥接" - -msgid "connected to" -msgstr "连接到" - msgid "" "This action will interrupt network connectivity for any virtual machine that " "depend on this network." @@ -340,14 +268,38 @@ msgstr "此操作将中断依赖此网络的虚拟机的网络连接。" msgid "Create a network" msgstr "创建一个网络" -msgid "Warning" -msgstr "警告" +msgid "" +"This will permanently delete the Storage Pool. Would you like to continue?" +msgstr "本操作将会永久删除存储池,是否继续?" + +msgid "This storage pool is empty." +msgstr "这个存储池为空" msgid "" "It will format your disk and you will loose any data in there, are you sure " "to continue? " msgstr "你的磁盘将会格式化,磁盘上的数据会丢失,你确定要继续吗?" +msgid "The Storage Pool name can not be blank." +msgstr "" + +msgid "The Storage Pool path can not be blank." +msgstr "" + +msgid "NFS server mount path can not be blank." +msgstr "NFS服务器挂载路径不能为空" + +msgid "" +"Invalid Storage Pool name. It may only contain letters, numbers, " +"underscores, and hyphens." +msgstr "" + +msgid "Invalid NFS mount path." +msgstr "" + +msgid "No logical device selected." +msgstr "" + msgid "The iSCSI target can not be blank." msgstr "iSCSI目标不能为空" @@ -408,17 +360,17 @@ msgid "" "your system." msgstr "如果目录不存在,KIMCHI会自动在系统中创建一个新的目录" -msgid "NFS server IP" -msgstr "NFS服务器IP" +msgid "NFS Server IP" +msgstr "" -msgid "NFS server IP or hostname. It should not be empty." -msgstr "NFS服务器IP或者主机名, 不能为空。" +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr "" msgid "NFS Path" msgstr "NFS 路径" -msgid "The nfs exported path on nfs server" -msgstr "nfs服务器上导出的路径" +msgid "The nfs exported path on nfs server." +msgstr "" msgid "Device Path" msgstr "设备路径" @@ -626,3 +578,471 @@ msgstr "光驱" msgid "Storage Pool" msgstr "存储池" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +msgid "Datastore is not initiated in the model object." +msgstr "" + +#, python-format +msgid "Authentication failed for user '%(userid)s'. [Error code: %(code)s]" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "" + +#, python-format +msgid "Unable to parse distro file: %(filename)s.Make sure, it is a json file." +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "" + +#, python-format +msgid "Unable to find ISO file ISO %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" + +msgid "Virtual machine $(name)s already exists" +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s already " +"exists or it is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" + +msgid "Remote ISO image is not supported by this server." +msgstr "" + +#, python-format +msgid "Screenshot not supported for virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to rename virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)" +msgstr "" + +#, python-format +msgid "Unable to connect to powered off machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string" +msgstr "" + +#, python-format +msgid "Invalid template URI: %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI: %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are spice or vnc" +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" + +msgid "Specify a template to create a Virtual Machine from" +msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" + +msgid "Do not support guest interface hot plug attachment" +msgstr "" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "" + +#, python-format +msgid "Template %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Storage Pool %(pool)s specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "Storage Pool %(pool)s specified for template %(template)s is not active" +msgstr "" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for cdrom." +msgstr "" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" + +msgid "Template name must be a string" +msgstr "" + +msgid "Template icon must be a path to the image" +msgstr "" + +msgid "Template distribution must be a string" +msgstr "" + +msgid "Template distribution version must be a string" +msgstr "" + +msgid "The number of CPUs must be a integer" +msgstr "" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for Template" +msgstr "" + +msgid "Specify an ISO image as CDROM to create a Template" +msgstr "" + +msgid "All networks for the Template must be specified in a list." +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s does not exist" +msgstr "" + +msgid "Autostart flag must be true or false" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create the Storage Pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active Storage Pool %(name)s" +msgstr "" + +#, python-format +msgid "Unable to list Storage Pools. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to create Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to activate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to deactivate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" + +#, python-format +msgid "Unsupported Storage Pool type: %(type)s" +msgstr "" + +#, python-format +msgid "Error while getting xml for Storage Pool %(pool)s" +msgstr "" + +msgid "Storage Pool name must be a string" +msgstr "" + +msgid "Supported Storage Pool types are dir, netfs, logical and kimchi-iso" +msgstr "" + +msgid "Storage Pool path must be a string" +msgstr "" + +msgid "Storage Pool host must be a IP or hostname" +msgstr "" + +msgid "Storage Pool devices must be the full path to the block device" +msgstr "" + +msgid "Storage Pool devices parameter must be a list" +msgstr "" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" + +msgid "Login username of the iSCSI target must be a string" +msgstr "" + +msgid "Login password of the iSCSI target must be a string" +msgstr "" + +msgid "Specify name and type to create a Storage Pool" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s does not exist in Storage Pool %(pool)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create Storage Volume %(volume)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s " +"is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes because Storage Pool %(pool)s is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to wipe Storage Volumes %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to resize Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" + +msgid "Interface should be bare nic, bonding or bridge device." +msgstr "" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "" + +msgid "" +"Unable to create VLAN tagged bridge using interface %(iface)s. Details: " +"%(err)" +msgstr "" + +msgid "Network name must be a string" +msgstr "" + +msgid "Supported network types are isolated, nat and bridge" +msgstr "" + +msgid "Network subnet must be a string with ip address and prefix or netmask" +msgstr "" + +msgid "Network interface must be a string" +msgstr "" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "" + +msgid "Specify name and type to create a Network" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "" + +msgid "Debug report tool not found in system" +msgstr "" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Can not find generated debug report named %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" + +#, python-format +msgid "Unable to find %(item)s in datastore" +msgstr "" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "" + +#, python-format +msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +msgstr "" + +msgid "Unable to choose a virutal machine name" +msgstr "" -- 1.7.10.4

From: Aline Manera <alinefm@br.ibm.com>
Update po files to include new messages from i18n.py
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- po/en_US.po | 686 ++++++++++++++++++++++++++++++++++++++++++++++----------- po/kimchi.pot | 624 ++++++++++++++++++++++++++++++++++++++++++--------- po/pt_BR.po | 684 +++++++++++++++++++++++++++++++++++++++++++++----------- po/zh_CN.po | 678 +++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 2174 insertions(+), 498 deletions(-)
diff --git a/po/en_US.po b/po/en_US.po index 77e0677..309f315 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-01-20 18:46-0200\n" +"POT-Creation-Date: 2014-02-09 20:37-0200\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -105,15 +105,6 @@ msgstr "Edit" msgid "Delete" msgstr "Delete"
-msgid "Failed to list the template" -msgstr "Failed to list the template" - -msgid "Please choose a template" -msgstr "Please choose a template" - -msgid "Failed to create vm" -msgstr "Failed to create vm" - msgid "The username or password you entered is incorrect. Please try again." msgstr "The username or password you entered is incorrect. Please try again."
@@ -126,26 +117,50 @@ msgstr "Log in" msgid "Logging in..." msgstr "Logging in..."
+msgid "Host" +msgstr "Host" + +msgid "Guests" +msgstr "Guests" + +msgid "Templates" +msgstr "Templates" + +msgid "Storage" +msgstr "Storage" + +msgid "Network" +msgstr "Network" + msgid "Invalid URL. Redireced to home page." msgstr "Invalid URL. Redireced to home page."
-msgid "Failed to start" -msgstr "Failed to start" +msgid "Failed to get application configuration" +msgstr "Failed to get application configuration" + +msgid "This is not a valid linux path" +msgstr "This is not a valid linux path." Linux + +msgid "This is not a valid url." +msgstr "This is not a valid url." + +msgid "No such data exsit." +msgstr "" Why some msgstr are empty? I see that sometimes you are just emptying
I couldn't get the necessity of this patch... it seems that basically you are just moving msgids and msgstrs around with little or not modification. There might be one or another new message... but it is just impossible to review because this is intermingled with apparently unnecessary moves. On 02/09/2014 08:48 PM, Aline Manera wrote: the msgstr. I am wondering why this is needed. I am probably missing something here as I am just learning about this as I read these patches.
-msgid "Failed to stop" -msgstr "Failed to stop" +msgid "options needed." +msgstr ""
-msgid "Failed to reset" -msgstr "Failed to reset" +msgid "Delete Confirmation" +msgstr "Delete Confirmation"
-msgid "Failed to delete" -msgstr "Failed to delete" +msgid "OK" +msgstr "OK"
-msgid "Failed to list guests" -msgstr "Failed to list guests" +msgid "Confirm" +msgstr "Confirm"
-msgid "Failed to create template" -msgstr "Failed to create template" +msgid "Warning" +msgstr "Warning"
msgid "Create template successfully" msgstr "Create template successfully" @@ -153,17 +168,17 @@ msgstr "Create template successfully" msgid "No iso found" msgstr "No iso found"
-msgid "Failed to scan" -msgstr "Failed to scan" +msgid "This is not a valid ISO file." +msgstr "This is not a valid ISO file."
-msgid "Failed to list iso distributions" -msgstr "Failed to list iso distributions" +msgid "This will permanently delete the Template. Would you like to continue?" +msgstr "This will permanently delete the Template. Would you like to continue?"
template
-msgid "Delete Confirmation" -msgstr "Delete Confirmation" +msgid "It will take long time. Do you want to continue?" +msgstr ""
-msgid "OK" -msgstr "OK" +msgid "Unable to shut down system as there are some VM(s) running!" +msgstr ""
msgid "Max:" msgstr "Max:" @@ -186,8 +201,12 @@ msgstr "Received" msgid "Sent" msgstr "Sent"
-msgid "Confirm" -msgstr "Confirm" +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" +msgstr "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?"
msgid "" "Debug report will be removed permanently and can't be recovered. Do you want " @@ -220,16 +239,6 @@ msgstr "Remove" msgid "Download" msgstr "Download"
-msgid "Some VM(s) are running!" -msgstr "Some VM(s) are running!" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" - msgid "" "This will delete the VM and its virtual disks. This operation cannot be " "undone. Would you like to continue?" @@ -237,96 +246,12 @@ msgstr "" "This will delete the VM and its virtual disks. This operation cannot be " "undone. Would you like to continue?"
-msgid "This will permanently delete the Template. Would you like to continue?" -msgstr "This will permanently delete the Template. Would you like to continue?" - -msgid "Failed to get application configuration" -msgstr "Failed to get application configuration" - -msgid "This is not a valid linux path" -msgstr "This is not a valid linux path." - -msgid "This is not a valid url." -msgstr "This is not a valid url." - msgid "The VLAN id must be between 1 and 4094." msgstr "The VLAN id must be between 1 and 4094."
-msgid "This is not a valid ISO file." -msgstr "This is not a valid ISO file." - -msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" -msgstr "" -"This will permanently delete the Storage Pool. Would you like to continue?" - -msgid "The storage pool name can not be blank." -msgstr "The storage pool name can not be blank." - -msgid "The storage pool path can not be blank." -msgstr "The storage pool path can not be blank." - -msgid "NFS server mount path can not be blank." -msgstr "NFS server mount path can not be blank." - -msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " -"underscores, and hyphens." -msgstr "" -"Invalid Storage Pool name. It may only contain letters, numbers, " -"underscores, and hyphens." - -msgid "This is not a real linux path." -msgstr "This is not a real linux path." - -msgid "Invalid nfs mount path." -msgstr "Invalid nfs mount path." - -msgid "No logical device selected." -msgstr "No logical device selected." - -msgid "This storage pool is empty." -msgstr "This storage pool is empty." - -msgid "Failed to list the storage pool." -msgstr "Failed to list the storage pool" - -msgid "The storage pool is not active now." -msgstr "The storage pool is not active now." - -msgid "Failed to delete template." -msgstr "Failed to delete template." - -msgid "Guests" -msgstr "Guests" - -msgid "Host" -msgstr "Host" - -msgid "Templates" -msgstr "Templates" - -msgid "Storage" -msgstr "Storage" - msgid "unavailable" msgstr "unavailable"
-msgid "Network" -msgstr "Network" - -msgid "isolated" -msgstr "isolated" - -msgid "NAT" -msgstr "NAT" - -msgid "bridged" -msgstr "bridged" - -msgid "connected to" -msgstr "connected to" - msgid "" "This action will interrupt network connectivity for any virtual machine that " "depend on this network." @@ -337,8 +262,13 @@ msgstr "" msgid "Create a network" msgstr "Create a network"
-msgid "Warning" -msgstr "Warning" +msgid "" +"This will permanently delete the Storage Pool. Would you like to continue?" +msgstr "" +"This will permanently delete the Storage Pool. Would you like to continue?"
storage pool
+ +msgid "This storage pool is empty." +msgstr "This storage pool is empty."
msgid "" "It will format your disk and you will loose any data in there, are you sure " @@ -347,6 +277,26 @@ msgstr "" "It will format your disk and you will loose any data in there, are you sure " "to continue? "
+msgid "The Storage Pool name can not be blank." storage pool +msgstr "" + +msgid "The Storage Pool path can not be blank." storage pool +msgstr "" + +msgid "NFS server mount path can not be blank." +msgstr "NFS server mount path can not be blank." + +msgid "" +"Invalid Storage Pool name. It may only contain letters, numbers, " storage pool +"underscores, and hyphens." +msgstr "" + +msgid "Invalid NFS mount path." +msgstr "" + +msgid "No logical device selected." +msgstr "No logical device selected." + msgid "The iSCSI target can not be blank." msgstr "The iSCSI target can not be blank."
@@ -412,17 +362,17 @@ msgstr "" "Kimchi will try to create the directory when it does not already exist in " "your system."
-msgid "NFS server IP" -msgstr "NFS server IP" +msgid "NFS Server IP" +msgstr ""
-msgid "NFS server IP or hostname. It should not be empty." -msgstr "NFS server IP or hostname. It should not be empty." +msgid "NFS server IP or hostname. It can be input or chosen from history." +msgstr ""
msgid "NFS Path" msgstr "NFS Path"
-msgid "The nfs exported path on nfs server" -msgstr "The nfs exported path on nfs server" +msgid "The nfs exported path on nfs server." NFS +msgstr ""
msgid "Device Path" msgstr "Device Path" Device path @@ -630,3 +580,471 @@ msgstr "CDROM"
msgid "Storage Pool" msgstr "Storage Pool" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +msgid "Datastore is not initiated in the model object." +msgstr "" + +#, python-format +msgid "Authentication failed for user '%(userid)s'. [Error code: %(code)s]" +msgstr "" + +#, python-format +msgid "Error while getting block devices. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Error while getting block device information for %(device)s." +msgstr "" + +#, python-format +msgid "Unable to find distro file: %(filename)s" +msgstr "" + +#, python-format +msgid "Unable to parse distro file: %(filename)s.Make sure, it is a json file." Unable to parse distro file: %(filename)s. Make sure it is a JSON file. +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host target %(portal)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to login to iSCSI host %(host)s target %(target)s" +msgstr "" + +#, python-format +msgid "Unable to find ISO file ISO %(filename)s" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s is not bootable" +msgstr "" + +#, python-format +msgid "The ISO file %(filename)s does not have a valid El Torito boot record" +msgstr "" + +#, python-format +msgid "Invalid El Torito validation entry in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Invalid El Torito boot indicator in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Unexpected volume type for primary volume in ISO %(filename)s" +msgstr "" + +#, python-format +msgid "Bad format while reading volume descriptor in ISO %(filename)s" +msgstr "" + +msgid "Virtual machine $(name)s already exists" +msgstr "" + +#, python-format +msgid "Virtual machine %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Unable to rename virtual machine %(name)s. The name %(new_name)s already " +"exists or it is not powered off." +msgstr "" + +#, python-format +msgid "Unable to retrieve screenshot for stopped virtual machine %(name)s" +msgstr "" + +msgid "Remote ISO image is not supported by this server." +msgstr "" + +#, python-format +msgid "Screenshot not supported for virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "Unable to create virtual machine %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to rename virtual machine %(name)s. Details: %(err)s" +msgstr "" + +msgid "Unable to retrieve virtual machine %(name)s. Details: %(err)" +msgstr "" + +#, python-format +msgid "Unable to connect to powered off machine %(name)s." +msgstr "" + +msgid "Virtual machine name must be a string" +msgstr "" + +#, python-format +msgid "Invalid template URI: %(value)s specified for virtual machine" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI: %(value)s specified for virtual machine" +msgstr "" + +msgid "Supported virtual machine graphics are spice or vnc" VNC +msgstr "" + +msgid "Graphics address to listen on must be IPv4 or IPv6" +msgstr "" + +msgid "Specify a template to create a Virtual Machine from" virtual machine
Also, we are sometimes using VM and sometimes using virtual machine. We need to decide what we want to use and stick to only one.
+msgstr "" + +#, python-format +msgid "Interface %(iface)s does not exist in virtual machine %(name)s" +msgstr "" + +#, python-format +msgid "" +"Network %(network)s specified for virtual machine %(name)s does not exist" +msgstr "" + +msgid "Do not support guest interface hot plug attachment" +msgstr "" + +msgid "Supported virtual machine interfaces type is only network" +msgstr "" + +msgid "Network name for virtual machine interface must be a string" +msgstr "" + +msgid "Invalid network model card specified for virtual machine interface" +msgstr "" + +msgid "Specify type and network to add a new virtual machine interface" +msgstr "" + +#, python-format +msgid "Template %(name)s already exists" +msgstr "" + +#, python-format +msgid "Template %(name)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Network '%(network)s' specified for template %(template)s does not exist" +msgstr "" + +#, python-format +msgid "" +"Storage Pool %(pool)s specified for template %(template)s does not exist" Storage pool +msgstr "" + +#, python-format +msgid "Storage Pool %(pool)s specified for template %(template)s is not active" Storage pool +msgstr "" + +#, python-format +msgid "Invalid parameter '%(param)s' specified for cdrom." CDROM +msgstr "" + +#, python-format +msgid "Network %(network)s specified for template %(template)s is not active" +msgstr "" + +msgid "Template name must be a string" +msgstr "" + +msgid "Template icon must be a path to the image" +msgstr "" + +msgid "Template distribution must be a string" +msgstr "" + +msgid "Template distribution version must be a string" +msgstr "" + +msgid "The number of CPUs must be a integer" +msgstr "" + +msgid "Amount of memory (MB) must be an integer greater than 512" +msgstr "" + +msgid "Template CDROM must be a local or remote ISO file" +msgstr "" + +#, python-format +msgid "Invalid storage pool URI %(value)s specified for Template" +msgstr "" + +msgid "Specify an ISO image as CDROM to create a Template" +msgstr "" + +msgid "All networks for the Template must be specified in a list." +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s already exists" Storage pool +msgstr "" + +#, python-format +msgid "Storage Pool %(name)s does not exist" Storage pool +msgstr "" + +msgid "Autostart flag must be true or false" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create the Storage Pool %(name)s" storage pool +msgstr "" + +#, python-format +msgid "Unable to delete active Storage Pool %(name)s" storage pool +msgstr "" + +#, python-format +msgid "Unable to list Storage Pools. Details: %(err)s" storage pools +msgstr "" + +#, python-format +msgid "Unable to create Storage Pool %(name)s. Details: %(err)s" storage pool +msgstr "" + +#, python-format +msgid "" +"Unable to get number of Storage Volumes in Storage Pool %(name)s. Details: " storage volumes and storage pool... The same applies to lots of other messages below. +"%(err)s" +msgstr "" + +#, python-format +msgid "Unable to activate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to deactivate Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Pool %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create NFS Pool as export path %(path)s may block during mount" +msgstr "" + +#, python-format +msgid "Unable to create NFS Pool as export path %(path)s mount failed" +msgstr "" + +#, python-format +msgid "Unsupported Storage Pool type: %(type)s" +msgstr "" + +#, python-format +msgid "Error while getting xml for Storage Pool %(pool)s" +msgstr "" + +msgid "Storage Pool name must be a string" +msgstr "" + +msgid "Supported Storage Pool types are dir, netfs, logical and kimchi-iso" +msgstr "" + +msgid "Storage Pool path must be a string" +msgstr "" + +msgid "Storage Pool host must be a IP or hostname" +msgstr "" + +msgid "Storage Pool devices must be the full path to the block device" +msgstr "" + +msgid "Storage Pool devices parameter must be a list" +msgstr "" + +msgid "Target IQN of an iSCSI pool must be a string" +msgstr "" + +msgid "Port of a remote storage server must be an integer between 1 and 65535" +msgstr "" + +msgid "Login username of the iSCSI target must be a string" +msgstr "" + +msgid "Login password of the iSCSI target must be a string" +msgstr "" + +msgid "Specify name and type to create a Storage Pool" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s already exists" +msgstr "" + +#, python-format +msgid "Storage Volume %(name)s does not exist in Storage Pool %(pool)s" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(volume)s becuase Storage Pool %(pool)s is " +"not active" +msgstr "" + +#, python-format +msgid "Specify %(item)s in order to create Storage Volume %(volume)s" +msgstr "" + +#, python-format +msgid "" +"Unable to retrieve Storage Volume %(volume)s because Storage Pool %(pool)s " +"is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes because Storage Pool %(pool)s is not active" +msgstr "" + +#, python-format +msgid "" +"Unable to create Storage Volume %(name)s in Storage Pool %(pool)s. Details: " +"%(err)s" +msgstr "" + +#, python-format +msgid "" +"Unable to list Storage Volumes in Storage Pool %(pool)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to wipe Storage Volumes %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to delete Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to resize Storage Volume %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Interface %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Network %(name)s already exists" +msgstr "" + +#, python-format +msgid "Network %(name)s does not exist" +msgstr "" + +#, python-format +msgid "Subnet %(subnet)s specified for network %(network)s is not valid." +msgstr "" + +#, python-format +msgid "Specify a network interface to create bridged network %(name)s" +msgstr "" + +#, python-format +msgid "Unable to delete active network %(name)s" +msgstr "" + +#, python-format +msgid "Interface %(iface)s specified for network %(network)s is already in use" +msgstr "" + +msgid "Interface should be bare nic, bonding or bridge device." NIC +msgstr "" + +#, python-format +msgid "Unable to create network %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Unable to find a free IP address for network '%(name)s'" +msgstr "" + +msgid "" +"Unable to create VLAN tagged bridge using interface %(iface)s. Details: " +"%(err)" +msgstr "" + +msgid "Network name must be a string" +msgstr "" + +msgid "Supported network types are isolated, nat and bridge" NAT +msgstr "" + +msgid "Network subnet must be a string with ip address and prefix or netmask" IP +msgstr "" + +msgid "Network interface must be a string" +msgstr "" + +msgid "Network VLAN ID must be an integer between 1 and 4094" +msgstr "" + +msgid "Specify name and type to create a Network" +msgstr "" + +#, python-format +msgid "Debug report %(name)s does not exist" +msgstr "" + +msgid "Debug report tool not found in system" +msgstr "" + +#, python-format +msgid "Unable to create debug report %(name)s. Details: %(err)s." +msgstr "" + +#, python-format +msgid "Can not find generated debug report named %(name)s" +msgstr "" + +#, python-format +msgid "Unable to generate debug report %(name)s. Details: %(err)s" +msgstr "" + +#, python-format +msgid "Storage server %(server)s was not used by Kimchi" +msgstr "" + +#, python-format +msgid "Distro '%(name)s' does not exist" +msgstr "" + +#, python-format +msgid "Partition %(name)s does not exist in the host" +msgstr "" + +msgid "Unable to shutdown host machine as there are running virtual machines" +msgstr "" + +msgid "Unable to reboot host machine as there are running virtual machines" +msgstr "" + +#, python-format +msgid "Unable to find %(item)s in datastore" +msgstr "" + +#, python-format +msgid "Invalid URI %(uri)s" +msgstr "" + +#, python-format +msgid "Timeout while running command '%(cmd)s' after %(seconds)s seconds" +msgstr "" + +msgid "Unable to choose a virutal machine name" +msgstr "" diff --git a/po/kimchi.pot b/po/kimchi.pot index 836b013..f105d14 100755 --- a/po/kimchi.pot +++ b/po/kimchi.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-01-20 18:46-0200\n" +"POT-Creation-Date: 2014-02-09 20:37-0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -103,46 +103,61 @@ msgstr "" msgid "Delete" msgstr ""
-msgid "Failed to list the template" +msgid "The username or password you entered is incorrect. Please try again." msgstr ""
-msgid "Please choose a template" +msgid "This field is required." msgstr ""
-msgid "Failed to create vm" +msgid "Log in" msgstr ""
-msgid "The username or password you entered is incorrect. Please try again." +msgid "Logging in..." msgstr ""
-msgid "This field is required." +msgid "Host" msgstr ""
-msgid "Log in" +msgid "Guests" msgstr ""
-msgid "Logging in..." +msgid "Templates" +msgstr "" + +msgid "Storage" +msgstr "" + +msgid "Network" msgstr ""
msgid "Invalid URL. Redireced to home page." msgstr ""
-msgid "Failed to start" +msgid "Failed to get application configuration" +msgstr "" + +msgid "This is not a valid linux path" msgstr ""
-msgid "Failed to stop" +msgid "This is not a valid url." msgstr ""
-msgid "Failed to reset" +msgid "No such data exsit." msgstr ""
-msgid "Failed to delete" +msgid "options needed." msgstr ""
-msgid "Failed to list guests" +msgid "Delete Confirmation" msgstr ""
-msgid "Failed to create template" +msgid "OK" +msgstr "" + +msgid "Confirm" +msgstr "" + +msgid "Warning" msgstr ""
msgid "Create template successfully" @@ -151,16 +166,16 @@ msgstr "" msgid "No iso found" msgstr ""
-msgid "Failed to scan" +msgid "This is not a valid ISO file." msgstr ""
-msgid "Failed to list iso distributions" +msgid "This will permanently delete the Template. Would you like to continue?" msgstr ""
-msgid "Delete Confirmation" +msgid "It will take long time. Do you want to continue?" msgstr ""
-msgid "OK" +msgid "Unable to shut down system as there are some VM(s) running!" msgstr ""
msgid "Max:" @@ -184,7 +199,9 @@ msgstr "" msgid "Sent" msgstr ""
-msgid "Confirm" +msgid "" +"Shutting down or restarting host will cause unsaved work lost. Continue to " +"shut down/restarting?" msgstr ""
msgid "" @@ -216,120 +233,55 @@ msgstr "" msgid "Download" msgstr ""
-msgid "Some VM(s) are running!" -msgstr "" - -msgid "" -"Shutting down or restarting host will cause unsaved work lost. Continue to " -"shut down/restarting?" -msgstr "" - msgid "" "This will delete the VM and its virtual disks. This operation cannot be " "undone. Would you like to continue?" msgstr ""
-msgid "This will permanently delete the Template. Would you like to continue?" -msgstr "" - -msgid "Failed to get application configuration" -msgstr "" - -msgid "This is not a valid linux path" -msgstr "" - -msgid "This is not a valid url." URL.
The comments on the above file applies to all the other files here. Best regards, Leonardo Garcia
-msgstr "" - msgid "The VLAN id must be between 1 and 4094." msgstr ""
-msgid "This is not a valid ISO file." +msgid "unavailable" msgstr ""
msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" -msgstr "" - -msgid "The storage pool name can not be blank." -msgstr "" - -msgid "The storage pool path can not be blank." +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." msgstr ""
-msgid "NFS server mount path can not be blank." +msgid "Create a network" msgstr ""
msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " -"underscores, and hyphens." -msgstr "" - -msgid "This is not a real linux path." -msgstr "" - -msgid "Invalid nfs mount path." -msgstr "" - -msgid "No logical device selected." +"This will permanently delete the Storage Pool. Would you like to continue?" msgstr ""
msgid "This storage pool is empty." msgstr ""
<...>
participants (2)
-
Aline Manera
-
Leonardo Augusto Guimarães Garcia