From dfde363aa63ad3e7967da49f4ab599399b89e7f8 Mon Sep 17 00:00:00 2001 From: Alejandro Sirgo Rica Date: Tue, 2 Apr 2024 12:51:34 +0200 Subject: src: log backtrace in unhandled error cases Log an error message in known error cases and log a backtrace otherwise. Define a new error type OgError to be used in all the 'raise' blocks to define the error message to log. The exception propagates until it reaches send_internal_server_error() where the exception type is checked. If the type is OgError we log the exception message. Logs the backtrace for other types. The initial error implementation printed a backtrace everytime an error ocurred. The next iteration changed it to only print a backtrace in a very particular case but ended up omiting too much information such as syntax errors or unknown error context. The actual implementation only logs the cases we already cover in the codebase and logs a bracktrace in the others, enabling a better debugging experience. --- src/live/ogOperations.py | 49 +++++++++++++++++++++++---------------------- src/live/parttypes.py | 9 +++++---- src/log.py | 6 +++++- src/ogClient.py | 5 +++-- src/ogRest.py | 9 +++++---- src/utils/bios.py | 5 +++-- src/utils/boot.py | 19 +++++++++--------- src/utils/disk.py | 11 +++++----- src/utils/fs.py | 13 ++++++------ src/utils/hw_inventory.py | 11 +++++----- src/utils/legacy.py | 15 +++++++------- src/utils/tiptorrent.py | 13 ++++++------ src/utils/uefi.py | 19 +++++++++--------- src/virtual/ogOperations.py | 15 +++++++------- 14 files changed, 108 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/live/ogOperations.py b/src/live/ogOperations.py index cfe05f6..0c08459 100644 --- a/src/live/ogOperations.py +++ b/src/live/ogOperations.py @@ -35,6 +35,7 @@ from src.utils.uefi import * from src.utils.boot import * from src.utils.sw_inventory import get_package_set from src.utils.hw_inventory import get_hardware_inventory, legacy_list_hardware_inventory +from src.log import OgError OG_SHELL = '/bin/bash' @@ -52,7 +53,7 @@ class OgLiveOperations: proc = subprocess.call(["pkill", "-9", "browser"]) proc = subprocess.Popen(["browser", "-qws", url]) except Exception as e: - raise RuntimeError('Cannot restart browser') from e + raise OgError('Cannot restart browser') from e def _refresh_payload_disk(self, cxt, part_setup, num_disk): part_setup['disk'] = str(num_disk) @@ -119,7 +120,7 @@ class OgLiveOperations: def _write_md5_file(self, path): if not os.path.exists(path): - raise ValueError(f'Invalid image path {path} when computing md5 checksum') + raise OgError(f'Invalid image path {path} when computing md5 checksum') filename = path + ".full.sum" dig = self._compute_md5(path) try: @@ -144,12 +145,12 @@ class OgLiveOperations: r = shutil.copy(src, dst) tip_write_csum(image_name) except Exception as e: - raise RuntimeError(f'Error copying image {image_name} to cache. Reported: {e}') from e + raise OgError(f'Error copying image {image_name} to cache. Reported: {e}') from e def _restore_image_unicast(self, repo, name, devpath, cache=False): if ogChangeRepo(repo, smb_user=self._smb_user, smb_pass=self._smb_pass) != 0: self._restartBrowser(self._url) - raise ValueError(f'Cannot change repository to {repo}') + raise OgError(f'Cannot change repository to {repo}') logging.debug(f'restore_image_unicast: name => {name}') if cache: image_path = f'/opt/opengnsys/cache/opt/opengnsys/images/{name}.img' @@ -162,7 +163,7 @@ class OgLiveOperations: def _restore_image_tiptorrent(self, repo, name, devpath): if not os.path.exists(OG_CACHE_PATH): - raise RuntimeError('No cache partition is mounted') + raise OgError('No cache partition is mounted') image_path = f'/opt/opengnsys/cache/opt/opengnsys/images/{name}.img' try: @@ -172,11 +173,11 @@ class OgLiveOperations: except: self._restartBrowser(self._url) if (not os.path.exists(image_path)): - raise RuntimeError(f'Image file {image_path} does not exist') + raise OgError(f'Image file {image_path} does not exist') if (not tip_check_csum(repo, name)): - raise RuntimeError(f'checksum file {name}.full.sum is missing in repository {repo}') + raise OgError(f'checksum file {name}.full.sum is missing in repository {repo}') - raise RuntimeError(f'Unexpected error when restoring image file {image_path}') + raise OgError(f'Unexpected error when restoring image file {image_path}') self._restore_image(image_path, devpath) @@ -188,7 +189,7 @@ class OgLiveOperations: cmd_pc = shlex.split(f'partclone.restore -d0 -C -I -o {devpath}') if not os.path.exists(image_path): - raise RuntimeError(f'Image not found at {image_path} during image restore') + raise OgError(f'Image not found at {image_path} during image restore') with open('/tmp/command.log', 'wb', 0) as logfile: proc_lzop = subprocess.Popen(cmd_lzop, @@ -245,7 +246,7 @@ class OgLiveOperations: executable=OG_SHELL) (output, error) = ogRest.proc.communicate() except Exception as e: - raise RuntimeError(f'Error when running "shell run" subprocess: {e}') from e + raise OgError(f'Error when running "shell run" subprocess: {e}') from e if ogRest.proc.returncode != 0: logging.warn('Non zero exit code when running: %s', ' '.join(cmds)) @@ -269,9 +270,9 @@ class OgLiveOperations: partdev = get_partition_device(int(disk), int(partition)) mountpoint = partdev.replace('dev', 'mnt') if not mount_mkdir(partdev, mountpoint): - raise RuntimeError(f'Error mounting {partdev} at {mountpoint}') + raise OgError(f'Error mounting {partdev} at {mountpoint}') if not os.path.ismount(mountpoint): - raise RuntimeError(f'Invalid mountpoint {mountpoint} for software inventory') + raise OgError(f'Invalid mountpoint {mountpoint} for software inventory') self._restartBrowser(self._url_log) pkgset = get_package_set(mountpoint) @@ -294,7 +295,7 @@ class OgLiveOperations: try: inventory = get_hardware_inventory() except Exception as e: - raise RuntimeError(f'Error while running hardware inventory. {e}') from e + raise OgError(f'Error while running hardware inventory. {e}') from e finally: self._restartBrowser(self._url) @@ -321,7 +322,7 @@ class OgLiveOperations: elif table_type == 'GPT': cxt.create_disklabel('gpt') else: - raise ValueError(f'Unsupported partition scheme {table_type}, only MSDOS and GPT are supported') + raise OgError(f'Unsupported partition scheme {table_type}, only MSDOS and GPT are supported') logging.info(f'Setting up partition layout to {table_type}') @@ -415,7 +416,7 @@ class OgLiveOperations: if ogChangeRepo(repo, smb_user=self._smb_user, smb_pass=self._smb_pass) != 0: self._restartBrowser(self._url) - raise RuntimeError(f'Cannot change image repository to {repo}') + raise OgError(f'Cannot change image repository to {repo}') if ogRest.terminated: return @@ -431,25 +432,25 @@ class OgLiveOperations: if pa is None: self._restartBrowser(self._url) - raise RuntimeError(f'Target partition /dev/{diskname} not found') + raise OgError(f'Target partition /dev/{diskname} not found') padev = cxt.partition_to_string(pa, fdisk.FDISK_FIELD_DEVICE) fstype = cxt.partition_to_string(pa, fdisk.FDISK_FIELD_FSTYPE) if not fstype: - raise RuntimeError(f'No filesystem detected in {padev}. Aborting image creation') + raise OgError(f'No filesystem detected in {padev}. Aborting image creation') if change_access(user=self._smb_user, pwd=self._smb_pass) == -1: - raise RuntimeError('remount of /opt/opengnsys/images has failed') + raise OgError('remount of /opt/opengnsys/images has failed') if os.access(f'/opt/opengnsys/images', os.R_OK | os.W_OK) == False: - raise RuntimeError('Cannot access /opt/opengnsys/images in read and write mode, check permissions') + raise OgError('Cannot access /opt/opengnsys/images in read and write mode, check permissions') if os.access(f'{image_path}', os.R_OK) == True: logging.info(f'image file {image_path} already exists, updating.') copy_windows_efi_bootloader(disk, partition) if ogReduceFs(disk, partition) == -1: - raise ValueError(f'Failed to shrink {fstype} filesystem in {padev}') + raise OgError(f'Failed to shrink {fstype} filesystem in {padev}') cmd1 = shlex.split(f'partclone.{fstype} -I -C --clone -s {padev} -O -') cmd2 = shlex.split(f'lzop -1 -fo {image_path}') @@ -469,7 +470,7 @@ class OgLiveOperations: try: retdata = p2.communicate() except OSError as e: - raise OSError(f'Unexpected error when running partclone and lzop commands: {e}') from e + raise OgError(f'Unexpected error when running partclone and lzop commands: {e}') from e finally: logfile.close() p2.terminate() @@ -481,7 +482,7 @@ class OgLiveOperations: ogExtendFs(disk, partition) if os.access(f'{image_path}', os.R_OK) == False: - raise RuntimeError(f'Cannot access partclone image file {image_path}') + raise OgError(f'Cannot access partclone image file {image_path}') image_info = ogGetImageInfo(image_path) except Exception as e: @@ -492,7 +493,7 @@ class OgLiveOperations: shutil.move(f'{image_path}.ant', image_path) self._restartBrowser(self._url) - raise RuntimeError(f'Failed to create image for {fstype} filesystem in device {padev}: {e}') from e + raise OgError(f'Failed to create image for {fstype} filesystem in device {padev}: {e}') from e try: st = os.stat(image_path) @@ -510,7 +511,7 @@ class OgLiveOperations: image_info.mtime = mtime if self._write_md5_file(f'/opt/opengnsys/images/{name}.img') == -1: - raise ValueError(f'Cannot write {name}.full.sum file') + raise OgError(f'Cannot write {name}.full.sum file') self._restartBrowser(self._url) diff --git a/src/live/parttypes.py b/src/live/parttypes.py index b4c1793..d8db8f6 100644 --- a/src/live/parttypes.py +++ b/src/live/parttypes.py @@ -7,6 +7,7 @@ # (at your option) any later version. import fdisk +from src.log import OgError GPT_PARTTYPES = { 'LINUX-SWAP': '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F', @@ -43,15 +44,15 @@ def get_gpt_parttype(cxt, ptype_str): def get_parttype(cxt, ptype_str): if not cxt: - raise RuntimeError('No libfdisk context') + raise OgError('No libfdisk context') if not cxt.label or cxt.label.name not in ['dos', 'gpt']: - raise RuntimeError('Unknown libfdisk label') + raise OgError('Unknown libfdisk label') if type(ptype_str) != str: - raise RuntimeError('Invalid partition type') + raise OgError('Invalid partition type') if cxt.label.name == 'dos': return get_dos_parttype(cxt, ptype_str) elif cxt.label.name == 'gpt': return get_gpt_parttype(cxt, ptype_str) else: - raise RuntimeError(f'Invalid partition label \'{cxt.label.name}\'') + raise OgError(f'Invalid partition label \'{cxt.label.name}\'') diff --git a/src/log.py b/src/log.py index 0d86a16..9478bb7 100644 --- a/src/log.py +++ b/src/log.py @@ -11,6 +11,10 @@ import logging.config import os +class OgError(Exception): + pass + + def _default_logging_linux(): from src.utils.net import getifaddr logconfig = { @@ -125,7 +129,7 @@ def configure_logging(mode, level): elif mode == 'live': logconfig = _default_logging_live() else: - raise ValueError(f'Logging mode {mode} not supported') + raise OgError(f'Logging mode {mode} not supported') logconfig['loggers']['']['level'] = level diff --git a/src/ogClient.py b/src/ogClient.py index abacc12..c30070c 100644 --- a/src/ogClient.py +++ b/src/ogClient.py @@ -16,6 +16,7 @@ from io import StringIO from src.restRequest import * from src.ogRest import * +from src.log import OgError from enum import Enum class State(Enum): @@ -31,7 +32,7 @@ class ogClient: self.mode = self.CONFIG['opengnsys']['mode'] if self.mode not in {'virtual', 'live', 'linux', 'windows'}: - raise ValueError(f'Invalid ogClient mode: {self.mode}.') + raise OgError(f'Invalid ogClient mode: {self.mode}.') if self.mode in {'linux', 'windows'}: self.event_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.event_sock.setblocking(0) @@ -190,4 +191,4 @@ class ogClient: message = event_sock.recv(4096).decode('utf-8').rstrip() self.send_event_hint(message) else: - raise ValueError(f'Invalid ogClient run state: {str(state)}.') + raise OgError(f'Invalid ogClient run state: {str(state)}.') diff --git a/src/ogRest.py b/src/ogRest.py index c7bdcdb..5d6c746 100644 --- a/src/ogRest.py +++ b/src/ogRest.py @@ -19,6 +19,7 @@ import logging from logging.handlers import SysLogHandler from src.restRequest import * +from src.log import OgError class ThreadState(Enum): @@ -263,13 +264,13 @@ class ogRest(): from src.windows.ogOperations import OgWindowsOperations self.operations = OgWindowsOperations() else: - raise ValueError(f'Ogrest mode \'{self.mode}\'not supported') + raise OgError(f'Ogrest mode \'{self.mode}\'not supported') def send_internal_server_error(self, client, exc=None): - if isinstance(exc, AssertionError): - logging.exception(exc) - else: + if isinstance(exc, OgError): logging.error(exc) + else: + logging.exception(exc) response = restResponse(ogResponses.INTERNAL_ERR, seq=client.seq) client.send(response.get()) self.state = ThreadState.IDLE diff --git a/src/utils/bios.py b/src/utils/bios.py index 1c16633..9c62b38 100644 --- a/src/utils/bios.py +++ b/src/utils/bios.py @@ -8,6 +8,7 @@ import logging import os +from src.log import OgError def get_grub_boot_params(mountpoint, device): @@ -35,7 +36,7 @@ def get_vmlinuz_path(mountpoint): target_file = file if not target_file: - raise FileNotFoundError(f'vmlinuz not found in {initrd_dir}') + raise OgError(f'vmlinuz not found in {initrd_dir}') return os.path.join(linuz_dir, target_file) @@ -48,6 +49,6 @@ def get_initrd_path(mountpoint): target_file = file if not target_file: - raise FileNotFoundError(f'initrd not found in {initrd_dir}') + raise OgError(f'initrd not found in {initrd_dir}') return os.path.join(initrd_dir, target_file) diff --git a/src/utils/boot.py b/src/utils/boot.py index 9ce5238..6ee7450 100644 --- a/src/utils/boot.py +++ b/src/utils/boot.py @@ -17,13 +17,14 @@ from src.utils.disk import get_partition_device, get_efi_partition from src.utils.bios import * from src.utils.uefi import * from src.utils.fs import * +from src.log import OgError def _boot_bios_linux(disk, part, mountpoint): logging.info(f'Booting Linux system') if not get_linux_distro_id(mountpoint) == 'ubuntu': - raise NotImplementedError(f'{os_probe(mountpoint)} detected, only Ubuntu is supported for legacy BIOS boot') + raise OgError(f'{os_probe(mountpoint)} detected, only Ubuntu is supported for legacy BIOS boot') kernel_path = get_vmlinuz_path(mountpoint) initrd_path = get_initrd_path(mountpoint) @@ -39,7 +40,7 @@ def _boot_bios_linux(disk, part, mountpoint): subprocess.run(shlex.split(kexec_cmd), check=True, text=True) subprocess.run(shlex.split(kexec_reboot_cmd), check=True, text=True) except OSError as e: - raise OSError(f'Error processing kexec: {e}') from e + raise OgError(f'Error processing kexec: {e}') from e def _boot_bios_windows(disk, part, mountpoint): logging.info(f'Booting Windows system') @@ -52,7 +53,7 @@ def _boot_bios_windows(disk, part, mountpoint): with open(f'{mountpoint}/ogboot.secondboot', 'w') as f: f.write('\0' * (3072)) except OSError as e: - raise OSError(f'Could not create ogboot files in Windows partition: {e}') from e + raise OgError(f'Could not create ogboot files in Windows partition: {e}') from e def _boot_uefi_windows(disk, part, mountpoint): logging.info(f'Booting windows system') @@ -60,7 +61,7 @@ def _boot_uefi_windows(disk, part, mountpoint): esp, esp_disk, esp_part_number = get_efi_partition(disk, enforce_gpt=True) esp_mountpoint = esp.replace('dev', 'mnt') if not mount_mkdir(esp, esp_mountpoint): - raise RuntimeError(f'Unable to mount detected EFI System Partition at {esp} into {esp_mountpoint}') + raise OgError(f'Unable to mount detected EFI System Partition at {esp} into {esp_mountpoint}') loader_paths = [f'{esp_mountpoint}/EFI/{bootlabel}/Boot/bootmgfw.efi', f'{esp_mountpoint}/EFI/Microsoft/Boot/bootmgfw.efi'] @@ -71,7 +72,7 @@ def _boot_uefi_windows(disk, part, mountpoint): logging.info(f'Found bootloader at ESP partition: {loader}') break else: - raise RuntimeError(f'Unable to locate Windows EFI bootloader bootmgfw.efi') + raise OgError(f'Unable to locate Windows EFI bootloader bootmgfw.efi') efibootmgr_delete_bootentry(bootlabel) efibootmgr_create_bootentry(esp_disk, esp_part_number, loader, bootlabel) @@ -85,7 +86,7 @@ def _boot_uefi_linux(disk, part, mountpoint): esp, esp_disk, esp_part_number = get_efi_partition(disk, enforce_gpt=False) esp_mountpoint = esp.replace('dev', 'mnt') if not mount_mkdir(esp, esp_mountpoint): - raise RuntimeError(f'Unable to mount detected EFI System Partition at {esp} into {esp_mountpoint}') + raise OgError(f'Unable to mount detected EFI System Partition at {esp} into {esp_mountpoint}') loader_paths = [f'{esp_mountpoint}/EFI/{bootlabel}/Boot/shimx64.efi', f'{esp_mountpoint}/EFI/ubuntu/shimx64.efi'] @@ -96,7 +97,7 @@ def _boot_uefi_linux(disk, part, mountpoint): logging.info(f'Found bootloader at ESP partition: {loader}') break else: - raise RuntimeError(f'Unable to locate Linux EFI bootloader shimx64.efi') + raise OgError(f'Unable to locate Linux EFI bootloader shimx64.efi') efibootmgr_delete_bootentry(bootlabel) efibootmgr_create_bootentry(esp_disk, esp_part_number, loader, bootlabel) @@ -109,7 +110,7 @@ def boot_os_at(disk, part): device = get_partition_device(disk, part) mountpoint = device.replace('dev', 'mnt') if not mount_mkdir(device, mountpoint): - raise RuntimeError(f'Cannot probe OS family. Unable to mount {device} into {mountpoint}') + raise OgError(f'Cannot probe OS family. Unable to mount {device} into {mountpoint}') is_uefi = is_uefi_supported() if is_uefi: @@ -130,6 +131,6 @@ def boot_os_at(disk, part): elif not is_uefi and os_family == OSFamily.LINUX: _boot_bios_linux(disk, part, mountpoint) else: - raise RuntimeError(f'Unknown OS family {os_family}') + raise OgError(f'Unknown OS family {os_family}') finally: umount(mountpoint) diff --git a/src/utils/disk.py b/src/utils/disk.py index 323994c..a44153d 100644 --- a/src/utils/disk.py +++ b/src/utils/disk.py @@ -8,6 +8,7 @@ import os import logging +from src.log import OgError import fdisk @@ -29,7 +30,7 @@ def get_partition_device(disknum, partnum): """ disk_index = disknum - 1 if disk_index < 0 or disk_index >= len(get_disks()): - raise ValueError(f'Invalid disk number {disknum}, {len(get_disks())} disks available.') + raise OgError(f'Invalid disk number {disknum}, {len(get_disks())} disks available.') disk = get_disks()[disk_index] cxt = fdisk.Context(f'/dev/{disk}') @@ -38,7 +39,7 @@ def get_partition_device(disknum, partnum): if pa.partno == partnum - 1: return cxt.partition_to_string(pa, fdisk.FDISK_FIELD_DEVICE) - raise ValueError(f'No such partition with disk index {disknum} and partition index {partnum}') + raise OgError(f'No such partition with disk index {disknum} and partition index {partnum}') def get_efi_partition(disknum, enforce_gpt): @@ -55,16 +56,16 @@ def get_efi_partition(disknum, enforce_gpt): """ disk_index = disknum - 1 if disk_index < 0 or disk_index >= len(get_disks()): - raise ValueError(f'Invalid disk number {disknum} when trying to find ESP, {len(get_disks())} disks available.') + raise OgError(f'Invalid disk number {disknum} when trying to find ESP, {len(get_disks())} disks available.') disk = get_disks()[disk_index] cxt = fdisk.Context(f'/dev/{disk}') if enforce_gpt and cxt.label == fdisk.FDISK_DISKLABEL_DOS: - raise RuntimeError(f'Windows EFI System requires GPT partition scheme, but /dev/{disk} has DOS partition scheme') + raise OgError(f'Windows EFI System requires GPT partition scheme, but /dev/{disk} has DOS partition scheme') for pa in cxt.partitions: logging.info(f'Checking partition "{pa.type.name}"...') if pa.type.name == 'EFI System': return cxt.partition_to_string(pa, fdisk.FDISK_FIELD_DEVICE), f'/dev/{disk}', pa.partno + 1 - raise RuntimeError(f'Cannot find "EFI System" partition at /dev/{disk}') + raise OgError(f'Cannot find "EFI System" partition at /dev/{disk}') diff --git a/src/utils/fs.py b/src/utils/fs.py index 7e1d115..83d8d47 100644 --- a/src/utils/fs.py +++ b/src/utils/fs.py @@ -10,6 +10,7 @@ import logging import os import subprocess import shlex +from src.log import OgError from subprocess import DEVNULL, PIPE, STDOUT @@ -148,12 +149,12 @@ def mkfs(fs, disk, partition, label=None): } if fs not in fsdict: - raise ValueError(f'mkfs failed, unsupported target filesystem {fs}') + raise OgError(f'mkfs failed, unsupported target filesystem {fs}') try: partdev = get_partition_device(disk, partition) except ValueError as e: - raise ValueError(f'mkfs aborted: {e}') from e + raise OgError(f'mkfs aborted: {e}') from e fsdict[fs](partdev, label) @@ -249,11 +250,11 @@ def _reduce_ntfsresize(partdev): data_split = output_data.split(pattern) # If we fail to match pattern in the split then data_split will contain [output_data] if len(data_split) == 1: - raise ValueError(f'nfsresize: failed to find: {pattern}') + raise OgError(f'nfsresize: failed to find: {pattern}') value_str = data_split[1].split(' ')[0] if not value_str.isdigit() or value_str.startswith('-'): - raise ValueError(f'nfsresize: failed to parse numeric value at {pattern}') + raise OgError(f'nfsresize: failed to parse numeric value at {pattern}') return int(value_str) try: @@ -307,11 +308,11 @@ def _extend_resize2fs(partdev): cmd = shlex.split(f'resize2fs -f {partdev}') proc = subprocess.run(cmd) if proc.returncode != 0: - raise RuntimeError(f'Error growing ext4 filesystem at {partdev}') + raise OgError(f'Error growing ext4 filesystem at {partdev}') def _extend_ntfsresize(partdev): cmd = shlex.split(f'ntfsresize -f {partdev}') proc = subprocess.run(cmd, input=b'y') if proc.returncode != 0: - raise RuntimeError(f'Error growing ntfs filesystem at {partdev}') + raise OgError(f'Error growing ntfs filesystem at {partdev}') diff --git a/src/utils/hw_inventory.py b/src/utils/hw_inventory.py index c534101..7341dac 100644 --- a/src/utils/hw_inventory.py +++ b/src/utils/hw_inventory.py @@ -10,6 +10,7 @@ import json import os.path import shlex import subprocess +from src.log import OgError from collections import namedtuple from enum import Enum, auto @@ -55,16 +56,16 @@ class HardwareInventory(): def add_element(self, elem): if elem.type not in HardwareType: - raise ValueError(f'Unsupported hardware type, received {elem.type}') + raise OgError(f'Unsupported hardware type, received {elem.type}') if not elem.name: - raise ValueError('Empty hardware element name') + raise OgError('Empty hardware element name') self.elements.append(elem) def _bytes_to_human(size): suffixes = ['B', 'MiB', 'GiB', 'TiB'] if type(size) is not int: - raise TypeError(f'Invalid type in _bytes_to_human, got: {size} {type(size)}') + raise OgError(f'Invalid type in _bytes_to_human, got: {size} {type(size)}') for exponent, suffix in enumerate(suffixes, start=1): conv = size / (1024**exponent) if conv < 1024: @@ -250,7 +251,7 @@ def legacy_hardware_element(element): represented as "vga=Foo" """ if type(element) is not HardwareElement: - raise TypeError('Invalid hardware element type') + raise OgError('Invalid hardware element type') elif element.type is HardwareType.MULTIMEDIA: nemonic = 'mul' elif element.type is HardwareType.BOOTMODE: @@ -297,7 +298,7 @@ def get_hardware_inventory(): if type(j) is list: root = j[0] if type(root) is not dict: - raise ValueError('Invalid lshw json output') + raise OgError('Invalid lshw json output') inventory = HardwareInventory() _fill_computer_model(inventory, root) diff --git a/src/utils/legacy.py b/src/utils/legacy.py index e740450..cdc79c9 100644 --- a/src/utils/legacy.py +++ b/src/utils/legacy.py @@ -16,6 +16,7 @@ import shutil from subprocess import PIPE, DEVNULL, STDOUT, CalledProcessError from src.utils.fs import umount +from src.log import OgError class ImageInfo: @@ -75,9 +76,9 @@ def image_info_from_partclone(partclone_output): fill_imageinfo(line, image_info) if not image_info.datasize: - raise ValueError("Missing device size from partclone.info output") + raise OgError("Missing device size from partclone.info output") elif not image_info.filesystem: - raise ValueError("Missing filesystem from partclone.info output") + raise OgError("Missing filesystem from partclone.info output") return image_info @@ -100,7 +101,7 @@ def run_lzop_partcloneinfo(image_path): p2_out, p2_err = p2.communicate() if p2.returncode != 0: - raise ValueError(f'Unable to process image {image_path}') + raise OgError(f'Unable to process image {image_path}') return p2_out @@ -174,7 +175,7 @@ def ogChangeRepo(ip, smb_user='opengnsys', smb_pass='og'): try: ipaddr = ipaddress.ip_address(ip) except ValueError as e: - raise ValueError(f'Invalid IP address {ip} received') + raise OgError(f'Invalid IP address {ip} received') from e mounted = False with open('/etc/mtab') as f: @@ -209,7 +210,7 @@ def restoreImageCustom(repo_ip, image_name, disk, partition, method): """ """ if not shutil.which('restoreImageCustom'): - raise OSError('restoreImageCustom not found') + raise OgError('restoreImageCustom not found') cmd = f'restoreImageCustom {repo_ip} {image_name} {disk} {partition} {method}' with open('/tmp/command.log', 'wb', 0) as logfile: @@ -220,7 +221,7 @@ def restoreImageCustom(repo_ip, image_name, disk, partition, method): shell=True, check=True) except OSError as e: - raise OSError(f'Error processing restoreImageCustom: {e}') from e + raise OgError(f'Error processing restoreImageCustom: {e}') from e return proc.returncode @@ -240,6 +241,6 @@ def configureOs(disk, partition): check=True) out = proc.stdout except OSError as e: - raise OSError(f'Error processing configureOsCustom: {e}') from e + raise OgError(f'Error processing configureOsCustom: {e}') from e return out diff --git a/src/utils/tiptorrent.py b/src/utils/tiptorrent.py index 18c4df7..83ca052 100644 --- a/src/utils/tiptorrent.py +++ b/src/utils/tiptorrent.py @@ -13,6 +13,7 @@ import shlex import shutil import subprocess import urllib.request +from src.log import OgError def _compute_md5(path, bs=2**20): m = hashlib.md5() @@ -33,9 +34,9 @@ def tip_fetch_csum(tip_addr, image_name): with urllib.request.urlopen(f'{url}') as resp: r = resp.readline().rstrip().decode('utf-8') except urllib.error.URLError as e: - raise urllib.error.URLError(f'URL error when fetching checksum: {e.reason}') from e + raise OgError(f'URL error when fetching checksum: {e.reason}') from e except urllib.error.HTTPError as e: - raise urllib.error.URLError(f'HTTP Error when fetching checksum: {e.reason}') from e + raise OgError(f'HTTP Error when fetching checksum: {e.reason}') from e return r @@ -46,7 +47,7 @@ def tip_write_csum(image_name): image_path = f'/opt/opengnsys/cache/opt/opengnsys/images/{image_name}.img' if not os.path.exists(image_path): - raise RuntimeError(f'Invalid image path {image_path} for tiptorrent checksum writing') + raise OgError(f'Invalid image path {image_path} for tiptorrent checksum writing') filename = image_path + ".full.sum" csum = _compute_md5(image_path) @@ -62,7 +63,7 @@ def tip_check_csum(tip_addr, image_name): logging.info(f'Verifying checksum for {image_name}.img, please wait...') image_path = f'/opt/opengnsys/cache/opt/opengnsys/images/{image_name}.img' if not os.path.exists(image_path): - raise RuntimeError(f'Invalid image path {image_path} for tiptorrent image csum comparison') + raise OgError(f'Invalid image path {image_path} for tiptorrent image csum comparison') cache_csum = _compute_md5(image_path) remote_csum = tip_fetch_csum(tip_addr, image_name) @@ -85,12 +86,12 @@ def tip_client_get(tip_addr, image_name): cwd='/opt/opengnsys/cache/opt/opengnsys/images/') proc.communicate() except OSError as e: - raise OSError('Unexpected error running tiptorrent subprocess: {e}') from e + raise OgError('Unexpected error running tiptorrent subprocess: {e}') from e finally: logfile.close() if proc.returncode != 0: - raise RuntimeError(f'Error fetching image {image_name} via tiptorrent') + raise OgError(f'Error fetching image {image_name} via tiptorrent') else: logging.info('Calculating checksum...') logging.info('*DO NOT REBOOT OR POWEROFF* the client during this time') diff --git a/src/utils/uefi.py b/src/utils/uefi.py index b51d765..17b35cb 100644 --- a/src/utils/uefi.py +++ b/src/utils/uefi.py @@ -15,6 +15,7 @@ import shutil from src.utils.disk import * from src.utils.fs import * from src.utils.probe import * +from src.log import OgError import fdisk @@ -25,14 +26,14 @@ def _find_bootentry(entries, label): if entry['description'] == label: return entry else: - raise NameError('Boot entry {label} not found') + raise OgError('Boot entry {label} not found') def _strip_boot_prefix(entry): try: num = entry['name'][4:] except: - raise KeyError('Unable to strip "Boot" prefix from boot entry') + raise OgError('Unable to strip "Boot" prefix from boot entry') return num @@ -56,7 +57,7 @@ def is_uefi_supported(): def run_efibootmgr_json(): if _check_efibootmgr_json() is False: - raise RuntimeError(f'{EFIBOOTMGR_BIN} not available') + raise OgError(f'{EFIBOOTMGR_BIN} not available') proc = subprocess.run([EFIBOOTMGR_BIN, '--json'], capture_output=True, text=True) dict_json = json.loads(proc.stdout) @@ -99,14 +100,14 @@ def efibootmgr_create_bootentry(disk, part, loader, label, add_to_bootorder=True try: proc = subprocess.run(shlex.split(efibootmgr_cmd), check=True, text=True) except OSError as e: - raise OSError(f'Unexpected error adding boot entry to nvram. UEFI firmware might be buggy') from e + raise OgError(f'Unexpected error adding boot entry to nvram. UEFI firmware might be buggy') from e def copy_windows_efi_bootloader(disk, partition): device = get_partition_device(disk, partition) mountpoint = device.replace('dev', 'mnt') if not mount_mkdir(device, mountpoint): - raise RuntimeError(f'Cannot probe OS family. Unable to mount {device} into {mountpoint}') + raise OgError(f'Cannot probe OS family. Unable to mount {device} into {mountpoint}') os_family = get_os_family(mountpoint) is_uefi = is_uefi_supported() @@ -119,7 +120,7 @@ def copy_windows_efi_bootloader(disk, partition): esp_mountpoint = esp.replace('dev', 'mnt') if not mount_mkdir(esp, esp_mountpoint): umount(mountpoint) - raise RuntimeError(f'Unable to mount detected EFI System Partition at {esp} into {esp_mountpoint}') + raise OgError(f'Unable to mount detected EFI System Partition at {esp} into {esp_mountpoint}') loader_paths = [f'{esp_mountpoint}/EFI/{bootlabel}/Boot/bootmgfw.efi', f'{esp_mountpoint}/EFI/Microsoft/Boot/bootmgfw.efi'] @@ -131,7 +132,7 @@ def copy_windows_efi_bootloader(disk, partition): logging.info(f'Found bootloader at ESP partition: {loader}') break else: - raise RuntimeError(f'Unable to locate Windows EFI bootloader bootmgfw.efi') + raise OgError(f'Unable to locate Windows EFI bootloader bootmgfw.efi') loader_dir = os.path.dirname(loader) destination_dir = f'{mountpoint}/ogBoot' @@ -139,12 +140,12 @@ def copy_windows_efi_bootloader(disk, partition): try: shutil.rmtree(destination_dir) except Exception as e: - raise OSError(f'Failed to delete {destination_dir}: {e}') from e + raise OgError(f'Failed to delete {destination_dir}: {e}') from e logging.info(f'Copying {loader_dir} into {destination_dir}') try: shutil.copytree(loader_dir, destination_dir) except Exception as e: - raise OSError(f'Failed to copy {loader_dir} into {destination_dir}: {e}') from e + raise OgError(f'Failed to copy {loader_dir} into {destination_dir}: {e}') from e finally: umount(mountpoint) umount(esp_mountpoint) diff --git a/src/virtual/ogOperations.py b/src/virtual/ogOperations.py index 0819a76..3cfe83a 100644 --- a/src/virtual/ogOperations.py +++ b/src/virtual/ogOperations.py @@ -23,6 +23,7 @@ import math import sys import enum import time +from src.log import OgError class OgVM: DEFAULT_CPU = 'host' @@ -97,7 +98,7 @@ class OgQMP: self.sock.connect((self.ip, self.port)) except socket.error as err: if err.errno == errno.ECONNREFUSED: - raise RuntimeError('Cannot connect to QEMU') + raise OgError('Cannot connect to QEMU') elif err.errno == errno.EINPROGRESS: pass @@ -114,11 +115,11 @@ class OgQMP: pass if 'QMP' not in out: - raise RuntimeError('Cannot handshake QEMU') + raise OgError('Cannot handshake QEMU') out = self.talk(str({"execute": "qmp_capabilities"})) if 'return' not in out: - raise RuntimeError('Cannot handshake QEMU') + raise OgError('Cannot handshake QEMU') def disconnect(self): try: @@ -143,9 +144,9 @@ class OgQMP: try: self.sock.send(bytes(data, 'utf-8')) except Exception as e: - raise RuntimeError('Cannot talk to QEMU') from e + raise OgError('Cannot talk to QEMU') from e else: - raise RuntimeError('Timeout when talking to QEMU') + raise OgError('Timeout when talking to QEMU') return self.recv(timeout=timeout) @@ -158,9 +159,9 @@ class OgQMP: out = self.sock.recv(4096).decode('utf-8') out = json.loads(out) except socket.error as err: - raise RuntimeError('Cannot talk to QEMU') from err + raise OgError('Cannot talk to QEMU') from err else: - raise RuntimeError('Timeout when talking to QEMU') + raise OgError('Timeout when talking to QEMU') return out class OgVirtualOperations: -- cgit v1.2.3-18-g5258