From fd88ce50366f28ceb2a7de43c7f51a0c6f9ff14b Mon Sep 17 00:00:00 2001 From: Zhenyu Zheng Date: Tue, 10 Dec 2024 17:13:55 +0800 Subject: [PATCH] Refactor client codes Refactor client codes Signed-off-by: Zhenyu Zheng --- eulerlauncher/cli.py | 15 +-- eulerlauncher/eulerlauncherd.py | 118 +++++++++----------- eulerlauncher/macos-gui.py | 2 +- eulerlauncher/services/image_service.py | 74 +++++++++++++ eulerlauncher/services/imager_service.py | 111 ------------------- eulerlauncher/services/instance_service.py | 122 ++++++--------------- eulerlauncher/utils/constants.py | 15 ++- eulerlauncher/utils/utils.py | 20 ++-- requirements-win.txt | 3 +- requirements.txt | 2 +- 10 files changed, 184 insertions(+), 298 deletions(-) create mode 100644 eulerlauncher/services/image_service.py delete mode 100644 eulerlauncher/services/imager_service.py diff --git a/eulerlauncher/cli.py b/eulerlauncher/cli.py index d4795ff..8f5c229 100644 --- a/eulerlauncher/cli.py +++ b/eulerlauncher/cli.py @@ -174,20 +174,7 @@ def launch(vm_name, image, arch): except Exception: print('Calling to EulerLauncherd daemon failed, please check EulerLauncherd daemon status ...') else: - - if ret['ret'] == 1: - tb = pt.PrettyTable() - tb.field_names = ["Name", "Image", "State", "IP"] - tb.add_row( - [ret['instance']['name'], - ret['instance']['image'], - ret['instance']['vmState'], - ret['instance']['ipAddress']]) - - print(tb) - - else: - print(ret['msg']) + print(ret['msg']) @click.command() @click.argument('vm_name') diff --git a/eulerlauncher/eulerlauncherd.py b/eulerlauncher/eulerlauncherd.py index a0e4a1d..bf1b790 100644 --- a/eulerlauncher/eulerlauncherd.py +++ b/eulerlauncher/eulerlauncherd.py @@ -8,14 +8,13 @@ import platform import pystray import requests import signal -import subprocess import sys import time from eulerlauncher.grpcs.eulerlauncher_grpc import images_pb2_grpc from eulerlauncher.grpcs.eulerlauncher_grpc import instances_pb2_grpc from eulerlauncher.grpcs.eulerlauncher_grpc import flavors_pb2_grpc -from eulerlauncher.services import imager_service, instance_service, flavor_service +from eulerlauncher.services import image_service, instance_service, flavor_service from eulerlauncher.utils import constants from eulerlauncher.utils import objs from eulerlauncher.utils import utils @@ -33,7 +32,7 @@ parser.add_argument('conf_file', help='Configuration file for the application', parser.add_argument('base_dir', help='The base work directory of the daemon') -def config_logging(config): +def init_log(config): log_dir = config.conf.get('default', 'log_dir') debug = config.conf.get('default', 'debug') @@ -51,13 +50,13 @@ def config_logging(config): filename=log_file, level=log_level, filemode='a+') -def init(arch, config, LOG): +def init_workdir(arch, config, LOG): work_dir = config.conf.get('default', 'work_dir') image_dir = os.path.join(work_dir, 'images') flavor_dir = os.path.join(work_dir, 'flavors') instance_dir = os.path.join(work_dir, 'instances') instance_record_file = os.path.join(instance_dir, 'instances.json') - img_record_file = os.path.join(image_dir, 'images.json') + image_record_file = os.path.join(image_dir, 'images.json') flavor_record_file = os.path.join(flavor_dir, 'flavors.json') LOG.debug('Initializing EulerLauncherd ...') @@ -65,12 +64,13 @@ def init(arch, config, LOG): if not os.path.exists(work_dir): LOG.debug('Create %s as working directory ...' % work_dir) os.makedirs(work_dir) - LOG.debug('Checking for instances directory ...') + LOG.debug('Checking for instance directory ...') if not os.path.exists(instance_dir): - LOG.debug('Create %s as working directory ...' % work_dir) + LOG.debug('Create %s as instance directory ...' % instance_dir) os.makedirs(instance_dir) LOG.debug('Checking for instance database ...') if not os.path.exists(instance_record_file): + LOG.debug('Create %s as instance database ...' % instance_record_file) instances = { 'instances': {} } @@ -82,23 +82,24 @@ def init(arch, config, LOG): os.makedirs(image_dir) LOG.debug('Checking for image database ...') - remote_img_resp = requests.get(IMG_URL, verify=False) - remote_imgs = remote_img_resp.json()[arch] - if not os.path.exists(img_record_file): - images = {} - for name, path in remote_imgs.items(): - image = objs.Image() - image.name = name - image.path = path - image.location = constants.IMAGE_LOCATION_REMOTE - image.status = constants.IMAGE_STATUS_DOWLOADABLE - images[image.name] = image.to_dict() - - image_body = { - 'remote': images, + + if not os.path.exists(image_record_file): + LOG.debug('Create %s as image database ...' % image_record_file) + remote_image_resp = requests.get(IMG_URL, verify=False) + remote_images = remote_image_resp.json()[arch] + image_record = { + 'remote': {}, 'local': {} } - utils.save_json_data(img_record_file, image_body) + + for name, path in remote_images.items(): + image_record['remote'][name] = { + 'name': name, + 'path': path, + 'location': constants.IMAGE_LOCATION_REMOTE, + 'status': constants.IMAGE_STATUS_DOWLOADABLE + } + utils.save_json_data(image_record_file, image_record) LOG.debug('Checking for flavor directory ...') if not os.path.exists(flavor_dir): @@ -112,17 +113,16 @@ def init(arch, config, LOG): utils.save_json_data(flavor_record_file, flavors) -def serve(arch, host_os, CONF, LOG, base_dir): +def serve(host_arch, host_os, CONF, LOG): ''' - Run the EulerLauncherd Service + Run the EulerLauncherd service ''' server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) - images_pb2_grpc.add_ImageGrpcServiceServicer_to_server(imager_service.ImagerService(arch, host_os, CONF, base_dir), server) - instances_pb2_grpc.add_InstanceGrpcServiceServicer_to_server(instance_service.InstanceService(arch, host_os, CONF, base_dir), server) - flavors_pb2_grpc.add_FlavorGrpcServiceServicer_to_server(flavor_service.FlavorService(arch, host_os, CONF, base_dir), server) - server.add_insecure_port('[::]:50052') + images_pb2_grpc.add_ImageGrpcServiceServicer_to_server(image_service.ImageService(host_arch, host_os, CONF, LOG), server) + instances_pb2_grpc.add_InstanceGrpcServiceServicer_to_server(instance_service.InstanceService(host_arch, host_os, CONF, LOG), server) + server.add_insecure_port('localhost:50052') server.start() - LOG.debug('EulerLauncherd Service Started ...') + LOG.debug('EulerLauncherd service started ...') if host_os == 'Win': return server @@ -137,10 +137,10 @@ def serve(arch, host_os, CONF, LOG, base_dir): while True: time.sleep(1) -def init_launcherd(conf, base_dir): - CONF = objs.Conf(conf) +def init_launcherd(conf_file): + CONF = objs.Conf(conf_file) - config_logging(CONF) + init_log(CONF) LOG = logging.getLogger(__name__) host_arch_raw = platform.uname().machine @@ -149,13 +149,9 @@ def init_launcherd(conf, base_dir): host_arch = constants.ARCH_MAP[host_arch_raw] host_os = constants.OS_MAP[host_os_raw] - try: - init(host_arch, CONF, LOG) - except Exception as e: - LOG.debug('Error: ' + str(e)) - return str(e) - else: - return serve(host_arch, host_os, CONF, LOG, base_dir) + init_workdir(host_arch, CONF, LOG) + + return serve(host_arch, host_os, CONF, LOG) if __name__ == '__main__': @@ -163,36 +159,28 @@ if __name__ == '__main__': if host_os_raw != 'Windows': args = parser.parse_args() conf_file = args.conf_file - base_dir = args.base_dir - print(base_dir) else: conf_file = os.path.join(os.getcwd(), 'etc', 'eulerlauncher.conf') - base_dir = None - try: - pass - except Exception as e: - print('Error: ' + str(e)) - else: - if host_os_raw != 'Windows': - init_launcherd(conf_file, base_dir) - else: - try: - logo = PIL.Image.open(os.path.join(os.getcwd(), 'etc', 'favicon.png')) - - def on_clicked(icon, item): - icon.stop() - icon = pystray.Icon('EulerLauncher', logo, menu=pystray.Menu( - pystray.MenuItem('Exit EulerLauncher', on_clicked) - )) + if host_os_raw != 'Windows': + init_launcherd(conf_file) + else: + try: + logo = PIL.Image.open(os.path.join(os.getcwd(), 'etc', 'favicon.png')) - except Exception as e: + def on_clicked(icon, item): + icon.stop() + + icon = pystray.Icon('EulerLauncher', logo, menu=pystray.Menu( + pystray.MenuItem('Exit EulerLauncher', on_clicked) + )) + + except Exception as e: print('Error: ' + str(e)) sys.exit(0) - - server = init_launcherd(conf_file, base_dir) + + server = init_launcherd(conf_file) - icon.run() - server.stop(None) - sys.exit(0) - + icon.run() + server.stop(None) + sys.exit(0) diff --git a/eulerlauncher/macos-gui.py b/eulerlauncher/macos-gui.py index 3562e4f..3121686 100644 --- a/eulerlauncher/macos-gui.py +++ b/eulerlauncher/macos-gui.py @@ -41,7 +41,7 @@ if __name__ == '__main__': except Exception as e: print('Error: ' + str(e)) else: - launcherd_cmd = ['sudo', os.path.join(base_dir,'./bin/EulerLauncherd'), CONF_DIR_SHELL, base_dir] + launcherd_cmd = [os.path.join(base_dir,'./bin/eulerlauncherd'), CONF_DIR_SHELL] launcherd = subprocess.Popen(' '.join(launcherd_cmd), shell=True, preexec_fn=os.setsid) def term_handler(signum, frame): diff --git a/eulerlauncher/services/image_service.py b/eulerlauncher/services/image_service.py new file mode 100644 index 0000000..a168683 --- /dev/null +++ b/eulerlauncher/services/image_service.py @@ -0,0 +1,74 @@ +import os + +from eulerlauncher.grpcs.eulerlauncher_grpc import images_pb2, images_pb2_grpc +from eulerlauncher.utils import constants + + +class ImageService(images_pb2_grpc.ImageGrpcServiceServicer): + ''' + The Image GRPC Handler + ''' + + def __init__(self, arch, host_os, CONF, LOG) -> None: + self.CONF = CONF + self.LOG = LOG + self.work_dir = self.CONF.conf.get('default', 'work_dir') + self.image_dir = os.path.join(self.work_dir, 'images') + self.image_record_file = os.path.join(self.image_dir, 'images.json') + if host_os == 'Win': + from eulerlauncher.backends.win import image_handler as win_image_handler + self.backend = win_image_handler.WinImageHandler( + self.CONF, self.work_dir, self.image_dir, self.LOG) + elif host_os == 'MacOS': + from eulerlauncher.backends.mac import image_handler as mac_image_handler + self.backend = mac_image_handler.MacImageHandler( + self.CONF, self.work_dir, self.image_dir, self.LOG) + + + def list_images(self, request, context): + self.LOG.debug(f"Get request to list images ...") + all_images = self.backend.list_images() + ret = [] + for image in all_images: + ret.append({ + 'name': image['name'], + 'location': image['location'], + 'status': image['status'] + }) + return images_pb2.ListImageResponse(images=ret) + + + def download_image(self, request, context): + self.LOG.debug(f"Get request to download image: {request.name} ...") + ret = self.backend.download_image(request.name) + msg = '' + if ret == 0: + msg = f'Downloading: {request.name}, this might take a while, please check image status with "images" command.' + elif ret == 1: + msg = f'Image: {request.name} is valid for download, please check image name from REMOTE IMAGE LIST using "images" command ...' + return images_pb2.GeneralImageResponse(ret=ret, msg=msg) + + + def delete_image(self, request, context): + self.LOG.debug(f"Get request to delete image: {request.name} ...") + ret = self.backend.delete_image(request.name) + msg = '' + if ret == 0: + msg = f'Image: {request.name} has been successfully deleted.' + elif ret == 1: + msg = f'Image: {request.name} does not exist, please check again.' + return images_pb2.GeneralImageResponse(ret=ret, msg=msg) + + + def load_image(self, request, context): + self.LOG.debug(f"Get request to load image: {request.name} from path: {request.path} ...") + ret = self.backend.load_image(request.name, request.path) + msg = '' + if ret == 0: + msg = f'Loading: {request.name}, this might take a while, please check image status with "images" command.' + elif ret == 1: + msg = f'Image: {request.path} does not exist, please check again.' + elif ret == 2: + supported_fmt = ', '.join(constants.IMAGE_LOAD_SUPPORTED_TYPES) + msg = f'Unsupported image format, the current supported format are: {supported_fmt}.' + return images_pb2.GeneralImageResponse(ret=ret, msg=msg) diff --git a/eulerlauncher/services/imager_service.py b/eulerlauncher/services/imager_service.py deleted file mode 100644 index 0699a4f..0000000 --- a/eulerlauncher/services/imager_service.py +++ /dev/null @@ -1,111 +0,0 @@ -import logging -import os - -from eulerlauncher.backends.mac import image_handler as mac_image_handler -from eulerlauncher.backends.win import image_handler as win_image_handler -from eulerlauncher.grpcs.eulerlauncher_grpc import images_pb2, images_pb2_grpc -from eulerlauncher.utils import constants as launcher_constants -from eulerlauncher.utils import utils as launcher_utils - - -LOG = logging.getLogger(__name__) - - -class ImagerService(images_pb2_grpc.ImageGrpcServiceServicer): - ''' - The Imager GRPC Handler - ''' - - def __init__(self, arch, host_os, conf, svc_base_dir) -> None: - self.CONF = conf - self.svc_base_dir = svc_base_dir - self.work_dir = self.CONF.conf.get('default', 'work_dir') - self.image_dir = os.path.join(self.work_dir, 'images') - self.img_record_file = os.path.join(self.image_dir, 'images.json') - if host_os == 'Win': - self.backend = win_image_handler.WinImageHandler( - self.CONF, self.work_dir, self.image_dir, self.img_record_file, LOG) - elif host_os == 'MacOS': - self.backend = mac_image_handler.MacImageHandler( - self.CONF, self.work_dir, self.image_dir, self.img_record_file, - LOG, self.svc_base_dir) - - def list_images(self, request, context): - LOG.debug(f"Get request to list images ...") - all_images = launcher_utils.load_json_data(self.img_record_file) - - ret = [] - for _, images in all_images.items(): - for _, img in images.items(): - image = images_pb2.Image() - image.name = img['name'] - image.location = img['location'] - image.status = img['status'] - if image.status == launcher_constants.IMAGE_STATUS_DOWNLOADING: - image.status = self.backend.download_progress_bar(image.name) - elif image.status == launcher_constants.IMAGE_STATUS_LOADING: - image.status = self.backend.load_progress_bar(image.name) - ret.append(image) - LOG.debug(f"Responded: {ret}") - return images_pb2.ListImageResponse(images=ret) - - def download_image(self, request, context): - LOG.debug(f"Get request to download image: {request.name} ...") - all_images = launcher_utils.load_json_data(self.img_record_file) - - if request.name not in all_images['remote'].keys(): - LOG.debug(f'Image: {request.name} not valid for download') - msg = f'Error: Image {request.name} is not valid for download, please check image name from REMOTE IMAGE LIST using "images" command ...' - return images_pb2.GeneralImageResponse(ret=1, msg=msg) - - @launcher_utils.asyncwrapper - def do_download(images, name): - self.backend.download_and_transform(images, name) - - do_download(all_images, request.name) - - msg = f'Downloading: {request.name}, this might take a while, please check image status with "images" command.' - return images_pb2.GeneralImageResponse(ret=0, msg=msg) - - def load_image(self, request, context): - - LOG.debug(f"Get request to load image: {request.name} from path: {request.path} ...") - - supported, fmt = launcher_utils.check_file_tail( - request.path, launcher_constants.IMAGE_LOAD_SUPPORTED_TYPES + launcher_constants.IMAGE_LOAD_SUPPORTED_TYPES_COMPRESSED) - - if not supported: - supported_fmt = ', '.join(launcher_constants.IMAGE_LOAD_SUPPORTED_TYPES + launcher_constants.IMAGE_LOAD_SUPPORTED_TYPES_COMPRESSED) - msg = f'Unsupported image format, the current supported formats are: {supported_fmt}.' - - return images_pb2.GeneralImageResponse(ret=1, msg=msg) - - all_images = launcher_utils.load_json_data(self.img_record_file) - - msg = f'Loading: {request.name}, this might take a while, please check image status with "images" command.' - update = False - - local_images = all_images['local'] - if request.name in local_images.keys(): - LOG.debug(f"Image: {request.name} already existed, replace it with: {request.path} ...") - msg = f'Replacing: {request.name}, with new image file: {request.path}, this might take a while, please check image status with "images" command.' - update = True - - @launcher_utils.asyncwrapper - def do_load(images, name, path, fmt, update): - self.backend.load_and_transform(images, name, path, fmt, update) - - do_load(all_images, request.name, request.path, fmt, update) - - return images_pb2.GeneralImageResponse(ret=0, msg=msg) - - def delete_image(self, request, context): - LOG.debug(f"Get request to delete image: {request.name} ...") - images = launcher_utils.load_json_data(self.img_record_file) - ret = self.backend.delete_image(images, request.name) - if ret == 0: - msg = f'Image: {request.name} has been successfully deleted.' - elif ret == 1: - msg = f'Image: {request.name} does not exist, please check again.' - - return images_pb2.GeneralImageResponse(ret=1, msg=msg) diff --git a/eulerlauncher/services/instance_service.py b/eulerlauncher/services/instance_service.py index 4489491..47267a2 100644 --- a/eulerlauncher/services/instance_service.py +++ b/eulerlauncher/services/instance_service.py @@ -1,121 +1,63 @@ -import logging import os from eulerlauncher.grpcs.eulerlauncher_grpc import instances_pb2, instances_pb2_grpc -from eulerlauncher.utils import utils -LOG = logging.getLogger(__name__) - class InstanceService(instances_pb2_grpc.InstanceGrpcServiceServicer): ''' The Instance GRPC Handler ''' - def __init__(self, arch, host_os, conf, svc_base_dir) -> None: - self.CONF = conf - self.svc_base_dir = svc_base_dir + def __init__(self, host_arch, host_os, CONF, LOG) -> None: + self.CONF = CONF + self.LOG = LOG self.work_dir = self.CONF.conf.get('default', 'work_dir') self.instance_dir = os.path.join(self.work_dir, 'instances') self.instance_record_file = os.path.join(self.instance_dir, 'instances.json') self.image_dir = os.path.join(self.work_dir, 'images') - self.img_record_file = os.path.join(self.image_dir, 'images.json') - self.pattern = self.CONF.conf.get('default', 'pattern') - self.host_os = host_os + self.image_record_file = os.path.join(self.image_dir, 'images.json') if host_os == 'Win': from eulerlauncher.backends.win import instance_handler as win_instance_handler self.backend = win_instance_handler.WinInstanceHandler( - self.CONF, self.work_dir, self.instance_dir, self.image_dir, self.img_record_file, LOG, self.svc_base_dir) + self.CONF, self.work_dir, self.instance_dir, self.image_dir, self.LOG) elif host_os == 'MacOS': from eulerlauncher.backends.mac import instance_handler as mac_instance_handler self.backend = mac_instance_handler.MacInstanceHandler( - self.CONF, self.work_dir, self.instance_dir, self.image_dir, - self.img_record_file, LOG, self.svc_base_dir) + self.CONF, self.work_dir, self.instance_dir, self.image_dir, self.LOG) def list_instances(self, request, context): - LOG.debug(f"Get request to list instances ...") - instances_obj = self.backend.list_instances() - + self.LOG.debug(f"Get request to list instances ...") + all_instances = self.backend.list_instances() ret = [] - for vm_obj in instances_obj: - instance_dict = { - 'name': vm_obj.name, - 'image': vm_obj.image, - 'vm_state': vm_obj.vm_state, - 'ip_address': vm_obj.ip if vm_obj.ip else 'N/A' - } - ret.append(instance_dict) - + for instance in all_instances: + ret.append({ + 'name': instance['name'], + 'image': instance['image'], + 'vm_state': instance['state'], + 'ip_address': instance['ip_address'] + }) return instances_pb2.ListInstancesResponse(instances=ret) + def create_instance(self, request, context): - LOG.debug(f"Get request to create instance: {request.name} with image {request.image} ...") - # LOG.debug(self.pattern) - if self.host_os == 'Win': - if self.pattern == 'hyper-v' and request.arch == 'arm': - msg = f'Error: The pattern of hyper-v can not create the instance with the arm architecture, please choose correct argument : "--arch"' - return instances_pb2.CreateInstanceResponse(ret=2, msg=msg) - all_img = utils.load_json_data(self.img_record_file) - if request.image not in all_img['local'].keys(): + self.LOG.debug(f"Get request to create instance: {request.name} with image: {request.image} ...") + ret = self.backend.create_instance(request.name, request.image) + msg = '' + if ret == 0: + msg = f'Successfully created instance: {request.name} with image: {request.image}.' + elif ret == 1: msg = f'Error: Image "{request.image}" is not available locally, please check again or (down)load it before using ...' - return instances_pb2.CreateInstanceResponse(ret=2, msg=msg) - # LOG.debug(os.path.splitext(all_img['local'][request.image]['path'])) - # LOG.debug(request.arch) - if self.host_os == 'Win': - format = os.path.splitext(all_img['local'][request.image]['path'])[-1] - if (format == '.vhdx' and self.pattern == 'qemu') or (format == '.qcow2' and self.pattern == 'hyper-v'): - msg = f'Error: Image "{request.image}" is "{format}" format but pattern is {self.pattern}, please choose correct pattern or correct image.' - return instances_pb2.CreateInstanceResponse(ret=2, msg=msg) - all_instances = utils.load_json_data(self.instance_record_file) - if request.name in all_instances['instances'].keys(): + elif ret == 2: msg = f'Error: Instance with name {request.name} already exist, please specify another name.' - return instances_pb2.CreateInstanceResponse(ret=2, msg=msg) - - check_result = self.backend.check_names(request.name, all_instances) - if check_result == 1: - msg = f'Error: Instance with name {request.name} already exist in exixting Hyper-V or Qemu backend, please specify another name.' - return instances_pb2.CreateInstanceResponse(ret=2, msg=msg) - - vm = self.backend.create_instance( - request.name, request.image, self.instance_record_file, all_instances, all_img, False, 0, 0, request.arch) - msg = f'Successfully created {request.name} with image {request.image}' - return instances_pb2.CreateInstanceResponse(ret=1, msg=msg, instance=vm) + return instances_pb2.CreateInstanceResponse(ret=ret, msg=msg) - def delete_instance(self, request, context): - LOG.debug(f"Get request to delete instance: {request.name} ...") - all_instances = utils.load_json_data(self.instance_record_file) - if request.name not in all_instances['instances'].keys(): - msg = f'Error: Instance with name {request.name} does not exist.' - return instances_pb2.DeleteInstanceResponse(ret=2, msg=msg) - - self.backend.delete_instance(request.name, self.instance_record_file, all_instances) - msg = f'Successfully deleted instance: {request.name}.' - return instances_pb2.DeleteInstanceResponse(ret=1, msg=msg) - - def take_snapshot(self, request, context): - LOG.debug(f"Get request to take snapshot: {request.name} with snapshot name {request.snapshot}, export to path: {request.dest_path}...") - all_img = utils.load_json_data(self.img_record_file) - all_instances = utils.load_json_data(self.instance_record_file) - if request.name not in all_instances['instances'].keys(): - msg = f'Error: Instance with name {request.name} does not exist.' - return instances_pb2.TakeSnapshotResponse(msg=msg) - export_path = self.backend.take_snapshot(request.name, request.snapshot, request.dest_path, all_instances, all_img, self.instance_record_file) - msg = f'Successfully take snapshot: {request.snapshot} of vm: {request.name} and export snapshot image to {export_path}.' - return instances_pb2.TakeSnapshotResponse(msg=msg) - def export_development_image(self, request, context): - LOG.debug(f"Get request to export Python/Go/Java development image for: {request.name} with image name {request.image}, export to path: {request.dest_path}...") - all_img = utils.load_json_data(self.img_record_file) - all_instances = utils.load_json_data(self.instance_record_file) - if request.name not in all_instances['instances'].keys(): + def delete_instance(self, request, context): + self.LOG.debug(f"Get request to delete instance: {request.name} ...") + ret = self.backend.delete_instance(request.name) + msg = '' + if ret == 0: + msg = f'Successfully deleted instance: {request.name}.' + elif ret == 1: msg = f'Error: Instance with name {request.name} does not exist.' - return instances_pb2.ExportDevelopmentImageResponse(msg=msg) - result = self.backend.make_development_image(request.name, request.pwd) - if result != 0: - LOG.debug(f"install Python/Go/Java environment for vm {request.name} failed!") - msg = f"install Python/Go/Java environment for vm {request.name} failed!" - return instances_pb2.ExportDevelopmentImageResponse(msg=msg) - LOG.debug(f"vm: {request.name} install Python/Go/Java development environment finished") - export_path = self.backend.take_snapshot(request.name, request.image, request.dest_path, all_instances, all_img, self.instance_record_file) - msg = f'Successfully export Python/Go/Java development image: {request.image} of vm: {request.name} and export development image to {export_path}.' - return instances_pb2.ExportDevelopmentImageResponse(msg=msg) \ No newline at end of file + return instances_pb2.DeleteInstanceResponse(ret=ret, msg=msg) diff --git a/eulerlauncher/utils/constants.py b/eulerlauncher/utils/constants.py index 3654b79..0baa46d 100644 --- a/eulerlauncher/utils/constants.py +++ b/eulerlauncher/utils/constants.py @@ -23,12 +23,15 @@ ARCH_MAP = { 'x86_64': 'x86_64' } -VM_STATE_MAP = { - 2: 'Running', - 3: 'Stopped', - 10: 'Rebooting', - 32768: 'Paused', - 32769: 'Suspended', +INSTANCE_STATE_MAP = { + 0: 'N/A', + 1: 'Running', + 2: 'Blocked', + 3: 'Paused', + 4: 'Shutdown', + 5: 'Shutoff', + 6: 'Crashed', + 7: 'Suspended', 99: 'N/A' } diff --git a/eulerlauncher/utils/utils.py b/eulerlauncher/utils/utils.py index 3503fd8..190baa8 100644 --- a/eulerlauncher/utils/utils.py +++ b/eulerlauncher/utils/utils.py @@ -3,8 +3,8 @@ import json import os import random from threading import Thread +from lxml import etree import uuid -import chardet from google.protobuf.json_format import MessageToDict @@ -53,13 +53,21 @@ def format_mac_addr(mac_str): def load_json_data(json_file): with open(json_file, 'r', encoding='utf-8') as fr: - data = json.load(fr) + data = json.load(fr) return data def save_json_data(json_file, data): with open(json_file, 'w', encoding='utf-8') as fw: - json.dump(data, fw, indent=4, ensure_ascii=False) + json.dump(data, fw, indent=4, ensure_ascii=False) + +def load_xml_data(xml_file): + data = etree.parse(xml_file) + return data + +def save_xml_data(xml_file, data): + with open(xml_file, 'wb') as fw: + fw.write(etree.tostring(data, pretty_print=True, encoding='utf-8')) def generate_mac(): local_mac = uuid.uuid1().hex[-12:] @@ -93,9 +101,3 @@ def check_file_tail(file_name, to_check): break return ret, ret_fmt - -def detect_encoding(file_path): - with open(file_path, 'rb') as file: - raw_data = file.read() - result = chardet.detect(raw_data) - return result['encoding'] \ No newline at end of file diff --git a/requirements-win.txt b/requirements-win.txt index 7ed4143..7a1a826 100644 --- a/requirements-win.txt +++ b/requirements-win.txt @@ -23,4 +23,5 @@ pystray PyYAML six urllib3 -wget \ No newline at end of file +wget +libvirt-python \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e44a74e..f6d6953 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,4 +28,4 @@ wget pywebview sqlalchemy httpx -libvirt \ No newline at end of file +libvirt-python \ No newline at end of file -- Gitee