diff --git a/.gitignore b/.gitignore
index 7c9d0f2ebe2b0f9c6cf7986c8a2ec63695701469..0e052ff83a67a8892f09aa357b01f78ee7c80b43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,7 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
+.DS_Store
# PyInstaller
# Usually these files are written by a python script from a template
diff --git a/etc/.DS_Store b/etc/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..8cd44faa73ca32b3980f166a74c56d9b17e076bd
Binary files /dev/null and b/etc/.DS_Store differ
diff --git a/etc/bin/.DS_Store b/etc/bin/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..c420a9f7e7adf7bdbd5c5621ba1585807ca01a56
Binary files /dev/null and b/etc/bin/.DS_Store differ
diff --git a/etc/eulerlauncher.conf b/etc/eulerlauncher.conf
index a101a510a7e4508fa09797c0573d0299cf152f04..4c70880acb27c4705d43479772b93e552e60e7dd 100644
--- a/etc/eulerlauncher.conf
+++ b/etc/eulerlauncher.conf
@@ -1,8 +1,8 @@
-[default]
-log_dir =
-work_dir =
-wget_dir =
-qemu_dir =
+[default]
+log_dir = /Users/dengzhihang/Documents/workplace/eulerlauncher/log_dir
+work_dir = /Users/dengzhihang/Documents/workplace/eulerlauncher/work_dir
+wget_dir = /opt/homebrew/bin/wget
+qemu_dir = /opt/homebrew/bin/qemu-system-aarch64
debug = True
[vm]
diff --git a/etc/supported_images.json b/etc/supported_images.json
index 91d1c3adf141164a6bfced355dd09ffaeb65f11b..0d306db40d1db9c4dc161dc2c6dc05de54aa8e09 100644
--- a/etc/supported_images.json
+++ b/etc/supported_images.json
@@ -1,14 +1,14 @@
{
"x86_64":
{
+ "20.03-LTS": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-20.03-LTS/virtual_machine_img/x86_64/openEuler-20.03-LTS-x86_64.qcow2.xz",
"22.03-LTS": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-22.03-LTS/virtual_machine_img/x86_64/openEuler-22.03-LTS-x86_64.qcow2.xz",
- "22.09": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-22.09/virtual_machine_img/x86_64/openEuler-22.09-x86_64.qcow2.xz",
- "23.03": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-23.03/virtual_machine_img/x86_64/openEuler-23.03-x86_64.qcow2.xz"
+ "24.03-LTS": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-24.03/virtual_machine_img/x86_64/openEuler-24.03-LTS-x86_64.qcow2.xz"
},
"aarch64":
{
+ "20.03-LTS": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-20.03-LTS/virtual_machine_img/aarch64/openEuler-20.03-LTS-aarch64.qcow2.xz",
"22.03-LTS": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-22.03-LTS/virtual_machine_img/aarch64/openEuler-22.03-LTS-aarch64.qcow2.xz",
- "22.09": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-22.09/virtual_machine_img/aarch64/openEuler-22.09-aarch64.qcow2.xz",
- "23.03": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-23.03/virtual_machine_img/aarch64/openEuler-23.03-aarch64.qcow2.xz"
+ "24.03-LTS": "https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-24.03-LTS/virtual_machine_img/aarch64/openEuler-24.03-LTS-aarch64.qcow2.xz"
}
}
diff --git a/eulerlauncher/.DS_Store b/eulerlauncher/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..2e811fe9c885d47640a8cac3dcd204a4500adde7
Binary files /dev/null and b/eulerlauncher/.DS_Store differ
diff --git a/eulerlauncher/backends/mac/image_handler.py b/eulerlauncher/backends/mac/image_handler.py
index f9c8ec6753466f9183fc2d0a6a2fde0e08ac2f1e..2e10103af2b6aa54abdf562d7fa09f9a6b3a500f 100644
--- a/eulerlauncher/backends/mac/image_handler.py
+++ b/eulerlauncher/backends/mac/image_handler.py
@@ -1,4 +1,3 @@
-import copy
import lzma
import wget
import os
@@ -7,8 +6,7 @@ import shutil
import ssl
from eulerlauncher.utils import constants
-from eulerlauncher.utils import utils as omni_utils
-from eulerlauncher.utils import objs
+from eulerlauncher.utils import utils
ssl._create_default_https_context = ssl._create_unverified_context
@@ -16,103 +14,124 @@ ssl._create_default_https_context = ssl._create_unverified_context
class MacImageHandler(object):
- def __init__(self, conf, work_dir, image_dir, image_record_file,
- logger, base_dir) -> None:
- self.conf = conf
+ def __init__(self, CONF, work_dir, image_dir, LOG) -> None:
+ self.conf = CONF
self.work_dir = work_dir
self.image_dir = image_dir
- self.image_record_file = image_record_file
- self.base_dir = base_dir
- self.wget_bin = conf.conf.get('default', 'wget_dir')
- self.LOG = logger
+ self.image_record_file = os.path.join(image_dir, 'images.json')
+ self.LOG = LOG
- def download_and_transform(self, images, img_to_download):
-
- # Download the image
- img_name = wget.filename_from_url(images['remote'][img_to_download]['path'])
- img_dict = copy.deepcopy(images['remote'][img_to_download])
-
- if not os.path.exists(os.path.join(self.image_dir, img_name)):
- self.LOG.debug(f'Downloading image: {img_to_download} from remote repo ...')
- img_dict['location'] = constants.IMAGE_LOCATION_LOCAL
- img_dict['status'] = constants.IMAGE_STATUS_DOWNLOADING
- images['local'][img_to_download] = img_dict
- omni_utils.save_json_data(self.image_record_file, images)
+ def list_images(self):
+ image_record = utils.load_json_data(self.image_record_file)
+ all_images = list(image_record["remote"].values()) + list(image_record["local"].values())
+ return all_images
+
- download_cmd = [self.wget_bin, images['remote'][img_to_download]['path'],
- '-O', os.path.join(self.image_dir, img_name), '--no-check-certificate']
+ def download_image(self, name):
+ image_record = utils.load_json_data(self.image_record_file)
+ if name not in image_record['remote'].keys():
+ self.LOG.debug(f'Image: {name} not valid for download')
+ return 1
+
+ @utils.asyncwrapper
+ def download_and_transform(name):
+ image_record = utils.load_json_data(self.image_record_file)
+ image_url = image_record['remote'][name]['path']
+ image_file = wget.filename_from_url(image_url)
+
+ # Download the image
+ self.LOG.debug(f'Downloading image: {name} from remote repo ...')
+ image_record['local'][name] = {
+ 'name': name,
+ 'location': constants.IMAGE_LOCATION_LOCAL,
+ 'status': constants.IMAGE_STATUS_DOWNLOADING,
+ 'path': image_url
+ }
+ utils.save_json_data(self.image_record_file, image_record)
+ wget_bin = self.conf.conf.get('default', 'wget_dir')
+ download_cmd = [wget_bin, image_url,
+ '-O', os.path.join(self.image_dir, image_file),
+ '--no-check-certificate',
+ '--user-agent', 'Mozilla']
self.LOG.debug(' '.join(download_cmd))
subprocess.call(' '.join(download_cmd), shell=True)
- #wget.download(url=images['remote'][img_to_download]['path'], out=os.path.join(self.image_dir, img_name), bar=None)
- self.LOG.debug(f'Image: {img_to_download} succesfully downloaded from remote repo ...')
-
- # Decompress the image
- self.LOG.debug(f'Decompressing image file: {img_name} ...')
- qcow2_name = img_name[:-3]
- with open(os.path.join(self.image_dir, img_name), 'rb') as pr, open(os.path.join(self.image_dir, qcow2_name), 'wb') as pw:
- data = pr.read()
- data_dec = lzma.decompress(data)
- pw.write(data_dec)
-
- self.LOG.debug(f'Cleanup temp files ...')
- os.remove(os.path.join(self.image_dir, img_name))
+ self.LOG.debug(f'Image: {name} succesfully downloaded from remote repo ...')
- # Record local image
- img_dict['status'] = constants.IMAGE_STATUS_READY
- img_dict['path'] = os.path.join(self.image_dir, qcow2_name)
- images['local'][img_to_download] = img_dict
- omni_utils.save_json_data(self.image_record_file, images)
- self.LOG.debug(f'Image: {img_to_download} is ready ...')
+ # Decompress the image
+ self.LOG.debug(f'Decompressing image: {image_file} ...')
+ with open(os.path.join(self.image_dir, image_file), 'rb') as pr, open(os.path.join(self.image_dir, name), 'wb') as pw:
+ data = pr.read()
+ data_dec = lzma.decompress(data)
+ pw.write(data_dec)
+
+ self.LOG.debug(f'Cleanup temp files ...')
+ os.remove(os.path.join(self.image_dir, image_file))
+
+ # Record local image
+ image_record = utils.load_json_data(self.image_record_file)
+ image_record['local'][name]['status'] = constants.IMAGE_STATUS_READY
+ image_record['local'][name]['path'] = os.path.join(self.image_dir, name)
+ utils.save_json_data(self.image_record_file, image_record)
+ self.LOG.debug(f'Image: {name} is ready ...')
+
+ download_and_transform(name)
+ return 0
- def delete_image(self, images, img_to_delete):
- if img_to_delete not in images['local'].keys():
+ def delete_image(self, name):
+ image_record = utils.load_json_data(self.image_record_file)
+ if name not in image_record['local'].keys():
+ self.LOG.debug(f'Image: {name} not valid for delete')
return 1
- else:
- return self._delete_image(images, img_to_delete)
-
- def _delete_image(self, images, img_to_delete):
- img_path = images['local'][img_to_delete]['path']
- # TODO: Raise error message if image file not exists
- if os.path.exists(img_path):
- self.LOG.debug(f'Deleting: {img_path} ...')
- os.remove(img_path)
-
- self.LOG.debug(f'Deleting: {img_to_delete} from image database ...')
- del images['local'][img_to_delete]
- omni_utils.save_json_data(self.image_record_file, images)
+ image_path = image_record['local'][name]['path']
+ self.LOG.debug(f'Deleting: {name} from image database ...')
+ os.remove(image_path)
+ del image_record['local'][name]
+ utils.save_json_data(self.image_record_file, image_record)
return 0
- def load_and_transform(self, images, img_to_load, path, fmt, update=False):
+
+ def load_image(self, name, path):
+ if not os.path.exists(path):
+ self.LOG.debug(f'Image: {path} does not exist')
+ return 1
- if update:
- self._delete_image(images, img_to_load)
+ supported, fmt = utils.check_file_tail(path, constants.IMAGE_LOAD_SUPPORTED_TYPES)
+ if not supported:
+ self.LOG.debug(f'Image: {name} not valid for load')
+ return 2
- image = objs.Image()
- image.name = img_to_load
- image.path = ''
- image.location = constants.IMAGE_LOCATION_LOCAL
- image.status = constants.IMAGE_STATUS_LOADING
- images['local'][image.name] = image.to_dict()
- omni_utils.save_json_data(self.image_record_file, images)
-
- if fmt == 'qcow2':
- qcow2_name = f'{img_to_load}.qcow2'
- shutil.copyfile(path, os.path.join(self.image_dir, qcow2_name))
- else:
- # Decompress the image
- self.LOG.debug(f'Decompressing image file: {path} ...')
- qcow2_name = f'{img_to_load}.qcow2'
- with open(path, 'rb') as pr, open(os.path.join(self.image_dir, qcow2_name), 'wb') as pw:
- data = pr.read()
- data_dec = lzma.decompress(data)
- pw.write(data_dec)
-
- # Record local image
- image.path = os.path.join(self.image_dir, qcow2_name)
- image.status = constants.IMAGE_STATUS_READY
- images['local'][image.name] = image.to_dict()
- omni_utils.save_json_data(self.image_record_file, images)
- self.LOG.debug(f'Image: {qcow2_name} is ready ...')
+ @utils.asyncwrapper
+ def load_and_transform(name, path):
+ image_record = utils.load_json_data(self.image_record_file)
+ supported, fmt = utils.check_file_tail(path, constants.IMAGE_LOAD_SUPPORTED_TYPES)
+ self.LOG.debug(f'Loading image: {name} from image file: {path} ...')
+ image_record['local'][name] = {
+ 'name': name,
+ 'location': constants.IMAGE_LOCATION_LOCAL,
+ 'status': constants.IMAGE_STATUS_LOADING,
+ 'path': ''
+ }
+ utils.save_json_data(self.image_record_file, image_record)
+
+ if fmt == 'qcow2':
+ shutil.copyfile(path, os.path.join(self.image_dir, name))
+ else:
+ # Decompress the image
+ self.LOG.debug(f'Decompressing image file: {path} ...')
+ with open(path, 'rb') as pr, open(os.path.join(self.image_dir, name), 'wb') as pw:
+ data = pr.read()
+ data_dec = lzma.decompress(data)
+ pw.write(data_dec)
+
+ # Record local image
+ image_record = utils.load_json_data(self.image_record_file)
+ image_record['local'][name]['status'] = constants.IMAGE_STATUS_READY
+ image_record['local'][name]['path'] = os.path.join(self.image_dir, name)
+ utils.save_json_data(self.image_record_file, image_record)
+ self.LOG.debug(f'Image: {name} is ready ...')
+
+ load_and_transform(name, path)
+ return 0
\ No newline at end of file
diff --git a/eulerlauncher/backends/mac/instance_handler.py b/eulerlauncher/backends/mac/instance_handler.py
index a53e78d81925ece983d717e04f3151860cc6b26e..c3a7be6708de761d833bb6de131a24fc6652a507 100644
--- a/eulerlauncher/backends/mac/instance_handler.py
+++ b/eulerlauncher/backends/mac/instance_handler.py
@@ -1,177 +1,106 @@
import os
-import psutil
+import libvirt
import shutil
-import signal
-import subprocess
-import sys
-import time
-
-from oslo_utils import uuidutils
+import platform
from eulerlauncher.utils import constants
-from eulerlauncher.utils import utils as omni_utils
-from eulerlauncher.utils import objs
-from eulerlauncher.backends.mac import qemu
+from eulerlauncher.utils import utils
class MacInstanceHandler(object):
- def __init__(self, conf, work_dir, instance_dir, image_dir,
- image_record_file, logger, base_dir) -> None:
- self.conf = conf
+ def __init__(self, CONF, work_dir, instance_dir, image_dir, LOG) -> None:
+ self.conf = CONF
self.work_dir = work_dir
self.instance_dir = instance_dir
self.instance_record_file = os.path.join(instance_dir, 'instances.json')
self.image_dir = image_dir
- self.image_record_file = image_record_file
- self.driver = qemu.QemuDriver(self.conf, logger)
- self.running_instances = {}
- self.instance_pids = []
- self.base_dir = base_dir
- self.LOG = logger
+ self.image_record_file = os.path.join(image_dir, 'images.json')
+ self.LOG = LOG
def list_instances(self):
- instances = omni_utils.load_json_data(self.instance_record_file)['instances']
- vm_list = []
-
- for instance in instances.values():
- vm = objs.Instance(name=instance['name'])
- vm.uuid = instance['uuid']
- vm.mac = instance['mac_address']
- vm.info = None
- vm.vm_state = self._check_vm_state(instance)
- if not instance['ip_address']:
- ip_address = self._parse_ip_addr(vm.mac)
- vm.ip = ip_address
- else:
- vm.ip = instance['ip_address']
- vm.image = instance['image']
- vm_list.append(vm)
-
- return vm_list
-
- def _check_vm_state(self, instance):
- if instance['identification']['type'] == 'pid':
- instance_pid = instance['identification']['id']
- if instance_pid in psutil.pids() and \
- psutil.Process(instance_pid).status() == 'running' and \
- psutil.Process(instance_pid).name().startswith('qemu'):
- return constants.VM_STATE_MAP[2]
- else:
- return constants.VM_STATE_MAP[3]
- else:
- return constants.VM_STATE_MAP[99]
-
- def _parse_ip_addr(self, mac_addr):
- ip = ''
- cmd = 'arp -a'
- start_time = time.time()
- while(ip == '' and time.time() - start_time < 20):
- pr = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE)
- arp_result = pr.stdout.decode('utf-8').split('\n')
- founded = False
- for str in arp_result:
- # The result for 'arp -a' in MacOS is different with Linux, it erase
- # the first 0 if the first digit is 0 for this mac section, add it
- # back before compare
- try:
- arp_ip = str.split(' ')[1].replace("(", "").replace(")", "")
- mac = str.split(' ')[3].replace("(", "").replace(")", "")
- except IndexError:
- continue
- mac_list = mac.split(':')
- for i in range(0, len(mac_list)):
- if len(mac_list[i]) == 1:
- mac_list[i] = '0' + mac_list[i]
- mac_0 = ':'.join(mac_list)
- if mac_addr == mac_0:
- ip = arp_ip
- founded = True
- break
- if founded:
- break
-
- return ip
-
- def check_names(self, name, all_instances):
- try:
- all_instances['instances'][name]
+ instance_record = utils.load_json_data(self.instance_record_file)
+ all_instances = list(instance_record.values())
+ return all_instances
+
+ def create_instance(self, name, image):
+ image_record = utils.load_json_data(self.image_record_file)
+ if image not in image_record['local'].keys():
+ self.LOG.debug(f'Image: {image} is not available locally')
return 1
- except KeyError:
- return 0
-
- def create_instance(self, name, image_id, instance_record, all_instances, all_images):
- # Create dir for the instance
- vm_uuid = uuidutils.generate_uuid()
- vm_dict = {
- 'name': name,
- 'uuid': vm_uuid,
- 'image': image_id,
- 'vm_state': constants.VM_STATE_MAP[99],
- 'ip_address': 'N/A',
- 'mac_address': omni_utils.generate_mac(),
- 'identification': {
- 'type': 'pid',
- 'id': None
- }
- }
-
+
+ instance_record = utils.load_json_data(self.instance_record_file)
+ if name in instance_record.keys():
+ self.LOG.debug(f'Instance: {name} already exist')
+ return 2
+
instance_path = os.path.join(self.instance_dir, name)
os.makedirs(instance_path)
- img_path = all_images['local'][image_id]['path']
-
- root_disk_path = shutil.copyfile(img_path, os.path.join(instance_path, image_id + '.qcow2'))
-
- vm_process = self.driver.create_vm(name, vm_uuid, vm_dict['mac_address'], root_disk_path)
-
- self.running_instances[vm_process.pid] = vm_process
- self.instance_pids.append(vm_process.pid)
+ image_path = image_record['local'][image]['path']
+ disk_path = shutil.copyfile(image_path, os.path.join(instance_path, image))
+ host_arch_raw = platform.uname().machine
+ host_arch = constants.ARCH_MAP[host_arch_raw]
+ xml_file = os.path.join('/Library/Application Support/org.openeuler.eulerlauncher/','libvirt-' + host_arch + '.xml')
+ xml = utils.load_xml_data(xml_file)
+ vcpu = self.conf.conf.get('vm', 'cpu_num')
+ ram = self.conf.conf.get('vm', 'memory')
+
+ def xml_find_and_set(xml, xpath, attribute=None, value=None):
+ elements = xml.xpath(xpath)
+ if attribute is not None:
+ if value is not None:
+ elements[0].set(attribute, value)
+ return elements[0].get(attribute)
+ else:
+ if value is not None:
+ elements[0].text = value
+ return elements[0].text
+
+ xml_find_and_set(xml, 'name', value=name)
+ xml_find_and_set(xml, 'vcpu', value=vcpu)
+ xml_find_and_set(xml, 'memory', value=ram)
+ xml_find_and_set(xml, 'devices/emulator', value=self.conf.conf.get('default', 'qemu_dir'))
+ xml_find_and_set(xml, 'devices/disk/source', 'file', disk_path)
+ xml_find_and_set(xml, 'devices/interface/mac', 'address', utils.generate_mac())
+ utils.save_xml_data(xml_file, xml)
- vm_dict['identification']['id'] = vm_process.pid
-
- vm_ip = self._parse_ip_addr(vm_dict['mac_address'])
- vm_dict['ip_address'] = vm_ip
-
- instance_record_dict = {
+ conn = libvirt.open("qemu:///session")
+ with open(xml_file, 'r') as pr:
+ dom = conn.createLinux(pr.read())
+
+ instance_record[name] = {
+ 'id': dom.ID(),
'name': name,
- 'uuid': vm_dict['uuid'],
- 'image': image_id,
- 'path': instance_path,
- 'mac_address': vm_dict['mac_address'],
- 'ip_address': vm_dict['ip_address'],
- 'identification': vm_dict['identification']
+ 'state': constants.INSTANCE_STATE_MAP[dom.state()[0]],
+ 'vcpu': dom.maxVcpus(),
+ 'ram': dom.maxMemory() // 1024,
+ 'image': image,
+ 'mac_address': '',
+ 'ip_address': 'N/A',
+ 'path': instance_path
}
+ utils.save_json_data(self.instance_record_file, instance_record)
+ conn.close()
+ return 0
- all_instances['instances'][name] = instance_record_dict
- omni_utils.save_json_data(instance_record, all_instances)
+ def delete_instance(self, name):
+ instance_record = utils.load_json_data(self.instance_record_file)
- return {
- 'name': name,
- 'vm_state': self._check_vm_state(vm_dict),
- 'image': image_id,
- 'ip_address': vm_dict['ip_address']
- }
+ conn = libvirt.open("qemu:///session")
+ dom = conn.lookupByName(name)
- def delete_instance(self, name, instance_record, all_instances):
- # Delete instance process
- instance = all_instances['instances'][name]
- if instance['identification']['type'] == 'pid':
- instance_pid = instance['identification']['id']
- if instance_pid in psutil.pids() and \
- psutil.Process(instance_pid).is_running():
- psutil.Process(instance_pid).kill()
- self.LOG.debug(f'Instance: {name} with PID {instance_pid} succesfully killed ...')
- else:
- self.LOG.debug(f'Instance: {name} with PID {instance_pid} already stopped, skip ...')
+ if dom is not None:
+ dom.destroy()
+ self.LOG.debug(f'Instance: {name} succesfully killed ...')
else:
- self.LOG.debug(f'Instance: {name} unable to handled, skip ...')
+ self.LOG.debug(f'Instance: {name} already stopped, skip ...')
# Cleanup files and records
- instance_dir = instance['path']
- shutil.rmtree(instance_dir)
- del all_instances['instances'][name]
-
- omni_utils.save_json_data(instance_record, all_instances)
+ instance_path = instance_record[name]['path']
+ shutil.rmtree(instance_path)
+ del instance_record[name]
+ utils.save_json_data(self.instance_record_file, instance_record)
+ conn.close()
return 0
diff --git a/eulerlauncher/backends/mac/qemu.py b/eulerlauncher/backends/mac/qemu.py
deleted file mode 100644
index 2bdd900d0db4bd6a6f408db32a47875c535b12b2..0000000000000000000000000000000000000000
--- a/eulerlauncher/backends/mac/qemu.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import platform
-import subprocess
-import os
-
-from eulerlauncher.utils import constants
-
-
-class QemuDriver(object):
-
- def __init__(self, conf, logger) -> None:
- host_arch_raw = platform.uname().machine
- host_arch = constants.ARCH_MAP[host_arch_raw]
- self.qemu_bin = conf.conf.get('default', 'qemu_dir')
- self.uefi_file = os.path.join('/Library/Application\ Support/org.openeuler.eulerlauncher/','edk2-' + host_arch + '-code.fd')
- self.uefi_params = ',if=pflash,format=raw,readonly=on'
- self.vm_cpu = conf.conf.get('vm', 'cpu_num')
- self.vm_ram = conf.conf.get('vm', 'memory')
- self.LOG = logger
-
- def create_vm(self, vm_name, vm_uuid, vm_mac, vm_root_disk):
- qemu_cmd = [
- self.qemu_bin, '-machine', 'virt,highmem=off', '-name', vm_name, '-uuid', vm_uuid,
- '-accel hvf', '-drive', 'file=' + self.uefi_file + self.uefi_params, '-cpu host',
- '-nic', 'vmnet-shared,model=virtio-net-pci,mac=' + vm_mac,
- '-drive', 'file=' + vm_root_disk, '-device', 'virtio-scsi-pci,id=scsi0',
- '-smp', self.vm_cpu, '-m', self.vm_ram + 'M', '-monitor none -chardev null,id=char0',
- '-serial chardev:char0 -nographic']
- self.LOG.debug(' '.join(qemu_cmd))
- instance_process = subprocess.Popen(' '.join(qemu_cmd), shell=True)
- return instance_process
diff --git a/eulerlauncher/backends/win/image_handler.py b/eulerlauncher/backends/win/image_handler.py
index 9f09f4d13bcea66cc39a418e200ccabfdcd582dd..56a0c2ea2e621fb518d04c7c4d8182005ef97eb3 100644
--- a/eulerlauncher/backends/win/image_handler.py
+++ b/eulerlauncher/backends/win/image_handler.py
@@ -7,7 +7,7 @@ import ssl
from eulerlauncher.backends.win import powershell
from eulerlauncher.utils import constants
-from eulerlauncher.utils import utils as omni_utils
+from eulerlauncher.utils import utils
from eulerlauncher.utils import objs
@@ -23,32 +23,32 @@ class WinImageHandler(object):
self.image_record_file = image_record_file
self.LOG = logger
- def download_and_transform(self, images, img_to_download):
+ def download_and_transform(self, images, image_to_download):
# Download the image
- img_name = wget.filename_from_url(images['remote'][img_to_download]['path'])
- img_dict = copy.deepcopy(images['remote'][img_to_download])
+ image_name = wget.filename_from_url(images['remote'][image_to_download]['path'])
+ img_dict = copy.deepcopy(images['remote'][image_to_download])
- if not os.path.exists(os.path.join(self.image_dir, img_name)):
- self.LOG.debug(f'Downloading image: {img_to_download} from remote repo ...')
+ if not os.path.exists(os.path.join(self.image_dir, image_name)):
+ self.LOG.debug(f'Downloading image: {image_to_download} from remote repo ...')
img_dict['location'] = constants.IMAGE_LOCATION_LOCAL
img_dict['status'] = constants.IMAGE_STATUS_DOWNLOADING
- images['local'][img_to_download] = img_dict
- omni_utils.save_json_data(self.image_record_file, images)
- wget.download(url=images['remote'][img_to_download]['path'], out=os.path.join(self.image_dir, img_name), bar=None)
- self.LOG.debug(f'Image: {img_to_download} succesfully downloaded from remote repo ...')
+ images['local'][image_to_download] = img_dict
+ utils.save_json_data(self.image_record_file, images)
+ wget.download(url=images['remote'][image_to_download]['path'], out=os.path.join(self.image_dir, image_name), bar=None)
+ self.LOG.debug(f'Image: {image_to_download} succesfully downloaded from remote repo ...')
# Decompress the image
- self.LOG.debug(f'Decompressing image file: {img_name} ...')
- qcow2_name = img_name[:-3]
- with open(os.path.join(self.image_dir, img_name), 'rb') as pr, open(os.path.join(self.image_dir, qcow2_name), 'wb') as pw:
+ self.LOG.debug(f'Decompressing image file: {image_name} ...')
+ qcow2_name = image_name[:-3]
+ with open(os.path.join(self.image_dir, image_name), 'rb') as pr, open(os.path.join(self.image_dir, qcow2_name), 'wb') as pw:
data = pr.read()
data_dec = lzma.decompress(data)
pw.write(data_dec)
# Convert the qcow2 img to vhdx
- vhdx_name = img_to_download + '.vhdx'
- self.LOG.debug(f'Converting image file: {img_name} to {vhdx_name} ...')
+ vhdx_name = image_to_download + '.vhdx'
+ self.LOG.debug(f'Converting image file: {image_name} to {vhdx_name} ...')
with powershell.PowerShell('GBK') as ps:
cmd = 'qemu-img convert -O vhdx {0} {1}'
outs, errs = ps.run(cmd.format(os.path.join(self.image_dir, qcow2_name), os.path.join(self.image_dir, vhdx_name)))
@@ -59,9 +59,9 @@ class WinImageHandler(object):
# Record local image
img_dict['status'] = constants.IMAGE_STATUS_READY
img_dict['path'] = os.path.join(self.image_dir, vhdx_name)
- images['local'][img_to_download] = img_dict
- omni_utils.save_json_data(self.image_record_file, images)
- self.LOG.debug(f'Image: {img_to_download} is ready ...')
+ images['local'][image_to_download] = img_dict
+ utils.save_json_data(self.image_record_file, images)
+ self.LOG.debug(f'Image: {image_to_download} is ready ...')
def delete_image(self, images, img_to_delete):
if img_to_delete not in images['local'].keys():
@@ -77,7 +77,7 @@ class WinImageHandler(object):
self.LOG.debug(f'Deleting: {img_to_delete} from image database ...')
del images['local'][img_to_delete]
- omni_utils.save_json_data(self.image_record_file, images)
+ utils.save_json_data(self.image_record_file, images)
return 0
@@ -92,7 +92,7 @@ class WinImageHandler(object):
image.location = constants.IMAGE_LOCATION_LOCAL
image.status = constants.IMAGE_STATUS_LOADING
images['local'][image.name] = image.to_dict()
- omni_utils.save_json_data(self.image_record_file, images)
+ utils.save_json_data(self.image_record_file, images)
if fmt == 'qcow2':
qcow2_name = f'{img_to_load}.qcow2'
@@ -119,5 +119,5 @@ class WinImageHandler(object):
image.path = os.path.join(self.image_dir, vhdx_name)
image.status = constants.IMAGE_STATUS_READY
images['local'][image.name] = image.to_dict()
- omni_utils.save_json_data(self.image_record_file, images)
+ utils.save_json_data(self.image_record_file, images)
self.LOG.debug(f'Image: {vhdx_name} is ready ...')
diff --git a/eulerlauncher/backends/win/instance_handler.py b/eulerlauncher/backends/win/instance_handler.py
index 7b27055300490a449c7efdfa61fdb997e03cc2c0..c8c975f388d2c6108352d600ec94a1959f3c820b 100644
--- a/eulerlauncher/backends/win/instance_handler.py
+++ b/eulerlauncher/backends/win/instance_handler.py
@@ -9,7 +9,7 @@ from os_win import exceptions as os_win_exc
from eulerlauncher.backends.win import powershell
from eulerlauncher.backends.win import vmops
from eulerlauncher.utils import constants
-from eulerlauncher.utils import utils as omni_utils
+from eulerlauncher.utils import utils
from eulerlauncher.utils import objs
@@ -73,7 +73,7 @@ class WinInstanceHandler(object):
}
all_instances['instances'][name] = instance_record_dict
- omni_utils.save_json_data(instance_record, all_instances)
+ utils.save_json_data(instance_record, all_instances)
return {
'name': name,
@@ -91,7 +91,7 @@ class WinInstanceHandler(object):
shutil.rmtree(instance_dir)
del all_instances['instances'][name]
- omni_utils.save_json_data(instance_record, all_instances)
+ utils.save_json_data(instance_record, all_instances)
return 0
diff --git a/eulerlauncher/backends/win/vmops.py b/eulerlauncher/backends/win/vmops.py
index b8e4c75d4193bf3e7a807104b25b580bf98c27ae..618a8732f134cf17778f1cbd227d86ba5688c4d9 100644
--- a/eulerlauncher/backends/win/vmops.py
+++ b/eulerlauncher/backends/win/vmops.py
@@ -8,7 +8,7 @@ from oslo_utils import uuidutils
from eulerlauncher.utils import objs
from eulerlauncher.utils import constants
-from eulerlauncher.utils import utils as omni_utils
+from eulerlauncher.utils import utils
from eulerlauncher.backends.win import powershell
SWITCH_NAME = 'Default Switch'
@@ -83,7 +83,7 @@ class VMOps(object):
def get_instance_ip_addr(self, instance_name):
nic_name = instance_name + '_eth0'
nic = self.get_vm_nics(instance_name, nic_name)
- mac_address = omni_utils.format_mac_addr(nic.Address)
+ mac_address = utils.format_mac_addr(nic.Address)
with powershell.PowerShell('GBK') as ps:
outs, errs = ps.run('arp -a | findstr /i {}'.format(mac_address))
ip_address = outs.strip(' ').split(' ')[0]
diff --git a/eulerlauncher/cli.py b/eulerlauncher/cli.py
index 56972a1573780b1c5660695f3e7a3cc55009d430..ecf86e78fa078987c4f0b478cd0d2f15700c4b75 100644
--- a/eulerlauncher/cli.py
+++ b/eulerlauncher/cli.py
@@ -110,20 +110,7 @@ def launch(vm_name, image):
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.group()
diff --git a/eulerlauncher/eulerlauncherd.py b/eulerlauncher/eulerlauncherd.py
index 4bd0be7542a1457d53209c23dc5428ae0fb9b252..b7099502f8947790664d8caa019ab62d8034dcf3 100644
--- a/eulerlauncher/eulerlauncherd.py
+++ b/eulerlauncher/eulerlauncherd.py
@@ -1,5 +1,4 @@
import argparse
-from concurrent import futures
import grpc
import logging
import os
@@ -8,13 +7,14 @@ import platform
import pystray
import requests
import signal
-import subprocess
import sys
import time
+from concurrent import futures
+
from eulerlauncher.grpcs.eulerlauncher_grpc import images_pb2, images_pb2_grpc
from eulerlauncher.grpcs.eulerlauncher_grpc import instances_pb2, instances_pb2_grpc
-from eulerlauncher.services import imager_service, instance_service
+from eulerlauncher.services import image_service, instance_service
from eulerlauncher.utils import constants
from eulerlauncher.utils import objs
from eulerlauncher.utils import utils
@@ -29,10 +29,8 @@ if host_os_raw != 'Windows':
parser = argparse.ArgumentParser()
parser.add_argument('conf_file', help='Configuration file for the application', type=str)
-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')
@@ -50,26 +48,27 @@ 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')
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')
LOG.debug('Initializing EulerLauncherd ...')
LOG.debug('Checking for work directory ...')
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': {}
}
utils.save_json_data(instance_record_file, instances)
@@ -77,36 +76,34 @@ def init(arch, config, LOG):
if not os.path.exists(image_dir):
LOG.debug('Create %s as image directory ...' % image_dir)
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)
-
-def serve(arch, host_os, CONF, LOG, base_dir):
+ 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)
+
+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)
- 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
@@ -121,10 +118,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
@@ -133,13 +130,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__':
@@ -147,35 +140,29 @@ if __name__ == '__main__':
if host_os_raw != 'Windows':
args = parser.parse_args()
conf_file = args.conf_file
- base_dir = args.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))
+
+ if host_os_raw != 'Windows':
+ init_launcherd(conf_file)
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)
- ))
+ try:
+ logo = PIL.Image.open(os.path.join(os.getcwd(), 'etc', 'favicon.png'))
- except Exception as e:
- print('Error: ' + str(e))
- sys.exit(0)
-
- server = init_launcherd(conf_file, base_dir)
+ def on_clicked(icon, item):
+ icon.stop()
+
+ icon = pystray.Icon('EulerLauncher', logo, menu=pystray.Menu(
+ pystray.MenuItem('Exit EulerLauncher', on_clicked)
+ ))
- icon.run()
- server.stop(None)
+ except Exception as e:
+ print('Error: ' + str(e))
sys.exit(0)
+
+ server = init_launcherd(conf_file)
+
+ icon.run()
+ server.stop(None)
+ sys.exit(0)
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/images.proto b/eulerlauncher/grpcs/eulerlauncher_grpc/images.proto
index 26996d9dfd1c61817d7d3fc9fbc077fe3b02136b..4812b707c06d520ae09f976a4382e8a110223bd4 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/images.proto
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/images.proto
@@ -22,7 +22,6 @@ message Image {
message ListImageRequest {
}
-
message ListImageResponse {
repeated Image images = 1;
}
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2.py b/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2.py
index 6b2f860ebc20149da3530d08e18adeca7a89c574..e42523ea849787a0178bb3c0befe05ce804a3812 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2.py
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2.py
@@ -1,11 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
# source: images.proto
+# Protobuf Python Version: 5.28.1
"""Generated protocol buffer code."""
-from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+ _runtime_version.Domain.PUBLIC,
+ 5,
+ 28,
+ 1,
+ '',
+ 'images.proto'
+)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,26 +26,26 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cimages.proto\x12\x08omnivirt\"7\n\x05Image\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x10\n\x08location\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\"\x12\n\x10ListImageRequest\"4\n\x11ListImageResponse\x12\x1f\n\x06images\x18\x01 \x03(\x0b\x32\x0f.omnivirt.Image\"$\n\x14\x44ownloadImageRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\".\n\x10LoadImageRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\"\"\n\x12\x44\x65leteImageRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"0\n\x14GeneralImageResponse\x12\x0b\n\x03ret\x18\x01 \x01(\r\x12\x0b\n\x03msg\x18\x02 \x01(\t2\xcc\x02\n\x10ImageGrpcService\x12H\n\x0blist_images\x12\x1a.omnivirt.ListImageRequest\x1a\x1b.omnivirt.ListImageResponse\"\x00\x12R\n\x0e\x64ownload_image\x12\x1e.omnivirt.DownloadImageRequest\x1a\x1e.omnivirt.GeneralImageResponse\"\x00\x12J\n\nload_image\x12\x1a.omnivirt.LoadImageRequest\x1a\x1e.omnivirt.GeneralImageResponse\"\x00\x12N\n\x0c\x64\x65lete_image\x12\x1c.omnivirt.DeleteImageRequest\x1a\x1e.omnivirt.GeneralImageResponse\"\x00\x42\x03\x80\x01\x01\x62\x06proto3')
-_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'images_pb2', globals())
-if _descriptor._USE_C_DESCRIPTORS == False:
-
- DESCRIPTOR._options = None
- DESCRIPTOR._serialized_options = b'\200\001\001'
- _IMAGE._serialized_start=26
- _IMAGE._serialized_end=81
- _LISTIMAGEREQUEST._serialized_start=83
- _LISTIMAGEREQUEST._serialized_end=101
- _LISTIMAGERESPONSE._serialized_start=103
- _LISTIMAGERESPONSE._serialized_end=155
- _DOWNLOADIMAGEREQUEST._serialized_start=157
- _DOWNLOADIMAGEREQUEST._serialized_end=193
- _LOADIMAGEREQUEST._serialized_start=195
- _LOADIMAGEREQUEST._serialized_end=241
- _DELETEIMAGEREQUEST._serialized_start=243
- _DELETEIMAGEREQUEST._serialized_end=277
- _GENERALIMAGERESPONSE._serialized_start=279
- _GENERALIMAGERESPONSE._serialized_end=327
- _IMAGEGRPCSERVICE._serialized_start=330
- _IMAGEGRPCSERVICE._serialized_end=662
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'images_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+ _globals['DESCRIPTOR']._loaded_options = None
+ _globals['DESCRIPTOR']._serialized_options = b'\200\001\001'
+ _globals['_IMAGE']._serialized_start=26
+ _globals['_IMAGE']._serialized_end=81
+ _globals['_LISTIMAGEREQUEST']._serialized_start=83
+ _globals['_LISTIMAGEREQUEST']._serialized_end=101
+ _globals['_LISTIMAGERESPONSE']._serialized_start=103
+ _globals['_LISTIMAGERESPONSE']._serialized_end=155
+ _globals['_DOWNLOADIMAGEREQUEST']._serialized_start=157
+ _globals['_DOWNLOADIMAGEREQUEST']._serialized_end=193
+ _globals['_LOADIMAGEREQUEST']._serialized_start=195
+ _globals['_LOADIMAGEREQUEST']._serialized_end=241
+ _globals['_DELETEIMAGEREQUEST']._serialized_start=243
+ _globals['_DELETEIMAGEREQUEST']._serialized_end=277
+ _globals['_GENERALIMAGERESPONSE']._serialized_start=279
+ _globals['_GENERALIMAGERESPONSE']._serialized_end=327
+ _globals['_IMAGEGRPCSERVICE']._serialized_start=330
+ _globals['_IMAGEGRPCSERVICE']._serialized_end=662
# @@protoc_insertion_point(module_scope)
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2_grpc.py b/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2_grpc.py
index 28eb2df9c2085b818c685fe2958f4ffc8bc90904..ad44875a6cfc29f7b8a4cc02331806443ed57cbc 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2_grpc.py
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2_grpc.py
@@ -4,6 +4,25 @@ import grpc
from eulerlauncher.grpcs.eulerlauncher_grpc import images_pb2 as images__pb2
+GRPC_GENERATED_VERSION = '1.68.0'
+GRPC_VERSION = grpc.__version__
+_version_not_supported = False
+
+try:
+ from grpc._utilities import first_version_is_lower
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
+except ImportError:
+ _version_not_supported = True
+
+if _version_not_supported:
+ raise RuntimeError(
+ f'The grpc package installed is at version {GRPC_VERSION},'
+ + f' but the generated code in images_pb2_grpc.py depends on'
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
+ )
+
class ImageGrpcServiceStub(object):
"""Missing associated documentation comment in .proto file."""
@@ -18,22 +37,22 @@ class ImageGrpcServiceStub(object):
'/omnivirt.ImageGrpcService/list_images',
request_serializer=images__pb2.ListImageRequest.SerializeToString,
response_deserializer=images__pb2.ListImageResponse.FromString,
- )
+ _registered_method=True)
self.download_image = channel.unary_unary(
'/omnivirt.ImageGrpcService/download_image',
request_serializer=images__pb2.DownloadImageRequest.SerializeToString,
response_deserializer=images__pb2.GeneralImageResponse.FromString,
- )
+ _registered_method=True)
self.load_image = channel.unary_unary(
'/omnivirt.ImageGrpcService/load_image',
request_serializer=images__pb2.LoadImageRequest.SerializeToString,
response_deserializer=images__pb2.GeneralImageResponse.FromString,
- )
+ _registered_method=True)
self.delete_image = channel.unary_unary(
'/omnivirt.ImageGrpcService/delete_image',
request_serializer=images__pb2.DeleteImageRequest.SerializeToString,
response_deserializer=images__pb2.GeneralImageResponse.FromString,
- )
+ _registered_method=True)
class ImageGrpcServiceServicer(object):
@@ -90,6 +109,7 @@ def add_ImageGrpcServiceServicer_to_server(servicer, server):
generic_handler = grpc.method_handlers_generic_handler(
'omnivirt.ImageGrpcService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
+ server.add_registered_method_handlers('omnivirt.ImageGrpcService', rpc_method_handlers)
# This class is part of an EXPERIMENTAL API.
@@ -107,11 +127,21 @@ class ImageGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- return grpc.experimental.unary_unary(request, target, '/omnivirt.ImageGrpcService/list_images',
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/omnivirt.ImageGrpcService/list_images',
images__pb2.ListImageRequest.SerializeToString,
images__pb2.ListImageResponse.FromString,
- options, channel_credentials,
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def download_image(request,
@@ -124,11 +154,21 @@ class ImageGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- return grpc.experimental.unary_unary(request, target, '/omnivirt.ImageGrpcService/download_image',
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/omnivirt.ImageGrpcService/download_image',
images__pb2.DownloadImageRequest.SerializeToString,
images__pb2.GeneralImageResponse.FromString,
- options, channel_credentials,
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def load_image(request,
@@ -141,11 +181,21 @@ class ImageGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- return grpc.experimental.unary_unary(request, target, '/omnivirt.ImageGrpcService/load_image',
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/omnivirt.ImageGrpcService/load_image',
images__pb2.LoadImageRequest.SerializeToString,
images__pb2.GeneralImageResponse.FromString,
- options, channel_credentials,
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def delete_image(request,
@@ -158,8 +208,18 @@ class ImageGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- return grpc.experimental.unary_unary(request, target, '/omnivirt.ImageGrpcService/delete_image',
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/omnivirt.ImageGrpcService/delete_image',
images__pb2.DeleteImageRequest.SerializeToString,
images__pb2.GeneralImageResponse.FromString,
- options, channel_credentials,
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2.py b/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2.py
index 9877833f058ff6798506e937cee9f7ce7d1e555e..be819a1b61a9a7cd6efa29690682c5ea83171952 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2.py
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2.py
@@ -1,11 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
+# NO CHECKED-IN PROTOBUF GENCODE
# source: instances.proto
+# Protobuf Python Version: 5.28.1
"""Generated protocol buffer code."""
-from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import runtime_version as _runtime_version
from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+_runtime_version.ValidateProtobufRuntimeVersion(
+ _runtime_version.Domain.PUBLIC,
+ 5,
+ 28,
+ 1,
+ '',
+ 'instances.proto'
+)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,26 +26,26 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0finstances.proto\x12\x08omnivirt\"M\n\x08Instance\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05image\x18\x02 \x01(\t\x12\x10\n\x08vm_state\x18\x03 \x01(\t\x12\x12\n\nip_address\x18\x04 \x01(\t\"\x16\n\x14ListInstancesRequest\">\n\x15ListInstancesResponse\x12%\n\tinstances\x18\x01 \x03(\x0b\x32\x12.omnivirt.Instance\"4\n\x15\x43reateInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05image\x18\x02 \x01(\t\"j\n\x16\x43reateInstanceResponse\x12\x0b\n\x03ret\x18\x01 \x01(\r\x12\x0b\n\x03msg\x18\x02 \x01(\t\x12)\n\x08instance\x18\x03 \x01(\x0b\x32\x12.omnivirt.InstanceH\x00\x88\x01\x01\x42\x0b\n\t_instance\"%\n\x15\x44\x65leteInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"2\n\x16\x44\x65leteInstanceResponse\x12\x0b\n\x03ret\x18\x01 \x01(\r\x12\x0b\n\x03msg\x18\x02 \x01(\t2\x9a\x02\n\x13InstanceGrpcService\x12S\n\x0elist_instances\x12\x1e.omnivirt.ListInstancesRequest\x1a\x1f.omnivirt.ListInstancesResponse\"\x00\x12V\n\x0f\x63reate_instance\x12\x1f.omnivirt.CreateInstanceRequest\x1a .omnivirt.CreateInstanceResponse\"\x00\x12V\n\x0f\x64\x65lete_instance\x12\x1f.omnivirt.DeleteInstanceRequest\x1a .omnivirt.DeleteInstanceResponse\"\x00\x42\x03\x80\x01\x01\x62\x06proto3')
-_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
-_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'instances_pb2', globals())
-if _descriptor._USE_C_DESCRIPTORS == False:
-
- DESCRIPTOR._options = None
- DESCRIPTOR._serialized_options = b'\200\001\001'
- _INSTANCE._serialized_start=29
- _INSTANCE._serialized_end=106
- _LISTINSTANCESREQUEST._serialized_start=108
- _LISTINSTANCESREQUEST._serialized_end=130
- _LISTINSTANCESRESPONSE._serialized_start=132
- _LISTINSTANCESRESPONSE._serialized_end=194
- _CREATEINSTANCEREQUEST._serialized_start=196
- _CREATEINSTANCEREQUEST._serialized_end=248
- _CREATEINSTANCERESPONSE._serialized_start=250
- _CREATEINSTANCERESPONSE._serialized_end=356
- _DELETEINSTANCEREQUEST._serialized_start=358
- _DELETEINSTANCEREQUEST._serialized_end=395
- _DELETEINSTANCERESPONSE._serialized_start=397
- _DELETEINSTANCERESPONSE._serialized_end=447
- _INSTANCEGRPCSERVICE._serialized_start=450
- _INSTANCEGRPCSERVICE._serialized_end=732
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'instances_pb2', _globals)
+if not _descriptor._USE_C_DESCRIPTORS:
+ _globals['DESCRIPTOR']._loaded_options = None
+ _globals['DESCRIPTOR']._serialized_options = b'\200\001\001'
+ _globals['_INSTANCE']._serialized_start=29
+ _globals['_INSTANCE']._serialized_end=106
+ _globals['_LISTINSTANCESREQUEST']._serialized_start=108
+ _globals['_LISTINSTANCESREQUEST']._serialized_end=130
+ _globals['_LISTINSTANCESRESPONSE']._serialized_start=132
+ _globals['_LISTINSTANCESRESPONSE']._serialized_end=194
+ _globals['_CREATEINSTANCEREQUEST']._serialized_start=196
+ _globals['_CREATEINSTANCEREQUEST']._serialized_end=248
+ _globals['_CREATEINSTANCERESPONSE']._serialized_start=250
+ _globals['_CREATEINSTANCERESPONSE']._serialized_end=356
+ _globals['_DELETEINSTANCEREQUEST']._serialized_start=358
+ _globals['_DELETEINSTANCEREQUEST']._serialized_end=395
+ _globals['_DELETEINSTANCERESPONSE']._serialized_start=397
+ _globals['_DELETEINSTANCERESPONSE']._serialized_end=447
+ _globals['_INSTANCEGRPCSERVICE']._serialized_start=450
+ _globals['_INSTANCEGRPCSERVICE']._serialized_end=732
# @@protoc_insertion_point(module_scope)
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2_grpc.py b/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2_grpc.py
index 970781c046dbdda278277ff639fd0e0addcb983a..bfef0dbbebf50665145e3ca6cd8a8da33eb45514 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2_grpc.py
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2_grpc.py
@@ -4,6 +4,25 @@ import grpc
from eulerlauncher.grpcs.eulerlauncher_grpc import instances_pb2 as instances__pb2
+GRPC_GENERATED_VERSION = '1.68.0'
+GRPC_VERSION = grpc.__version__
+_version_not_supported = False
+
+try:
+ from grpc._utilities import first_version_is_lower
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
+except ImportError:
+ _version_not_supported = True
+
+if _version_not_supported:
+ raise RuntimeError(
+ f'The grpc package installed is at version {GRPC_VERSION},'
+ + f' but the generated code in instances_pb2_grpc.py depends on'
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
+ )
+
class InstanceGrpcServiceStub(object):
"""Missing associated documentation comment in .proto file."""
@@ -18,17 +37,17 @@ class InstanceGrpcServiceStub(object):
'/omnivirt.InstanceGrpcService/list_instances',
request_serializer=instances__pb2.ListInstancesRequest.SerializeToString,
response_deserializer=instances__pb2.ListInstancesResponse.FromString,
- )
+ _registered_method=True)
self.create_instance = channel.unary_unary(
'/omnivirt.InstanceGrpcService/create_instance',
request_serializer=instances__pb2.CreateInstanceRequest.SerializeToString,
response_deserializer=instances__pb2.CreateInstanceResponse.FromString,
- )
+ _registered_method=True)
self.delete_instance = channel.unary_unary(
'/omnivirt.InstanceGrpcService/delete_instance',
request_serializer=instances__pb2.DeleteInstanceRequest.SerializeToString,
response_deserializer=instances__pb2.DeleteInstanceResponse.FromString,
- )
+ _registered_method=True)
class InstanceGrpcServiceServicer(object):
@@ -74,6 +93,7 @@ def add_InstanceGrpcServiceServicer_to_server(servicer, server):
generic_handler = grpc.method_handlers_generic_handler(
'omnivirt.InstanceGrpcService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
+ server.add_registered_method_handlers('omnivirt.InstanceGrpcService', rpc_method_handlers)
# This class is part of an EXPERIMENTAL API.
@@ -91,11 +111,21 @@ class InstanceGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- return grpc.experimental.unary_unary(request, target, '/omnivirt.InstanceGrpcService/list_instances',
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/omnivirt.InstanceGrpcService/list_instances',
instances__pb2.ListInstancesRequest.SerializeToString,
instances__pb2.ListInstancesResponse.FromString,
- options, channel_credentials,
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def create_instance(request,
@@ -108,11 +138,21 @@ class InstanceGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- return grpc.experimental.unary_unary(request, target, '/omnivirt.InstanceGrpcService/create_instance',
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/omnivirt.InstanceGrpcService/create_instance',
instances__pb2.CreateInstanceRequest.SerializeToString,
instances__pb2.CreateInstanceResponse.FromString,
- options, channel_credentials,
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def delete_instance(request,
@@ -125,8 +165,18 @@ class InstanceGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- return grpc.experimental.unary_unary(request, target, '/omnivirt.InstanceGrpcService/delete_instance',
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/omnivirt.InstanceGrpcService/delete_instance',
instances__pb2.DeleteInstanceRequest.SerializeToString,
instances__pb2.DeleteInstanceResponse.FromString,
- options, channel_credentials,
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
diff --git a/eulerlauncher/macos-gui.py b/eulerlauncher/macos-gui.py
index 3562e4f6db2f6a590aa21af157161104c6efda4d..31216867462957c0f6a7110bceba91020386ef04 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 0000000000000000000000000000000000000000..a16868395f35403a00349e5ca4ecdcfeaac64be4
--- /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 0d1fb8eb82d23aa81d1b05117536a59856cc39e9..0000000000000000000000000000000000000000
--- a/eulerlauncher/services/imager_service.py
+++ /dev/null
@@ -1,106 +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 omni_constants
-from eulerlauncher.utils import utils as omni_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 = omni_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']
- 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 = omni_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 valid for download, please check image name from REMOTE IMAGE LIST using "images" command ...'
- return images_pb2.GeneralImageResponse(ret=1, msg=msg)
-
- @omni_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 = omni_utils.check_file_tail(
- request.path, omni_constants.IMAGE_LOAD_SUPPORTED_TYPES)
-
- if not supported:
- supported_fmt = ', '.join(omni_constants.IMAGE_LOAD_SUPPORTED_TYPES)
- msg = f'Unsupported image format, the current supported format are: {supported_fmt}.'
-
- return images_pb2.GeneralImageResponse(ret=1, msg=msg)
-
- all_images = omni_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
-
- @omni_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 = omni_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 bea002e913f7bceab9ce1b0dea845477c430938b..47267a275722dcf80eba2188053e9aa8ff399096 100644
--- a/eulerlauncher/services/instance_service.py
+++ b/eulerlauncher/services/instance_service.py
@@ -1,81 +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.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.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} ...")
-
- 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)
-
- 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)
- 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():
+ 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.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)
+ return instances_pb2.DeleteInstanceResponse(ret=ret, msg=msg)
diff --git a/eulerlauncher/utils/constants.py b/eulerlauncher/utils/constants.py
index 9383d2d5f2d0edf75c689631eb017ec0d846b989..0be17e80e361a55e323f52239a6ca1528a55954a 100644
--- a/eulerlauncher/utils/constants.py
+++ b/eulerlauncher/utils/constants.py
@@ -22,14 +22,17 @@ 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'
- }
+}
OS_MAP = {
'Darwin': 'MacOS',
diff --git a/eulerlauncher/utils/objs.py b/eulerlauncher/utils/objs.py
index 714e26d3247e638c9c7748080bb0550d2f9006d5..55c90a912aa3042a1ba031c284b1175978c5a47b 100644
--- a/eulerlauncher/utils/objs.py
+++ b/eulerlauncher/utils/objs.py
@@ -2,47 +2,6 @@ import os
import configparser
from eulerlauncher.utils import exceptions
-from eulerlauncher.utils import constants
-
-class Instance(object):
-
- def __init__(self, name='') -> None:
- self.name = name
- self.uuid = ''
- self.identifier = {}
- self.metadata = None
- self.vm_state = None
- self.vcpu = None
- self.ram = None
- self.disk = None
- self.info = None
- self.image = None
- self.ip = 'N/A'
- self.mac = 'N/A'
-
-
-class Image(object):
-
- def __init__(self) -> None:
- self.name = ''
- self.location = ''
- self.status = constants.IMAGE_STATUS_INIT
- self.path = ''
-
- def to_dict(self):
- image_dict = {
- 'name': self.name,
- 'location': self.location,
- 'status': self.status,
- 'path': self.path
- }
- return image_dict
-
- def from_dict(self, img_dict):
- self.name = img_dict['name']
- self.location = img_dict['location']
- self.status = img_dict['status']
- self.path = img_dict['path']
class Conf(object):
diff --git a/eulerlauncher/utils/utils.py b/eulerlauncher/utils/utils.py
index 8381c74aaddaa9d9418fdc9e08dfa1c014ab1e7b..190baa8634a0d123164734142a9f3ef4c7b6b939 100644
--- a/eulerlauncher/utils/utils.py
+++ b/eulerlauncher/utils/utils.py
@@ -3,6 +3,7 @@ import json
import os
import random
from threading import Thread
+from lxml import etree
import uuid
@@ -52,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:]
diff --git a/requirements-win.txt b/requirements-win.txt
index b67b36dc4415cf837515d153a8423b9e6e45fb9a..2de7fd5ab6ee2ef0f44f32a2db1ad6182528529a 100644
--- a/requirements-win.txt
+++ b/requirements-win.txt
@@ -22,3 +22,4 @@ PyYAML
six
urllib3
wget
+libvirt-python
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index db5e0f68c92003b71fc38050787376e243cb4a4a..07ff4f2eb6b253cd04fcdc434bbc5fc699f7a7f4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -14,7 +14,7 @@ oslo.i18n
oslo.log
oslo.serialization
oslo.utils
-Pillow
+pillow
prettytable
protobuf
psutil
@@ -23,3 +23,4 @@ PyYAML
six
urllib3
wget
+libvirt-python
\ No newline at end of file
diff --git a/resources/.DS_Store b/resources/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..431a59269701140d86619ca4654664d1ac2f222c
Binary files /dev/null and b/resources/.DS_Store differ
diff --git a/resources/libvirt/.DS_Store b/resources/libvirt/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..ae56b38ac304ba2a6311ecd6fa1e7df569669e4c
Binary files /dev/null and b/resources/libvirt/.DS_Store differ
diff --git a/resources/libvirt/libvirt-aarch64.xml b/resources/libvirt/libvirt-aarch64.xml
new file mode 100644
index 0000000000000000000000000000000000000000..822c77564a9d9a37b5b270aee84fb9aeabd5681a
--- /dev/null
+++ b/resources/libvirt/libvirt-aarch64.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ hvm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/libvirt/libvirt-x86_64.xml b/resources/libvirt/libvirt-x86_64.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7e711cee9f607f8d932166b95094f62a62531271
--- /dev/null
+++ b/resources/libvirt/libvirt-x86_64.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+ hvm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/qemu/edk2-aarch64-code.fd b/resources/qemu/edk2-aarch64-code.fd
deleted file mode 100644
index 832bfe21451ce2a2cc71f7ad91a92d20a372e8cf..0000000000000000000000000000000000000000
Binary files a/resources/qemu/edk2-aarch64-code.fd and /dev/null differ
diff --git a/resources/qemu/edk2-x86_64-code.fd b/resources/qemu/edk2-x86_64-code.fd
deleted file mode 100644
index b1cb5da36aee2f9b3c243c721cd6e44ae36c121c..0000000000000000000000000000000000000000
Binary files a/resources/qemu/edk2-x86_64-code.fd and /dev/null differ
diff --git a/specs/EulerLauncher-MacOS.spec b/specs/EulerLauncher-Mac.spec
similarity index 84%
rename from specs/EulerLauncher-MacOS.spec
rename to specs/EulerLauncher-Mac.spec
index 8952fca46ba4eb075a554fdcf7e45e50327179e3..50029630c88b065f148fc0ff7463b4f9e5adfbd6 100644
--- a/specs/EulerLauncher-MacOS.spec
+++ b/specs/EulerLauncher-Mac.spec
@@ -7,8 +7,8 @@ block_cipher = None
a = Analysis(
['../eulerlauncher/macos-gui.py'],
pathex=[],
- binaries=[('../dist/EulerLauncherd', './bin')],
- datas=[('../etc/eulerlauncher.conf', './etc'), ('../etc/images/favicon.png', './etc'), ('../resources/qemu/edk2-aarch64-code.fd', './etc'), ('../resources/qemu/edk2-x86_64-code.fd', './etc')],
+ binaries=[('../dist/eulerLauncherd', './bin')],
+ datas=[('../etc/eulerlauncher.conf', './etc'), ('../etc/images/favicon.png', './etc'), ('../resources/libvirt/libvirt-aarch64.xml', './etc'), ('../resources/libvirt/libvirt-x86_64.xml', './etc')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
diff --git a/specs/EulerLauncherd-Mac.spec b/specs/EulerLauncherd-Mac.spec
index 9dbbc2894fc5bbdf7c38e5c54af73e6436e1242f..75efb54821eccaaf1fedf80606f0f695bf03745b 100644
--- a/specs/EulerLauncherd-Mac.spec
+++ b/specs/EulerLauncherd-Mac.spec
@@ -28,7 +28,7 @@ exe = EXE(
a.zipfiles,
a.datas,
[],
- name='EulerLauncherd',
+ name='eulerlauncherd',
debug=False,
bootloader_ignore_signals=False,
strip=False,
diff --git a/specs/install.spec b/specs/install.spec
index ae6258c6c45689a26a4f2a5bbb089c7963ec2e08..97e503fcf87b86d529e1fee161b72aabb3abb954 100644
--- a/specs/install.spec
+++ b/specs/install.spec
@@ -8,7 +8,7 @@ a = Analysis(
['../eulerlauncher/install.py'],
pathex=[],
binaries=[('../dist/eulerlauncher', './etc')],
- datas=[('../etc/eulerlauncher.conf', './etc'), ('../resources/qemu/edk2-aarch64-code.fd', './etc'), ('../resources/qemu/edk2-x86_64-code.fd', './etc')],
+ datas=[('../etc/eulerlauncher.conf', './etc'), ('../resources/libvirt/libvirt-aarch64.xml', './etc'), ('../resources/libvirt/libvirt-x86_64.xml', './etc')],
hiddenimports=[],
hookspath=[],
hooksconfig={},