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