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

Leonardo Augusto Guimarães Garcia lagarcia at linux.vnet.ibm.com
Tue Feb 11 03:10:28 UTC 2014


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

Best regards,

Leonardo Garcia




More information about the Kimchi-devel mailing list