[Kimchi-devel] [PATCH 5/8] refactor exception: Update all exceptions

Daniel H Barboza danielhb at linux.vnet.ibm.com
Wed Feb 12 11:32:20 UTC 2014


Reviewed-by: Daniel Barboza <danielhb at linux.vnet.ibm.com>

On 02/11/2014 03:52 PM, Aline Manera wrote:
> From: Aline Manera <alinefm at 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 at 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




More information about the Kimchi-devel mailing list