[PATCH 0/8 V2] Refactor exception

From: Aline Manera <alinefm@br.ibm.com> V1 -> V2: - Add missing messages to i18n.py - Fix inconsistency with error message KCHTMPL6001M - Replace "Storage Pool" to "storage pool" - Replace "Storage Volume" to "storage volume" - Replace "VM" to "virtual machine" - And other minor changes suggested by Leonardo 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 | 739 ++++++++++++++++++++++++------ po/gen-pot.in | 8 +- po/kimchi.pot | 664 ++++++++++++++++++++++----- po/pt_BR.po | 738 +++++++++++++++++++++++------ po/zh_CN.po | 726 +++++++++++++++++++++++------ src/kimchi/API.json | 144 ++++-- src/kimchi/Makefile.am | 1 + src/kimchi/asynctask.py | 4 +- src/kimchi/auth.py | 8 +- src/kimchi/control/base.py | 116 ++--- src/kimchi/control/utils.py | 14 +- src/kimchi/disks.py | 5 +- src/kimchi/distroloader.py | 5 +- src/kimchi/exception.py | 42 +- src/kimchi/i18n.py | 181 ++++++++ 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 | 10 +- src/kimchi/template.py | 2 +- src/kimchi/utils.py | 12 +- src/kimchi/vmtemplate.py | 6 +- tests/test_exception.py | 12 +- 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/guest-add.html.tmpl | 2 +- ui/pages/i18n.html.tmpl | 172 ++++--- ui/pages/storagepool-add.html.tmpl | 4 +- ui/pages/tabs/network.html.tmpl | 2 +- 65 files changed, 3243 insertions(+), 1090 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: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 02/11/2014 03:52 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 The messages are associated with a code which will be used to identify the error independent of the language used in Kimchi. The code has a basic rule: - Start with KCH -> as it is related to Kimchi and not to any other plugin - Follow by the resource it references to: VM, TMPL, POOL, VOL, etc - And a number to represent the error: starting with 0001, 0002, etc for backend and for UI it starts in 6001, 6002, etc - And at the end which the message is: E (for error), M (for message), W (for warning), I (for info) So we will have some codes as: KCHVM0001E, KCHTMPL0001E, KCHPOOL0001E, KCHVM60001M, KCHPOOL6001M Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/i18n.py | 15 +++++ src/kimchi/i18n.py | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 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..f8071e9 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -26,4 +26,156 @@ _ = gettext.gettext messages = { + "KCHAPI0001E": _("Unkown parameter specified %(value)s"), + "KCHAPI0002E": _("Delete is not allowed for %(resource)s"), + "KCHAPI0003E": _("%(resource)s does not implement update method"), + "KCHAPI0004E": _("Parameters %(params)s are not allowed to be updated in %(resource)s"), + "KCHAPI0005E": _("Create is not allowed for %(resource)s"), + "KCHAPI0006E": _("Unable to parse JSON request"), + "KCHAPI0007E": _("This API only supports"), + + "KCHASYNC0001E": _("Datastore is not initiated in the model object."), + + "KCHAUTH0001E": _("Authentication failed for user '%(userid)s'. [Error code: %(code)s]"), + "KCHAUTH0002E": _("You are not authorized to access Kimchi"), + "KCHAUTH0003E": _("Specify %(item)s to login into Kimchi"), + + "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

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 02/11/2014 03:52 PM, Aline Manera 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
The messages are associated with a code which will be used to identify the error independent of the language used in Kimchi. The code has a basic rule: - Start with KCH -> as it is related to Kimchi and not to any other plugin - Follow by the resource it references to: VM, TMPL, POOL, VOL, etc - And a number to represent the error: starting with 0001, 0002, etc for backend and for UI it starts in 6001, 6002, etc - And at the end which the message is: E (for error), M (for message), W (for warning), I (for info)
So we will have some codes as: KCHVM0001E, KCHTMPL0001E, KCHPOOL0001E, KCHVM60001M, KCHPOOL6001M
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/i18n.py | 15 +++++ src/kimchi/i18n.py | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 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..f8071e9 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -26,4 +26,156 @@ _ = gettext.gettext
messages = { + "KCHAPI0001E": _("Unkown parameter specified %(value)s"), + "KCHAPI0002E": _("Delete is not allowed for %(resource)s"), + "KCHAPI0003E": _("%(resource)s does not implement update method"), + "KCHAPI0004E": _("Parameters %(params)s are not allowed to be updated in %(resource)s"), + "KCHAPI0005E": _("Create is not allowed for %(resource)s"), + "KCHAPI0006E": _("Unable to parse JSON request"), + "KCHAPI0007E": _("This API only supports"), + + "KCHASYNC0001E": _("Datastore is not initiated in the model object."), + + "KCHAUTH0001E": _("Authentication failed for user '%(userid)s'. [Error code: %(code)s]"), + "KCHAUTH0002E": _("You are not authorized to access Kimchi"), + "KCHAUTH0003E": _("Specify %(item)s to login into Kimchi"), + + "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: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 02/11/2014 03:52 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 | 116 +++++++++++++++++++++---------------------- src/kimchi/control/utils.py | 14 +++--- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py index f50ff6e..252e9ef 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 @@ -100,12 +98,13 @@ class Resource(object): fn(*self.model_args) cherrypy.response.status = 204 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) + e = InvalidOperation('KCHAPI0002E', {'resource': + get_class_name(self)}) + raise cherrypy.HTTPError(405, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message) @cherrypy.expose def index(self): @@ -113,33 +112,34 @@ 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: update = getattr(self.model, model_fn(self, 'update')) except AttributeError: - error = "%s does not implement update method" - raise cherrypy.HTTPError(405, error % get_class_name(self)) + e = InvalidOperation('KCHAPI0003E', {'resource': + get_class_name(self)}) + raise cherrypy.HTTPError(405, e.message) params = parse_request() validate_params(params, self, 'update') @@ -148,8 +148,10 @@ class Resource(object): invalids = [v for v in params.keys() if v not in self.update_params] if invalids: - error = "%s are not allowed to be updated" % invalids - raise cherrypy.HTTPError(405, error) + msg_args = {'params': ", ".join(invalids), + 'resource': get_class_name(self)} + e = InvalidOperation('KCHAPI0004E', msg_args) + raise cherrypy.HTTPError(405, e.message) ident = update(self.ident, params) if ident != self.ident: @@ -199,8 +201,9 @@ class Collection(object): try: create = getattr(self.model, model_fn(self, 'create')) except AttributeError: - error = 'Create is not allowed for %s' % get_class_name(self) - raise cherrypy.HTTPError(405, error) + e = InvalidOperation('KCHAPI0005E', {'resource': + get_class_name(self)}) + raise cherrypy.HTTPError(405, e.message) params = parse_request() validate_params(params, self, 'create') @@ -264,28 +267,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): @@ -299,8 +298,9 @@ class AsyncCollection(Collection): try: create = getattr(self.model, model_fn(self, 'create')) except AttributeError: - error = 'Create is not allowed for %s' % get_class_name(self) - raise cherrypy.HTTPError(405, error) + e = InvalidOperation('KCHAPI0005E', {'resource': + get_class_name(self)}) + raise cherrypy.HTTPError(405, e.message) params = parse_request() args = self.model_args + [params] diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py index 9c6878b..ebfdda7 100644 --- a/src/kimchi/control/utils.py +++ b/src/kimchi/control/utils.py @@ -30,7 +30,7 @@ import json from jsonschema import Draft3Validator, ValidationError, FormatChecker -from kimchi.exception import InvalidParameter +from kimchi.exception import InvalidParameter, OperationFailed from kimchi.utils import import_module, listPathModules @@ -77,10 +77,11 @@ def parse_request(): try: return json.loads(rawbody) except ValueError: - raise cherrypy.HTTPError(400, "Unable to parse JSON request") + e = OperationFailed('KCHAPI0006E') + raise cherrypy.HTTPError(400, e.message) else: - raise cherrypy.HTTPError(415, "This API only supports" - " 'application/json'") + e = OperationFailed('KCHAPI0007E') + raise cherrypy.HTTPError(415, e.message) def internal_redirect(url): @@ -101,9 +102,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

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 02/11/2014 03:52 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 | 116 +++++++++++++++++++++---------------------- src/kimchi/control/utils.py | 14 +++--- 2 files changed, 65 insertions(+), 65 deletions(-)
diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py index f50ff6e..252e9ef 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 @@ -100,12 +98,13 @@ class Resource(object): fn(*self.model_args) cherrypy.response.status = 204 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) + e = InvalidOperation('KCHAPI0002E', {'resource': + get_class_name(self)}) + raise cherrypy.HTTPError(405, e.message) + except OperationFailed, e: + raise cherrypy.HTTPError(500, e.message) + except InvalidOperation, e: + raise cherrypy.HTTPError(400, e.message)
@cherrypy.expose def index(self): @@ -113,33 +112,34 @@ 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: update = getattr(self.model, model_fn(self, 'update')) except AttributeError: - error = "%s does not implement update method" - raise cherrypy.HTTPError(405, error % get_class_name(self)) + e = InvalidOperation('KCHAPI0003E', {'resource': + get_class_name(self)}) + raise cherrypy.HTTPError(405, e.message)
params = parse_request() validate_params(params, self, 'update') @@ -148,8 +148,10 @@ class Resource(object): invalids = [v for v in params.keys() if v not in self.update_params] if invalids: - error = "%s are not allowed to be updated" % invalids - raise cherrypy.HTTPError(405, error) + msg_args = {'params': ", ".join(invalids), + 'resource': get_class_name(self)} + e = InvalidOperation('KCHAPI0004E', msg_args) + raise cherrypy.HTTPError(405, e.message)
ident = update(self.ident, params) if ident != self.ident: @@ -199,8 +201,9 @@ class Collection(object): try: create = getattr(self.model, model_fn(self, 'create')) except AttributeError: - error = 'Create is not allowed for %s' % get_class_name(self) - raise cherrypy.HTTPError(405, error) + e = InvalidOperation('KCHAPI0005E', {'resource': + get_class_name(self)}) + raise cherrypy.HTTPError(405, e.message)
params = parse_request() validate_params(params, self, 'create') @@ -264,28 +267,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): @@ -299,8 +298,9 @@ class AsyncCollection(Collection): try: create = getattr(self.model, model_fn(self, 'create')) except AttributeError: - error = 'Create is not allowed for %s' % get_class_name(self) - raise cherrypy.HTTPError(405, error) + e = InvalidOperation('KCHAPI0005E', {'resource': + get_class_name(self)}) + raise cherrypy.HTTPError(405, e.message)
params = parse_request() args = self.model_args + [params] diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py index 9c6878b..ebfdda7 100644 --- a/src/kimchi/control/utils.py +++ b/src/kimchi/control/utils.py @@ -30,7 +30,7 @@ import json from jsonschema import Draft3Validator, ValidationError, FormatChecker
-from kimchi.exception import InvalidParameter +from kimchi.exception import InvalidParameter, OperationFailed from kimchi.utils import import_module, listPathModules
@@ -77,10 +77,11 @@ def parse_request(): try: return json.loads(rawbody) except ValueError: - raise cherrypy.HTTPError(400, "Unable to parse JSON request") + e = OperationFailed('KCHAPI0006E') + raise cherrypy.HTTPError(400, e.message) else: - raise cherrypy.HTTPError(415, "This API only supports" - " 'application/json'") + e = OperationFailed('KCHAPI0007E') + raise cherrypy.HTTPError(415, e.message)
def internal_redirect(url): @@ -101,9 +102,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):

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 | 8 ++- 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/root.py | 7 +- src/kimchi/template.py | 2 +- src/kimchi/utils.py | 12 ++-- src/kimchi/vmtemplate.py | 6 +- tests/test_exception.py | 12 ++-- tests/test_rest.py | 4 +- tests/utils.py | 5 +- 30 files changed, 266 insertions(+), 222 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..c5c6266 100644 --- a/src/kimchi/auth.py +++ b/src/kimchi/auth.py @@ -29,7 +29,7 @@ import re from kimchi import template -from kimchi.exception import OperationFailed +from kimchi.exception import InvalidOperation, OperationFailed SESSION_USER = 'userid' @@ -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 @@ -152,4 +153,5 @@ def kimchiauth(*args, **kwargs): if not from_browser(): cherrypy.response.headers['WWW-Authenticate'] = 'Basic realm=kimchi' - raise cherrypy.HTTPError("401 Unauthorized") + e = InvalidOperation('KCHAUTH0002E') + raise cherrypy.HTTPError(401, e.message) 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/root.py b/src/kimchi/root.py index 2b5c4b8..37d59e2 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -33,7 +33,7 @@ from kimchi.config import paths from kimchi.control import sub_nodes from kimchi.control.base import Resource from kimchi.control.utils import parse_request -from kimchi.exception import OperationFailed +from kimchi.exception import MissingParameter, OperationFailed class Root(Resource): @@ -105,8 +105,9 @@ class KimchiRoot(Root): try: userid = params['userid'] password = params['password'] - except KeyError, key: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key) + except KeyError, item: + e = MissingParameter('KCHAUTH0003E', {'item': item}) + raise cherrypy.HTTPError(400, e.message) try: auth.login(userid, password) 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..3545de4 100644 --- a/src/kimchi/vmtemplate.py +++ b/src/kimchi/vmtemplate.py @@ -58,7 +58,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 +66,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..2209319 100644 --- a/tests/test_exception.py +++ b/tests/test_exception.py @@ -63,13 +63,13 @@ class ExceptionTests(unittest.TestCase): # test 405 wrong method resp = json.loads(request(host, port, '/', None, 'DELETE').read()) - msg = 'Delete is not allowed for kimchiroot' + msg = u'KCHAPI0002E: Delete is not allowed for kimchiroot' self.assertEquals('405 Method Not Allowed', resp.get('code')) self.assertEquals(msg, resp.get('reason')) # test 400 parse error resp = json.loads(request(host, port, '/vms', '{', 'POST').read()) - msg = 'Unable to parse JSON request' + msg = u'KCHAPI0006E: Unable to parse JSON request' self.assertEquals('400 Bad Request', resp.get('code')) self.assertEquals(msg, resp.get('reason')) self.assertNotIn('call_stack', resp) @@ -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) @@ -93,13 +93,13 @@ class ExceptionTests(unittest.TestCase): # test 405 wrong method resp = json.loads(request(host, port, '/', None, 'DELETE').read()) - msg = 'Delete is not allowed for kimchiroot' + msg = u'KCHAPI0002E: Delete is not allowed for kimchiroot' self.assertEquals('405 Method Not Allowed', resp.get('code')) self.assertEquals(msg, resp.get('reason')) # test 400 parse error resp = json.loads(request(host, port, '/vms', '{', 'POST').read()) - msg = 'Unable to parse JSON request' + msg = u'KCHAPI0006E: Unable to parse JSON request' self.assertEquals('400 Bad Request', resp.get('code')) self.assertEquals(msg, resp.get('reason')) self.assertIn('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

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 02/11/2014 03:52 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 | 8 ++- 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/root.py | 7 +- src/kimchi/template.py | 2 +- src/kimchi/utils.py | 12 ++-- src/kimchi/vmtemplate.py | 6 +- tests/test_exception.py | 12 ++-- tests/test_rest.py | 4 +- tests/utils.py | 5 +- 30 files changed, 266 insertions(+), 222 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..c5c6266 100644 --- a/src/kimchi/auth.py +++ b/src/kimchi/auth.py @@ -29,7 +29,7 @@ import re
from kimchi import template -from kimchi.exception import OperationFailed +from kimchi.exception import InvalidOperation, OperationFailed
SESSION_USER = 'userid' @@ -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
@@ -152,4 +153,5 @@ def kimchiauth(*args, **kwargs): if not from_browser(): cherrypy.response.headers['WWW-Authenticate'] = 'Basic realm=kimchi'
- raise cherrypy.HTTPError("401 Unauthorized") + e = InvalidOperation('KCHAUTH0002E') + raise cherrypy.HTTPError(401, e.message) 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/root.py b/src/kimchi/root.py index 2b5c4b8..37d59e2 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -33,7 +33,7 @@ from kimchi.config import paths from kimchi.control import sub_nodes from kimchi.control.base import Resource from kimchi.control.utils import parse_request -from kimchi.exception import OperationFailed +from kimchi.exception import MissingParameter, OperationFailed
class Root(Resource): @@ -105,8 +105,9 @@ class KimchiRoot(Root): try: userid = params['userid'] password = params['password'] - except KeyError, key: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key) + except KeyError, item: + e = MissingParameter('KCHAUTH0003E', {'item': item}) + raise cherrypy.HTTPError(400, e.message)
try: auth.login(userid, password) 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..3545de4 100644 --- a/src/kimchi/vmtemplate.py +++ b/src/kimchi/vmtemplate.py @@ -58,7 +58,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 +66,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..2209319 100644 --- a/tests/test_exception.py +++ b/tests/test_exception.py @@ -63,13 +63,13 @@ class ExceptionTests(unittest.TestCase):
# test 405 wrong method resp = json.loads(request(host, port, '/', None, 'DELETE').read()) - msg = 'Delete is not allowed for kimchiroot' + msg = u'KCHAPI0002E: Delete is not allowed for kimchiroot' self.assertEquals('405 Method Not Allowed', resp.get('code')) self.assertEquals(msg, resp.get('reason'))
# test 400 parse error resp = json.loads(request(host, port, '/vms', '{', 'POST').read()) - msg = 'Unable to parse JSON request' + msg = u'KCHAPI0006E: Unable to parse JSON request' self.assertEquals('400 Bad Request', resp.get('code')) self.assertEquals(msg, resp.get('reason')) self.assertNotIn('call_stack', resp) @@ -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)
@@ -93,13 +93,13 @@ class ExceptionTests(unittest.TestCase):
# test 405 wrong method resp = json.loads(request(host, port, '/', None, 'DELETE').read()) - msg = 'Delete is not allowed for kimchiroot' + msg = u'KCHAPI0002E: Delete is not allowed for kimchiroot' self.assertEquals('405 Method Not Allowed', resp.get('code')) self.assertEquals(msg, resp.get('reason'))
# test 400 parse error resp = json.loads(request(host, port, '/vms', '{', 'POST').read()) - msg = 'Unable to parse JSON request' + msg = u'KCHAPI0006E: Unable to parse JSON request' self.assertEquals('400 Bad Request', resp.get('code')) self.assertEquals(msg, resp.get('reason')) self.assertIn('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

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: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 02/11/2014 03:52 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/guest-add.html.tmpl | 2 +- ui/pages/i18n.html.tmpl | 172 ++++++++++++++---------------- ui/pages/storagepool-add.html.tmpl | 4 +- ui/pages/tabs/network.html.tmpl | 2 +- 20 files changed, 198 insertions(+), 209 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..3704f30 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['KCHTMPL6003M'], + 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/guest-add.html.tmpl b/ui/pages/guest-add.html.tmpl index 36a0f35..e99eb68 100644 --- a/ui/pages/guest-add.html.tmpl +++ b/ui/pages/guest-add.html.tmpl @@ -38,7 +38,7 @@ <h2>1. $_("Virtual Machine Name")</h2> <div class="field"> <p class="text-help"> - $_("The name used to identify the VM. If omitted, a name will be chosen based on the template used.") + $_("The name used to identify the virtual machine. If omitted, a name will be chosen based on the template used.") </p> <input type="text" class="text" style="width: 300px" name="name"> </div> diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl index d63d4e9..098a0a9 100644 --- a/ui/pages/i18n.html.tmpl +++ b/ui/pages/i18n.html.tmpl @@ -6,6 +6,7 @@ * Authors: * Mei Na Zhou <zhoumein@linux.vnet.ibm.com> * ShaoHe Feng <shaohef@linux.vnet.ibm.com> + * Aline Manera <alinefm@linux.vnet.ibm.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,99 +37,84 @@ <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")", + + 'KCHTMPL6001W': "$_("No iso found")", + + 'KCHTMPL6002E': "$_("This is not a valid ISO file.")", + + 'KCHTMPL6001M': "$_("Create template successfully")", + 'KCHTMPL6002M': "$_("It will take long time. Do you want to continue?")", + 'KCHTMPL6003M': "$_("This will permanently delete the template. Would you like to continue?")", + + 'KCHHOST6001E': "$_("Unable to shut down system as there are some virtual machines 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 virtual machine 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> diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl index dac99fe..9e93298 100644 --- a/ui/pages/storagepool-add.html.tmpl +++ b/ui/pages/storagepool-add.html.tmpl @@ -87,7 +87,7 @@ <section class="form-section"> <h2>4. $_("NFS Path")</h2> <div class="field storage-field"> - <p class="text-help">$_("The nfs exported path on nfs server.")</p> + <p class="text-help">$_("The NFS exported path on NFS server.")</p> <div id="targetFilterSelectId" class="storage-add-input-width"> <input id="nfspathId" class="input" disabled/> <div> @@ -100,7 +100,7 @@ </div> <div class="logical-section tmpl-html"> <section class="form-section storageType"> - <h2>3. $_("Device Path")</h2> + <h2>3. $_("Device path")</h2> <div class="host-partition"></div> </section> </div> diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl index 8cd991f..81c1566 100644 --- a/ui/pages/tabs/network.html.tmpl +++ b/ui/pages/tabs/network.html.tmpl @@ -69,7 +69,7 @@ </div> <div class="input-container"> <input type="radio" id="networkTypeBri" name="networkType" value="bridged"> - <label for="networkTypeBri">$_("Bridged: VMs are connected to physical network directly")</label> + <label for="networkTypeBri">$_("Bridged: Virtual machines are connected to physical network directly")</label> </div> <div class="destination"> <label>$_("Destination"): </label> -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 02/11/2014 03:52 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/guest-add.html.tmpl | 2 +- ui/pages/i18n.html.tmpl | 172 ++++++++++++++---------------- ui/pages/storagepool-add.html.tmpl | 4 +- ui/pages/tabs/network.html.tmpl | 2 +- 20 files changed, 198 insertions(+), 209 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..3704f30 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['KCHTMPL6003M'], + 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/guest-add.html.tmpl b/ui/pages/guest-add.html.tmpl index 36a0f35..e99eb68 100644 --- a/ui/pages/guest-add.html.tmpl +++ b/ui/pages/guest-add.html.tmpl @@ -38,7 +38,7 @@ <h2>1. $_("Virtual Machine Name")</h2> <div class="field"> <p class="text-help"> - $_("The name used to identify the VM. If omitted, a name will be chosen based on the template used.") + $_("The name used to identify the virtual machine. If omitted, a name will be chosen based on the template used.") </p> <input type="text" class="text" style="width: 300px" name="name"> </div> diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl index d63d4e9..098a0a9 100644 --- a/ui/pages/i18n.html.tmpl +++ b/ui/pages/i18n.html.tmpl @@ -6,6 +6,7 @@ * Authors: * Mei Na Zhou <zhoumein@linux.vnet.ibm.com> * ShaoHe Feng <shaohef@linux.vnet.ibm.com> + * Aline Manera <alinefm@linux.vnet.ibm.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,99 +37,84 @@ <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")", + + 'KCHTMPL6001W': "$_("No iso found")", + + 'KCHTMPL6002E': "$_("This is not a valid ISO file.")", + + 'KCHTMPL6001M': "$_("Create template successfully")", + 'KCHTMPL6002M': "$_("It will take long time. Do you want to continue?")", + 'KCHTMPL6003M': "$_("This will permanently delete the template. Would you like to continue?")", + + 'KCHHOST6001E': "$_("Unable to shut down system as there are some virtual machines 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 virtual machine 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> diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl index dac99fe..9e93298 100644 --- a/ui/pages/storagepool-add.html.tmpl +++ b/ui/pages/storagepool-add.html.tmpl @@ -87,7 +87,7 @@ <section class="form-section"> <h2>4. $_("NFS Path")</h2> <div class="field storage-field"> - <p class="text-help">$_("The nfs exported path on nfs server.")</p> + <p class="text-help">$_("The NFS exported path on NFS server.")</p> <div id="targetFilterSelectId" class="storage-add-input-width"> <input id="nfspathId" class="input" disabled/> <div> @@ -100,7 +100,7 @@ </div> <div class="logical-section tmpl-html"> <section class="form-section storageType"> - <h2>3. $_("Device Path")</h2> + <h2>3. $_("Device path")</h2> <div class="host-partition"></div> </section> </div> diff --git a/ui/pages/tabs/network.html.tmpl b/ui/pages/tabs/network.html.tmpl index 8cd991f..81c1566 100644 --- a/ui/pages/tabs/network.html.tmpl +++ b/ui/pages/tabs/network.html.tmpl @@ -69,7 +69,7 @@ </div> <div class="input-container"> <input type="radio" id="networkTypeBri" name="networkType" value="bridged"> - <label for="networkTypeBri">$_("Bridged: VMs are connected to physical network directly")</label> + <label for="networkTypeBri">$_("Bridged: Virtual machines are connected to physical network directly")</label> </div> <div class="destination"> <label>$_("Destination"): </label>

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 | 739 +++++++++++++++++++++++++++++++++++++++++++++------------ po/kimchi.pot | 664 ++++++++++++++++++++++++++++++++++++++++++--------- po/pt_BR.po | 738 ++++++++++++++++++++++++++++++++++++++++++++------------ po/zh_CN.po | 726 +++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 2327 insertions(+), 540 deletions(-) diff --git a/po/en_US.po b/po/en_US.po index 77e0677..5a5327a 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-11 15:02-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" @@ -36,11 +36,9 @@ msgid "Virtual Machine Name" msgstr "Virtual Machine Name" msgid "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." msgstr "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." msgid "Template" msgstr "Template" @@ -105,15 +103,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,38 +115,38 @@ msgstr "Log in" msgid "Logging in..." msgstr "Logging in..." -msgid "Invalid URL. Redireced to home page." -msgstr "Invalid URL. Redireced to home page." +msgid "Host" +msgstr "Host" -msgid "Failed to start" -msgstr "Failed to start" +msgid "Guests" +msgstr "Guests" -msgid "Failed to stop" -msgstr "Failed to stop" +msgid "Templates" +msgstr "Templates" -msgid "Failed to reset" -msgstr "Failed to reset" +msgid "Storage" +msgstr "Storage" -msgid "Failed to delete" -msgstr "Failed to delete" +msgid "Network" +msgstr "Network" -msgid "Failed to list guests" -msgstr "Failed to list guests" +msgid "Invalid URL. Redireced to home page." +msgstr "Invalid URL. Redireced to home page." -msgid "Failed to create template" -msgstr "Failed to create template" +msgid "Failed to get application configuration" +msgstr "Failed to get application configuration" -msgid "Create template successfully" -msgstr "Create template successfully" +msgid "This is not a valid Linux path" +msgstr "" -msgid "No iso found" -msgstr "No iso found" +msgid "This is not a valid URL." +msgstr "" -msgid "Failed to scan" -msgstr "Failed to scan" +msgid "No such data exsit." +msgstr "" -msgid "Failed to list iso distributions" -msgstr "Failed to list iso distributions" +msgid "options needed." +msgstr "" msgid "Delete Confirmation" msgstr "Delete Confirmation" @@ -165,6 +154,30 @@ msgstr "Delete Confirmation" msgid "OK" msgstr "OK" +msgid "Confirm" +msgstr "Confirm" + +msgid "Warning" +msgstr "Warning" + +msgid "No iso found" +msgstr "No iso found" + +msgid "This is not a valid ISO file." +msgstr "This is not a valid ISO file." + +msgid "Create template successfully" +msgstr "Create template successfully" + +msgid "It will take long time. Do you want to continue?" +msgstr "" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" + msgid "Max:" msgstr "Max:" @@ -186,8 +199,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,113 +237,17 @@ 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?" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" 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 +258,12 @@ 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 "" + +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 +272,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,20 +357,20 @@ 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" +msgid "Device path" +msgstr "" msgid "iSCSI Server" msgstr "iSCSI Server" @@ -517,8 +462,8 @@ msgstr "Isolated: no physical network connection" msgid "NAT: outbound physical network connection only" msgstr "NAT: outbound physical network connection only" -msgid "Bridged: VMs are connected to physical network directly" -msgstr "Bridged: VMs are connected to physical network directly" +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" msgid "Destination" msgstr "Destination" @@ -630,3 +575,501 @@ msgstr "CDROM" msgid "Storage Pool" msgstr "Storage Pool" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +#, python-format +msgid "Delete is not allowed for %(resource)s" +msgstr "" + +#, python-format +msgid "%(resource)s does not implement update method" +msgstr "" + +#, python-format +msgid "Parameters %(params)s are not allowed to be updated in %(resource)s" +msgstr "" + +#, python-format +msgid "Create is not allowed for %(resource)s" +msgstr "" + +msgid "Unable to parse JSON request" +msgstr "" + +msgid "This API only supports" +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 "" + +msgid "You are not authorized to access Kimchi" +msgstr "" + +#, python-format +msgid "Specify %(item)s to login into Kimchi" +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..a4b3935 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-11 15:02-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" @@ -36,8 +36,8 @@ msgid "Virtual Machine Name" msgstr "" msgid "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." msgstr "" msgid "Template" @@ -103,64 +103,79 @@ 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 "Create template successfully" +msgid "Confirm" +msgstr "" + +msgid "Warning" 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 "Create template successfully" msgstr "" -msgid "Delete Confirmation" +msgid "It will take long time. Do you want to continue?" msgstr "" -msgid "OK" +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines 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,39 +233,35 @@ 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?" +"This will delete the virtual machine 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?" +msgid "The VLAN id must be between 1 and 4094." msgstr "" -msgid "Failed to get application configuration" +msgid "unavailable" msgstr "" -msgid "This is not a valid linux path" +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." msgstr "" -msgid "This is not a valid url." +msgid "Create a network" msgstr "" -msgid "The VLAN id must be between 1 and 4094." +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" msgstr "" -msgid "This is not a valid ISO file." +msgid "This storage pool is empty." msgstr "" msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" +"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." @@ -261,77 +274,16 @@ msgid "NFS server mount path can not be blank." msgstr "" msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " +"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." +msgid "Invalid NFS mount path." msgstr "" 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 "" - -msgid "bridged" -msgstr "" - -msgid "connected to" -msgstr "" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" - -msgid "Create a network" -msgstr "" - -msgid "Warning" -msgstr "" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" - msgid "The iSCSI target can not be blank." msgstr "" @@ -390,19 +342,19 @@ 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" +msgid "Device path" msgstr "" msgid "iSCSI Server" @@ -495,7 +447,7 @@ msgstr "" msgid "NAT: outbound physical network connection only" msgstr "" -msgid "Bridged: VMs are connected to physical network directly" +msgid "Bridged: Virtual machines are connected to physical network directly" msgstr "" msgid "Destination" @@ -608,3 +560,501 @@ msgstr "" msgid "Storage Pool" msgstr "" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +#, python-format +msgid "Delete is not allowed for %(resource)s" +msgstr "" + +#, python-format +msgid "%(resource)s does not implement update method" +msgstr "" + +#, python-format +msgid "Parameters %(params)s are not allowed to be updated in %(resource)s" +msgstr "" + +#, python-format +msgid "Create is not allowed for %(resource)s" +msgstr "" + +msgid "Unable to parse JSON request" +msgstr "" + +msgid "This API only supports" +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 "" + +msgid "You are not authorized to access Kimchi" +msgstr "" + +#, python-format +msgid "Specify %(item)s to login into Kimchi" +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..adf291a 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-11 15:02-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" @@ -52,11 +52,9 @@ msgid "Virtual Machine Name" msgstr "Nome da máquina virtual" msgid "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." msgstr "" -"O nome usado para identificar a máquina virtual. Se omitido, o nome será " -"escolhido baseado no modelo usado." msgid "Template" msgstr "Modelo" @@ -121,15 +119,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,38 +133,38 @@ msgstr "Entrar" msgid "Logging in..." msgstr "Entrando" -msgid "Invalid URL. Redireced to home page." -msgstr "URL inválida. Redirecionado para a Página Inicial." +msgid "Host" +msgstr "Hospedeiro" -msgid "Failed to start" -msgstr "Erro ao iniciar" +msgid "Guests" +msgstr "Máquinas Virtuais" -msgid "Failed to stop" -msgstr "Erro ao parar" +msgid "Templates" +msgstr "Modelos" -msgid "Failed to reset" -msgstr "Erro ao reiniciar" +msgid "Storage" +msgstr "Storage" -msgid "Failed to delete" -msgstr "Erro ao remover" +msgid "Network" +msgstr "Redes" -msgid "Failed to list guests" -msgstr "Erro ao listar as máquinas virtuais" +msgid "Invalid URL. Redireced to home page." +msgstr "URL inválida. Redirecionado para a Página Inicial." -msgid "Failed to create template" -msgstr "Erro ao criar modelo" +msgid "Failed to get application configuration" +msgstr "Erro ao carregar as configurações da aplicação" -msgid "Create template successfully" -msgstr "Modelo criado com sucesso" +msgid "This is not a valid Linux path" +msgstr "" -msgid "No iso found" -msgstr "Nenhuma ISO encontrada" +msgid "This is not a valid URL." +msgstr "" -msgid "Failed to scan" -msgstr "Erro ao escanear" +msgid "No such data exsit." +msgstr "" -msgid "Failed to list iso distributions" -msgstr "Erro ao listar distribuições ISO" +msgid "options needed." +msgstr "" msgid "Delete Confirmation" msgstr "Confirmação de remoção" @@ -183,6 +172,30 @@ msgstr "Confirmação de remoção" msgid "OK" msgstr "OK" +msgid "Confirm" +msgstr "Confirmar" + +msgid "Warning" +msgstr "Aviso" + +msgid "No iso found" +msgstr "Nenhuma ISO encontrada" + +msgid "This is not a valid ISO file." +msgstr "Esse não é um arquivo ISO válido." + +msgid "Create template successfully" +msgstr "Modelo criado com sucesso" + +msgid "It will take long time. Do you want to continue?" +msgstr "" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" + msgid "Max:" msgstr "Máximo:" @@ -204,8 +217,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,112 +255,17 @@ 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?" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" 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 +276,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 "" + +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 +290,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,20 +372,20 @@ 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" +msgid "Device path" +msgstr "" msgid "iSCSI Server" msgstr "" @@ -531,8 +477,8 @@ msgstr "Isolado: nenhuma conexão física" msgid "NAT: outbound physical network connection only" msgstr "NAT: somente conexão de rede física de saída" -msgid "Bridged: VMs are connected to physical network directly" -msgstr "Bridged: Máquinas virtuais estão conectadas diretamente a rede física" +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" msgid "Destination" msgstr "Destino" @@ -644,3 +590,501 @@ msgstr "CD-ROM" msgid "Storage Pool" msgstr "Nome do Storage Pool" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +#, python-format +msgid "Delete is not allowed for %(resource)s" +msgstr "" + +#, python-format +msgid "%(resource)s does not implement update method" +msgstr "" + +#, python-format +msgid "Parameters %(params)s are not allowed to be updated in %(resource)s" +msgstr "" + +#, python-format +msgid "Create is not allowed for %(resource)s" +msgstr "" + +msgid "Unable to parse JSON request" +msgstr "" + +msgid "This API only supports" +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 "" + +msgid "You are not authorized to access Kimchi" +msgstr "" + +#, python-format +msgid "Specify %(item)s to login into Kimchi" +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..88ef9ed 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-11 15:02-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" @@ -52,9 +52,9 @@ msgid "Virtual Machine Name" msgstr "虚拟机名称" msgid "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." -msgstr "该名称用来唯一标识虚拟机,如果不指定,将会基于模板自动生成一个名称。" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr "" msgid "Template" msgstr "模板" @@ -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,38 +131,38 @@ msgstr "登录" msgid "Logging in..." msgstr "登录中..." -msgid "Invalid URL. Redireced to home page." -msgstr "无效的URL,已重定向到首页" +msgid "Host" +msgstr "主机" -msgid "Failed to start" -msgstr "启动失败" +msgid "Guests" +msgstr "客户机" -msgid "Failed to stop" -msgstr "停止失败" +msgid "Templates" +msgstr "模板" -msgid "Failed to reset" -msgstr "重启失败" +msgid "Storage" +msgstr "存储" -msgid "Failed to delete" -msgstr "删除失败" +msgid "Network" +msgstr "网络" -msgid "Failed to list guests" -msgstr "客户机列表加载失败" +msgid "Invalid URL. Redireced to home page." +msgstr "无效的URL,已重定向到首页" -msgid "Failed to create template" -msgstr "模板创建失败" +msgid "Failed to get application configuration" +msgstr "获取应用配置失败" -msgid "Create template successfully" -msgstr "创建模板成功" +msgid "This is not a valid Linux path" +msgstr "" -msgid "No iso found" -msgstr "没有发现ISO文件" +msgid "This is not a valid URL." +msgstr "" -msgid "Failed to scan" -msgstr "扫描失败" +msgid "No such data exsit." +msgstr "" -msgid "Failed to list iso distributions" -msgstr "加载ISO列表失败" +msgid "options needed." +msgstr "" msgid "Delete Confirmation" msgstr "删除确认" @@ -179,6 +170,30 @@ msgstr "删除确认" msgid "OK" msgstr "确定" +msgid "Confirm" +msgstr "确认" + +msgid "Warning" +msgstr "警告" + +msgid "No iso found" +msgstr "没有发现ISO文件" + +msgid "This is not a valid ISO file." +msgstr "这不是一个有效的ISO文件" + +msgid "Create template successfully" +msgstr "创建模板成功" + +msgid "It will take long time. Do you want to continue?" +msgstr "" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines 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,122 +249,57 @@ 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 "您正在删除虚拟机,本操作将不能恢复,是否继续?" +"This will delete the virtual machine 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 "The VLAN id must be between 1 and 4094." +msgstr "" -msgid "Failed to get application configuration" -msgstr "获取应用配置失败" +msgid "unavailable" +msgstr "无法获取" -msgid "This is not a valid linux path" -msgstr "这不是一个有效的LINUX路径" +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "此操作将中断依赖此网络的虚拟机的网络连接。" -msgid "This is not a valid url." -msgstr "这不是一个有效的URL" +msgid "Create a network" +msgstr "创建一个网络" -msgid "The VLAN id must be between 1 and 4094." +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" msgstr "" -msgid "This is not a valid ISO file." -msgstr "这不是一个有效的ISO文件" +msgid "This storage pool is empty." +msgstr "这个存储池为空" msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" -msgstr "本操作将会永久删除存储池,是否继续?" +"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 "存储池的名字不能为空" +msgstr "" msgid "The storage pool path can not be blank." -msgstr "存储池的路径不能为空" +msgstr "" msgid "NFS server mount path can not be blank." msgstr "NFS服务器挂载路径不能为空" msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " +"Invalid storage pool name. It may only contain letters, numbers, " "underscores, and hyphens." -msgstr "无效的存储池名字,它应该只包括字母,数字,下划线及连接符" - -msgid "This is not a real linux path." -msgstr "这不是一个符合要求的LINUX路径" +msgstr "" -msgid "Invalid nfs mount path." -msgstr "无效的nfs挂载路径" +msgid "Invalid NFS mount path." +msgstr "" 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." -msgstr "此操作将中断依赖此网络的虚拟机的网络连接。" - -msgid "Create a network" -msgstr "创建一个网络" - -msgid "Warning" -msgstr "警告" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "你的磁盘将会格式化,磁盘上的数据会丢失,你确定要继续吗?" - msgid "The iSCSI target can not be blank." msgstr "iSCSI目标不能为空" @@ -408,20 +360,20 @@ 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 "设备路径" +msgid "Device path" +msgstr "" msgid "iSCSI Server" msgstr "iSCSI服务器" @@ -513,8 +465,8 @@ msgstr "隔离: 同物理网络不连通" msgid "NAT: outbound physical network connection only" msgstr "NAT: 从虚拟机到物理网络单向连接" -msgid "Bridged: VMs are connected to physical network directly" -msgstr "桥接: 虚拟机直接接入物理网络" +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr "" msgid "Destination" msgstr "目标设备" @@ -626,3 +578,501 @@ msgstr "光驱" msgid "Storage Pool" msgstr "存储池" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +#, python-format +msgid "Delete is not allowed for %(resource)s" +msgstr "" + +#, python-format +msgid "%(resource)s does not implement update method" +msgstr "" + +#, python-format +msgid "Parameters %(params)s are not allowed to be updated in %(resource)s" +msgstr "" + +#, python-format +msgid "Create is not allowed for %(resource)s" +msgstr "" + +msgid "Unable to parse JSON request" +msgstr "" + +msgid "This API only supports" +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 "" + +msgid "You are not authorized to access Kimchi" +msgstr "" + +#, python-format +msgid "Specify %(item)s to login into Kimchi" +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

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 02/11/2014 03:52 PM, Aline Manera wrote:
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 | 739 +++++++++++++++++++++++++++++++++++++++++++++------------ po/kimchi.pot | 664 ++++++++++++++++++++++++++++++++++++++++++--------- po/pt_BR.po | 738 ++++++++++++++++++++++++++++++++++++++++++++------------ po/zh_CN.po | 726 +++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 2327 insertions(+), 540 deletions(-)
diff --git a/po/en_US.po b/po/en_US.po index 77e0677..5a5327a 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-11 15:02-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" @@ -36,11 +36,9 @@ msgid "Virtual Machine Name" msgstr "Virtual Machine Name"
msgid "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." msgstr "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used."
msgid "Template" msgstr "Template" @@ -105,15 +103,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,38 +115,38 @@ msgstr "Log in" msgid "Logging in..." msgstr "Logging in..."
-msgid "Invalid URL. Redireced to home page." -msgstr "Invalid URL. Redireced to home page." +msgid "Host" +msgstr "Host"
-msgid "Failed to start" -msgstr "Failed to start" +msgid "Guests" +msgstr "Guests"
-msgid "Failed to stop" -msgstr "Failed to stop" +msgid "Templates" +msgstr "Templates"
-msgid "Failed to reset" -msgstr "Failed to reset" +msgid "Storage" +msgstr "Storage"
-msgid "Failed to delete" -msgstr "Failed to delete" +msgid "Network" +msgstr "Network"
-msgid "Failed to list guests" -msgstr "Failed to list guests" +msgid "Invalid URL. Redireced to home page." +msgstr "Invalid URL. Redireced to home page."
-msgid "Failed to create template" -msgstr "Failed to create template" +msgid "Failed to get application configuration" +msgstr "Failed to get application configuration"
-msgid "Create template successfully" -msgstr "Create template successfully" +msgid "This is not a valid Linux path" +msgstr ""
-msgid "No iso found" -msgstr "No iso found" +msgid "This is not a valid URL." +msgstr ""
-msgid "Failed to scan" -msgstr "Failed to scan" +msgid "No such data exsit." +msgstr ""
-msgid "Failed to list iso distributions" -msgstr "Failed to list iso distributions" +msgid "options needed." +msgstr ""
msgid "Delete Confirmation" msgstr "Delete Confirmation" @@ -165,6 +154,30 @@ msgstr "Delete Confirmation" msgid "OK" msgstr "OK"
+msgid "Confirm" +msgstr "Confirm" + +msgid "Warning" +msgstr "Warning" + +msgid "No iso found" +msgstr "No iso found" + +msgid "This is not a valid ISO file." +msgstr "This is not a valid ISO file." + +msgid "Create template successfully" +msgstr "Create template successfully" + +msgid "It will take long time. Do you want to continue?" +msgstr "" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" + msgid "Max:" msgstr "Max:"
@@ -186,8 +199,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,113 +237,17 @@ 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?" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" 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 +258,12 @@ 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 "" + +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 +272,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,20 +357,20 @@ 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" +msgid "Device path" +msgstr ""
msgid "iSCSI Server" msgstr "iSCSI Server" @@ -517,8 +462,8 @@ msgstr "Isolated: no physical network connection" msgid "NAT: outbound physical network connection only" msgstr "NAT: outbound physical network connection only"
-msgid "Bridged: VMs are connected to physical network directly" -msgstr "Bridged: VMs are connected to physical network directly" +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr ""
msgid "Destination" msgstr "Destination" @@ -630,3 +575,501 @@ msgstr "CDROM"
msgid "Storage Pool" msgstr "Storage Pool" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +#, python-format +msgid "Delete is not allowed for %(resource)s" +msgstr "" + +#, python-format +msgid "%(resource)s does not implement update method" +msgstr "" + +#, python-format +msgid "Parameters %(params)s are not allowed to be updated in %(resource)s" +msgstr "" + +#, python-format +msgid "Create is not allowed for %(resource)s" +msgstr "" + +msgid "Unable to parse JSON request" +msgstr "" + +msgid "This API only supports" +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 "" + +msgid "You are not authorized to access Kimchi" +msgstr "" + +#, python-format +msgid "Specify %(item)s to login into Kimchi" +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..a4b3935 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-11 15:02-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" @@ -36,8 +36,8 @@ msgid "Virtual Machine Name" msgstr ""
msgid "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." msgstr ""
msgid "Template" @@ -103,64 +103,79 @@ 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 "Create template successfully" +msgid "Confirm" +msgstr "" + +msgid "Warning" 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 "Create template successfully" msgstr ""
-msgid "Delete Confirmation" +msgid "It will take long time. Do you want to continue?" msgstr ""
-msgid "OK" +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines 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,39 +233,35 @@ 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?" +"This will delete the virtual machine 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?" +msgid "The VLAN id must be between 1 and 4094." msgstr ""
-msgid "Failed to get application configuration" +msgid "unavailable" msgstr ""
-msgid "This is not a valid linux path" +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." msgstr ""
-msgid "This is not a valid url." +msgid "Create a network" msgstr ""
-msgid "The VLAN id must be between 1 and 4094." +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" msgstr ""
-msgid "This is not a valid ISO file." +msgid "This storage pool is empty." msgstr ""
msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" +"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." @@ -261,77 +274,16 @@ msgid "NFS server mount path can not be blank." msgstr ""
msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " +"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." +msgid "Invalid NFS mount path." msgstr ""
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 "" - -msgid "bridged" -msgstr "" - -msgid "connected to" -msgstr "" - -msgid "" -"This action will interrupt network connectivity for any virtual machine that " -"depend on this network." -msgstr "" - -msgid "Create a network" -msgstr "" - -msgid "Warning" -msgstr "" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "" - msgid "The iSCSI target can not be blank." msgstr ""
@@ -390,19 +342,19 @@ 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" +msgid "Device path" msgstr ""
msgid "iSCSI Server" @@ -495,7 +447,7 @@ msgstr "" msgid "NAT: outbound physical network connection only" msgstr ""
-msgid "Bridged: VMs are connected to physical network directly" +msgid "Bridged: Virtual machines are connected to physical network directly" msgstr ""
msgid "Destination" @@ -608,3 +560,501 @@ msgstr ""
msgid "Storage Pool" msgstr "" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +#, python-format +msgid "Delete is not allowed for %(resource)s" +msgstr "" + +#, python-format +msgid "%(resource)s does not implement update method" +msgstr "" + +#, python-format +msgid "Parameters %(params)s are not allowed to be updated in %(resource)s" +msgstr "" + +#, python-format +msgid "Create is not allowed for %(resource)s" +msgstr "" + +msgid "Unable to parse JSON request" +msgstr "" + +msgid "This API only supports" +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 "" + +msgid "You are not authorized to access Kimchi" +msgstr "" + +#, python-format +msgid "Specify %(item)s to login into Kimchi" +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..adf291a 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-11 15:02-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" @@ -52,11 +52,9 @@ msgid "Virtual Machine Name" msgstr "Nome da máquina virtual"
msgid "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." msgstr "" -"O nome usado para identificar a máquina virtual. Se omitido, o nome será " -"escolhido baseado no modelo usado."
msgid "Template" msgstr "Modelo" @@ -121,15 +119,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,38 +133,38 @@ msgstr "Entrar" msgid "Logging in..." msgstr "Entrando"
-msgid "Invalid URL. Redireced to home page." -msgstr "URL inválida. Redirecionado para a Página Inicial." +msgid "Host" +msgstr "Hospedeiro"
-msgid "Failed to start" -msgstr "Erro ao iniciar" +msgid "Guests" +msgstr "Máquinas Virtuais"
-msgid "Failed to stop" -msgstr "Erro ao parar" +msgid "Templates" +msgstr "Modelos"
-msgid "Failed to reset" -msgstr "Erro ao reiniciar" +msgid "Storage" +msgstr "Storage"
-msgid "Failed to delete" -msgstr "Erro ao remover" +msgid "Network" +msgstr "Redes"
-msgid "Failed to list guests" -msgstr "Erro ao listar as máquinas virtuais" +msgid "Invalid URL. Redireced to home page." +msgstr "URL inválida. Redirecionado para a Página Inicial."
-msgid "Failed to create template" -msgstr "Erro ao criar modelo" +msgid "Failed to get application configuration" +msgstr "Erro ao carregar as configurações da aplicação"
-msgid "Create template successfully" -msgstr "Modelo criado com sucesso" +msgid "This is not a valid Linux path" +msgstr ""
-msgid "No iso found" -msgstr "Nenhuma ISO encontrada" +msgid "This is not a valid URL." +msgstr ""
-msgid "Failed to scan" -msgstr "Erro ao escanear" +msgid "No such data exsit." +msgstr ""
-msgid "Failed to list iso distributions" -msgstr "Erro ao listar distribuições ISO" +msgid "options needed." +msgstr ""
msgid "Delete Confirmation" msgstr "Confirmação de remoção" @@ -183,6 +172,30 @@ msgstr "Confirmação de remoção" msgid "OK" msgstr "OK"
+msgid "Confirm" +msgstr "Confirmar" + +msgid "Warning" +msgstr "Aviso" + +msgid "No iso found" +msgstr "Nenhuma ISO encontrada" + +msgid "This is not a valid ISO file." +msgstr "Esse não é um arquivo ISO válido." + +msgid "Create template successfully" +msgstr "Modelo criado com sucesso" + +msgid "It will take long time. Do you want to continue?" +msgstr "" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines running!" +msgstr "" + msgid "Max:" msgstr "Máximo:"
@@ -204,8 +217,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,112 +255,17 @@ 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?" +"This will delete the virtual machine and its virtual disks. This operation " +"cannot be undone. Would you like to continue?" 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 +276,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 "" + +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 +290,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,20 +372,20 @@ 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" +msgid "Device path" +msgstr ""
msgid "iSCSI Server" msgstr "" @@ -531,8 +477,8 @@ msgstr "Isolado: nenhuma conexão física" msgid "NAT: outbound physical network connection only" msgstr "NAT: somente conexão de rede física de saída"
-msgid "Bridged: VMs are connected to physical network directly" -msgstr "Bridged: Máquinas virtuais estão conectadas diretamente a rede física" +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr ""
msgid "Destination" msgstr "Destino" @@ -644,3 +590,501 @@ msgstr "CD-ROM"
msgid "Storage Pool" msgstr "Nome do Storage Pool" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +#, python-format +msgid "Delete is not allowed for %(resource)s" +msgstr "" + +#, python-format +msgid "%(resource)s does not implement update method" +msgstr "" + +#, python-format +msgid "Parameters %(params)s are not allowed to be updated in %(resource)s" +msgstr "" + +#, python-format +msgid "Create is not allowed for %(resource)s" +msgstr "" + +msgid "Unable to parse JSON request" +msgstr "" + +msgid "This API only supports" +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 "" + +msgid "You are not authorized to access Kimchi" +msgstr "" + +#, python-format +msgid "Specify %(item)s to login into Kimchi" +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..88ef9ed 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-11 15:02-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" @@ -52,9 +52,9 @@ msgid "Virtual Machine Name" msgstr "虚拟机名称"
msgid "" -"The name used to identify the VM. If omitted, a name will be chosen based on " -"the template used." -msgstr "该名称用来唯一标识虚拟机,如果不指定,将会基于模板自动生成一个名称。" +"The name used to identify the virtual machine. If omitted, a name will be " +"chosen based on the template used." +msgstr ""
msgid "Template" msgstr "模板" @@ -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,38 +131,38 @@ msgstr "登录" msgid "Logging in..." msgstr "登录中..."
-msgid "Invalid URL. Redireced to home page." -msgstr "无效的URL,已重定向到首页" +msgid "Host" +msgstr "主机"
-msgid "Failed to start" -msgstr "启动失败" +msgid "Guests" +msgstr "客户机"
-msgid "Failed to stop" -msgstr "停止失败" +msgid "Templates" +msgstr "模板"
-msgid "Failed to reset" -msgstr "重启失败" +msgid "Storage" +msgstr "存储"
-msgid "Failed to delete" -msgstr "删除失败" +msgid "Network" +msgstr "网络"
-msgid "Failed to list guests" -msgstr "客户机列表加载失败" +msgid "Invalid URL. Redireced to home page." +msgstr "无效的URL,已重定向到首页"
-msgid "Failed to create template" -msgstr "模板创建失败" +msgid "Failed to get application configuration" +msgstr "获取应用配置失败"
-msgid "Create template successfully" -msgstr "创建模板成功" +msgid "This is not a valid Linux path" +msgstr ""
-msgid "No iso found" -msgstr "没有发现ISO文件" +msgid "This is not a valid URL." +msgstr ""
-msgid "Failed to scan" -msgstr "扫描失败" +msgid "No such data exsit." +msgstr ""
-msgid "Failed to list iso distributions" -msgstr "加载ISO列表失败" +msgid "options needed." +msgstr ""
msgid "Delete Confirmation" msgstr "删除确认" @@ -179,6 +170,30 @@ msgstr "删除确认" msgid "OK" msgstr "确定"
+msgid "Confirm" +msgstr "确认" + +msgid "Warning" +msgstr "警告" + +msgid "No iso found" +msgstr "没有发现ISO文件" + +msgid "This is not a valid ISO file." +msgstr "这不是一个有效的ISO文件" + +msgid "Create template successfully" +msgstr "创建模板成功" + +msgid "It will take long time. Do you want to continue?" +msgstr "" + +msgid "This will permanently delete the template. Would you like to continue?" +msgstr "" + +msgid "Unable to shut down system as there are some virtual machines 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,122 +249,57 @@ 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 "您正在删除虚拟机,本操作将不能恢复,是否继续?" +"This will delete the virtual machine 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 "The VLAN id must be between 1 and 4094." +msgstr ""
-msgid "Failed to get application configuration" -msgstr "获取应用配置失败" +msgid "unavailable" +msgstr "无法获取"
-msgid "This is not a valid linux path" -msgstr "这不是一个有效的LINUX路径" +msgid "" +"This action will interrupt network connectivity for any virtual machine that " +"depend on this network." +msgstr "此操作将中断依赖此网络的虚拟机的网络连接。"
-msgid "This is not a valid url." -msgstr "这不是一个有效的URL" +msgid "Create a network" +msgstr "创建一个网络"
-msgid "The VLAN id must be between 1 and 4094." +msgid "" +"This will permanently delete the storage pool. Would you like to continue?" msgstr ""
-msgid "This is not a valid ISO file." -msgstr "这不是一个有效的ISO文件" +msgid "This storage pool is empty." +msgstr "这个存储池为空"
msgid "" -"This will permanently delete the Storage Pool. Would you like to continue?" -msgstr "本操作将会永久删除存储池,是否继续?" +"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 "存储池的名字不能为空" +msgstr ""
msgid "The storage pool path can not be blank." -msgstr "存储池的路径不能为空" +msgstr ""
msgid "NFS server mount path can not be blank." msgstr "NFS服务器挂载路径不能为空"
msgid "" -"Invalid Storage Pool name. It may only contain letters, numbers, " +"Invalid storage pool name. It may only contain letters, numbers, " "underscores, and hyphens." -msgstr "无效的存储池名字,它应该只包括字母,数字,下划线及连接符" - -msgid "This is not a real linux path." -msgstr "这不是一个符合要求的LINUX路径" +msgstr ""
-msgid "Invalid nfs mount path." -msgstr "无效的nfs挂载路径" +msgid "Invalid NFS mount path." +msgstr ""
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." -msgstr "此操作将中断依赖此网络的虚拟机的网络连接。" - -msgid "Create a network" -msgstr "创建一个网络" - -msgid "Warning" -msgstr "警告" - -msgid "" -"It will format your disk and you will loose any data in there, are you sure " -"to continue? " -msgstr "你的磁盘将会格式化,磁盘上的数据会丢失,你确定要继续吗?" - msgid "The iSCSI target can not be blank." msgstr "iSCSI目标不能为空"
@@ -408,20 +360,20 @@ 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 "设备路径" +msgid "Device path" +msgstr ""
msgid "iSCSI Server" msgstr "iSCSI服务器" @@ -513,8 +465,8 @@ msgstr "隔离: 同物理网络不连通" msgid "NAT: outbound physical network connection only" msgstr "NAT: 从虚拟机到物理网络单向连接"
-msgid "Bridged: VMs are connected to physical network directly" -msgstr "桥接: 虚拟机直接接入物理网络" +msgid "Bridged: Virtual machines are connected to physical network directly" +msgstr ""
msgid "Destination" msgstr "目标设备" @@ -626,3 +578,501 @@ msgstr "光驱"
msgid "Storage Pool" msgstr "存储池" + +#, python-format +msgid "Unkown parameter specified %(value)s" +msgstr "" + +#, python-format +msgid "Delete is not allowed for %(resource)s" +msgstr "" + +#, python-format +msgid "%(resource)s does not implement update method" +msgstr "" + +#, python-format +msgid "Parameters %(params)s are not allowed to be updated in %(resource)s" +msgstr "" + +#, python-format +msgid "Create is not allowed for %(resource)s" +msgstr "" + +msgid "Unable to parse JSON request" +msgstr "" + +msgid "This API only supports" +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 "" + +msgid "You are not authorized to access Kimchi" +msgstr "" + +#, python-format +msgid "Specify %(item)s to login into Kimchi" +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 ""
participants (2)
-
Aline Manera
-
Daniel H Barboza