diff --git a/.gitignore b/.gitignore
index 7c9d0f2ebe2b0f9c6cf7986c8a2ec63695701469..0f5908931a247c2cdd3af168aa29e182a601f1a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,12 +26,12 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
+.DS_Store
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
-*.spec
# Installer logs
pip-log.txt
diff --git a/docs/developer-manual.md b/docs/developer-manual.md
index 01ff36e4963a68ca89d89007414817be9ad1fee6..ae88c758e3017e831bb04e822e9929e8437283d2 100644
--- a/docs/developer-manual.md
+++ b/docs/developer-manual.md
@@ -64,7 +64,7 @@ EulerLauncher可执行文件包括以下几个部分:
项目源码中已包含用于构建EulerLauncher的Spec脚本`EulerLauncher-MacOS.spec`, 若非必要,请勿修改该文件,使用一下命令开始构建:
``` Shell
- pyinstaller --clean --noconfirm specs/EulerLauncher-MacOS.spec
+ pyinstaller --clean --noconfirm specs/EulerLauncher-Mac.spec
```
构建`eulerlauncher` CLI 及 `install` 脚本, cli与install之间有依赖关系,请严格按照下面的顺序进行构建:
diff --git a/docs/mac-user-manual.md b/docs/mac-user-manual.md
index f7d5771451beea723b5a921b66090329ebfb7b05..74f6b1a24c31109ba76d8ec9db8d84c3714b7e44 100644
--- a/docs/mac-user-manual.md
+++ b/docs/mac-user-manual.md
@@ -23,11 +23,14 @@ Homebrew是一款Mac OS平台下的软件包管理工具,拥有安装、卸载
### 安装Qemu及wget
-**EulerLauncher**在MacOS上运行依赖于`QEMU`,镜像下载依赖于`wget`,使用`Homebrew`可以非常方便的下载和管理此类软件,使用以下命令进行安装:
+**EulerLauncher**在MacOS上运行依赖于`QEMU`和`libvirt`,镜像下载依赖于`wget`,使用`Homebrew`可以非常方便的下载和管理此类软件,使用以下命令进行安装:
``` Shell
brew install qemu
brew install wget
+brew install libvirt
+brew tap jeffreywildman/homebrew-virt-manager
+brew install virt-viewer
```
### 配置sudo免密码权限
@@ -58,18 +61,6 @@ brew install wget
2. 配置**EulerLauncher**:
- - 查看`qemu`及`wget`所处位置,`qemu`二进制文件在不同架构下名称不同,请根据自身情况选择正确的名称(Apple Silicon: qemu-system-aarch64; Intel: qemu-system-x86_64):
- ``` Shell
- which wget
- which qemu-system-{host_arch}
- ```
- 参考输出:
- ```
- /opt/homebrew/bin/wget
- /opt/homebrew/bin/qemu-system-aarch64
- ```
- 查看完成后,记录路径结果,在接下来的步骤中将会使用到。
-
- 打开`eulerlauncher.conf`并进行配置:
``` Shell
sudo vi /Library/Application\ Support/org.openeuler.eulerlauncher/eulerlauncher.conf
@@ -80,8 +71,6 @@ brew install wget
[default]
log_dir = # 日志文件位置(xxx.log)
work_dir = # eulerlauncher工作目录,用于存储虚拟机镜像、虚拟机文件等
- wget_dir = # wget的可执行文件路径,请参考上一步的内容进行配置
- qemu_dir = # qemu的可执行文件路径,请参考上一步的内容进行配置
debug = True
[vm]
@@ -125,7 +114,7 @@ eulerlauncher images
2. 下载远端镜像
```Shell
-eulerlauncher download-image 22.03-LTS
+eulerlauncher image download 22.03-LTS
Downloading: 22.03-LTS, this might take a while, please check image status with "images" command.
```
@@ -133,7 +122,7 @@ Downloading: 22.03-LTS, this might take a while, please check image status with
镜像下载请求是一个异步请求,具体的下载动作将在后台完成,具体耗时与你的网络情况相关,整体的镜像下载流程包括下载、解压缩、格式转换等相关子流程,在下载过程中可以通过 `image` 命令随时查看下载进展与镜像状态:
```Shell
-eulerlauncher images
+eulerlauncher image list
+-----------+----------+--------------+
| Images | Location | Status |
@@ -148,7 +137,7 @@ eulerlauncher images
当镜像状态转变为 `Ready` 时,表示镜像下载完成,处于 `Ready` 状态的镜像可被用来创建虚拟机:
```Shell
-eulerlauncher images
+eulerlauncher image list
+-----------+----------+--------------+
| Images | Location | Status |
@@ -164,7 +153,7 @@ eulerlauncher images
用户也可以加载自定义镜像或预先下载到本地的镜像到EulerLauncher中用于创建自定义虚拟机:
```Shell
-eulerlauncher load-image --path {image_file_path} IMAGE_NAME
+eulerlauncher image load --path {image_file_path} IMAGE_NAME
```
当前支持加载的镜像格式有 `xxx.qcow2.xz`,`xxx.qcow2`
@@ -172,7 +161,7 @@ eulerlauncher load-image --path {image_file_path} IMAGE_NAME
例如:
```Shell
-eulerlauncher load-image --path /opt/openEuler-22.03-LTS-x86_64.qcow2.xz 2203-load
+eulerlauncher image load --path /opt/openEuler-22.03-LTS-x86_64.qcow2.xz 2203-load
Loading: 2203-load, this might take a while, please check image status with "images" command.
```
@@ -180,7 +169,7 @@ Loading: 2203-load, this might take a while, please check image status with "ima
将位于 `/opt` 目录下的 `openEuler-22.03-LTS-x86_64.qcow2.xz` 加载到EulerLauncher系统中,并命名为 `2203-load`,与下载命令一样,加载命令也是一个异步命令,用户需要用镜像列表命令查询镜像状态直到显示为 `Ready`, 但相对于直接下载镜像,加载镜像的速度会快很多:
```Shell
-eulerlauncher images
+eulerlauncher image list
+-----------+----------+--------------+
| Images | Location | Status |
@@ -190,7 +179,7 @@ eulerlauncher images
| 2203-load | Local | Loading |
+-----------+----------+--------------+
-eulerlauncher images
+eulerlauncher image list
+-----------+----------+--------------+
| Images | Location | Status |
@@ -206,7 +195,7 @@ eulerlauncher images
通过下面的命令将镜像从EulerLauncher系统中删除:
```Shell
-eulerlauncher delete-image 2203-load
+eulerlauncher image delete 2203-load
Image: 2203-load has been successfully deleted.
```
@@ -216,7 +205,7 @@ Image: 2203-load has been successfully deleted.
1. 获取虚拟机列表:
```shell
-eulerlauncher list
+eulerlauncher instance list
+----------+-----------+---------+---------------+
| Name | Image | State | IP |
@@ -236,22 +225,38 @@ eulerlauncher list
```Shell
ssh root@{instance_ip}
```
+
若使用的是openEuler社区提供的官方镜像,则默认用户为 `root` 默认密码为 `openEuler12#$`
3. 创建虚拟机
```Shell
-eulerlauncher launch --image {image_name} {instance_name}
+eulerlauncher instance launch --image {image_name} {instance_name}
```
通过 `--image` 指定镜像,同时指定虚拟机名称。
4. 删除虚拟机
```Shell
-eulerlauncher delete-instance {instance_name}
+eulerlauncher instance delete {instance_name}
```
根据虚拟机名称删除指定的虚拟机。
+5. 暂停虚拟机
+```Shell
+eulerlauncher instance suspend {instance_name}
+```
+
+6. 恢复虚拟机
+```Shell
+eulerlauncher instance resume {instance_name}
+```
+
+7. 虚拟机控制台
+```Shell
+eulerlauncher instance console {instance_name}
+```
+
[1]: https://developer.apple.com/documentation/vmnet
[2]: https://gitee.com/openeuler/eulerlauncher/releases
\ No newline at end of file
diff --git a/etc/bin/config-env.bat b/etc/bin/config-env.bat
index b77e085b36775b692013a4e9f0047d10b9db221c..e39481017277140d79de2c6ea4a658cf6ca29640 100644
--- a/etc/bin/config-env.bat
+++ b/etc/bin/config-env.bat
@@ -1,8 +1,8 @@
@ECHO OFF
REM usage: append_system_path "path"
set CURR_DIR=%~dp0
-set QEMU_DIR=%~dp0qemu-img\
+set qemu_bin=%~dp0qemu-img\
SET Key="HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
FOR /F "usebackq tokens=2*" %%A IN (`REG QUERY %Key% /v PATH`) DO Set CurrPath=%%B
ECHO %CurrPath% > system_path_bak.txt
-SETX PATH "%CurrPath%";%CURR_DIR%;%QEMU_DIR% /m
\ No newline at end of file
+SETX PATH "%CurrPath%";%CURR_DIR%;%qemu_bin% /m
\ No newline at end of file
diff --git a/etc/eulerlauncher.conf b/etc/eulerlauncher.conf
index a101a510a7e4508fa09797c0573d0299cf152f04..66b2c0d284b2a317a6bd869588462a29324e0227 100644
--- a/etc/eulerlauncher.conf
+++ b/etc/eulerlauncher.conf
@@ -1,8 +1,6 @@
[default]
-log_dir =
-work_dir =
-wget_dir =
-qemu_dir =
+log_dir =
+work_dir =
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/backends/image_handler.py b/eulerlauncher/backends/image_handler.py
new file mode 100644
index 0000000000000000000000000000000000000000..4382fa2472e9bb7810edd8de7a608bab9ee07ec0
--- /dev/null
+++ b/eulerlauncher/backends/image_handler.py
@@ -0,0 +1,140 @@
+import lzma
+import wget
+import os
+import subprocess
+import shutil
+import ssl
+
+from eulerlauncher.utils import constants
+from eulerlauncher.utils import utils
+
+
+ssl._create_default_https_context = ssl._create_unverified_context
+
+
+class MacImageHandler(object):
+
+ 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_path = os.path.join(image_dir, 'images.json')
+ self.LOG = LOG
+
+
+ def list_images(self):
+ image_record = utils.load_json_data(self.image_record_path)
+ all_images = list(image_record["remote"].values()) + list(image_record["local"].values())
+ return all_images
+
+
+ def download_image(self, name):
+ image_record = utils.load_json_data(self.image_record_path)
+ 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_path)
+ image_url = image_record['remote'][name]['path']
+ image_file = wget.filename_from_url(image_url)
+ image_path = os.path.join(self.image_dir, image_file)
+
+ # 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_STATE_MAP[2],
+ 'path': image_url
+ }
+ utils.save_json_data(self.image_record_path, image_record)
+ wget_bin = shutil.which('wget_bin')
+ download_cmd = [wget_bin, image_url,
+ '-O', image_path,
+ '--no-check-certificate',
+ '--user-agent', 'Mozilla']
+ self.LOG.debug(' '.join(download_cmd))
+ subprocess.call(' '.join(download_cmd), shell=True)
+ self.LOG.debug(f'Image: {name} succesfully downloaded from remote repo ...')
+
+ # Decompress the image
+ self.LOG.debug(f'Decompressing image: {image_file} ...')
+ with open(image_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)
+
+ self.LOG.debug(f'Cleanup temp files ...')
+ os.remove(image_path)
+
+ # Record local image
+ image_record = utils.load_json_data(self.image_record_path)
+ image_record['local'][name]['status'] = constants.IMAGE_STATE_MAP[4]
+ image_record['local'][name]['path'] = os.path.join(self.image_dir, name)
+ utils.save_json_data(self.image_record_path, image_record)
+ self.LOG.debug(f'Image: {name} is ready ...')
+
+ download_and_transform(name)
+ return 0
+
+
+ def delete_image(self, name):
+ image_record = utils.load_json_data(self.image_record_path)
+ if name not in image_record['local'].keys():
+ self.LOG.debug(f'Image: {name} not valid for delete')
+ return 1
+
+ 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_path, image_record)
+ self.LOG.debug(f'Image: {name} succesfully deleted ...')
+ return 0
+
+
+ def load_image(self, name, path):
+ if not os.path.exists(path):
+ self.LOG.debug(f'Image: {path} does not exist')
+ return 1
+
+ supported, fmt = utils.check_format(path, constants.IMAGE_LOAD_SUPPORTED_TYPES)
+ if not supported:
+ self.LOG.debug(f'Image: {name} not valid for load')
+ return 2
+
+ @utils.asyncwrapper
+ def load_and_transform(name, path):
+ image_record = utils.load_json_data(self.image_record_path)
+ image_path = os.path.join(self.image_dir, name)
+ supported, fmt = utils.check_format(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_STATE_MAP[3],
+ 'path': ''
+ }
+ utils.save_json_data(self.image_record_path, image_record)
+
+ if fmt == 'qcow2':
+ shutil.copyfile(path, image_path)
+ else:
+ # Decompress the image
+ self.LOG.debug(f'Decompressing image file: {path} ...')
+ with open(path, 'rb') as pr, open(image_path, '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_path)
+ image_record['local'][name]['status'] = constants.IMAGE_STATE_MAP[4]
+ image_record['local'][name]['path'] = image_path
+ utils.save_json_data(self.image_record_path, 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/instance_handler.py b/eulerlauncher/backends/instance_handler.py
new file mode 100644
index 0000000000000000000000000000000000000000..844bddd731935b6d691b7925e53d97a1a7c12db9
--- /dev/null
+++ b/eulerlauncher/backends/instance_handler.py
@@ -0,0 +1,165 @@
+import os
+import libvirt
+import shutil
+import platform
+import subprocess
+
+from eulerlauncher.utils import constants
+from eulerlauncher.utils import utils
+
+class MacInstanceHandler(object):
+
+ 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_path = os.path.join(instance_dir, 'instances.json')
+ self.image_dir = image_dir
+ self.image_record_path = os.path.join(image_dir, 'images.json')
+ self.LOG = LOG
+
+
+ def list_instances(self):
+ instance_record = utils.load_json_data(self.instance_record_path)
+ all_instances = list(instance_record.values())
+ return all_instances
+
+
+ def create_instance(self, name, image):
+ image_record = utils.load_json_data(self.image_record_path)
+ if image not in image_record['local'].keys():
+ self.LOG.debug(f'Image: {image} is not available locally')
+ return 1
+
+ instance_record = utils.load_json_data(self.instance_record_path)
+ 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)
+ 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_path = os.path.join('/Library/Application Support/org.openeuler.eulerlauncher/','libvirt-' + host_arch + '.xml')
+ xml = utils.load_xml_data(xml_path)
+ vcpu = self.CONF.get('vm', 'cpu_num')
+ ram = self.CONF.get('vm', 'memory')
+ qemu_bin = shutil.which('qemu-system-aarch64')
+ mac_address = utils.generate_mac_address()
+
+ utils.xml_find_and_set(xml, 'name', value=name)
+ utils.xml_find_and_set(xml, 'vcpu', value=vcpu)
+ utils.xml_find_and_set(xml, 'memory', value=ram)
+ utils.xml_find_and_set(xml, 'devices/emulator', value=qemu_bin)
+ utils.xml_find_and_set(xml, 'devices/disk/source', 'file', disk_path)
+ qemu_arg = 'driver=virtio-net-pci,netdev=eth0,mac=' + mac_address
+ utils.xml_find_and_set(xml, 'qemu:commandline/qemu:arg[2]', 'value', qemu_arg)
+ utils.save_xml_data(xml_path, xml)
+
+ try:
+ conn = libvirt.open("qemu:///system")
+ with open(xml_path, 'r') as pr:
+ dom = conn.createLinux(pr.read())
+
+ with open(os.path.join(instance_path, name), 'w') as pw:
+ xml_dec = dom.XMLDesc()
+ pw.write(xml_dec)
+
+ ip_address = utils.parse_ip_address(mac_address)
+
+ instance_record[name] = {
+ 'id': dom.ID(),
+ 'name': name,
+ 'state': constants.INSTANCE_STATE_MAP[dom.state()[0]],
+ 'vcpu': vcpu,
+ 'ram': ram,
+ 'image': image,
+ 'mac_address': mac_address,
+ 'ip_address': ip_address,
+ 'path': instance_path
+ }
+ utils.save_json_data(self.instance_record_path, instance_record)
+ conn.close()
+ except Exception:
+ self.LOG.debug(f'Libvirt error creating instance: {name}')
+ shutil.rmtree(instance_path)
+ return 3
+ self.LOG.debug(f'Instance: {name} succesfully created ...')
+ return 0
+
+
+ def delete_instance(self, name):
+ instance_record = utils.load_json_data(self.instance_record_path)
+ if name not in instance_record.keys():
+ self.LOG.debug(f'Instance: {name} does not exist')
+ return 1
+
+ conn = libvirt.open("qemu:///system")
+ dom = conn.lookupByName(name)
+ dom.destroy()
+ # Cleanup files and records
+ instance_path = instance_record[name]['path']
+ shutil.rmtree(instance_path)
+ del instance_record[name]
+
+ utils.save_json_data(self.instance_record_path, instance_record)
+ conn.close()
+ self.LOG.debug(f'Instance: {name} succesfully killed ...')
+ return 0
+
+
+ def suspend_instance(self, name):
+ instance_record = utils.load_json_data(self.instance_record_path)
+ if name not in instance_record.keys():
+ self.LOG.debug(f'Instance: {name} does not exist')
+ return 1
+
+ conn = libvirt.open("qemu:///system")
+ dom = conn.lookupByName(name)
+ dom.suspend()
+
+ instance_record[name]['state'] = constants.INSTANCE_STATE_MAP[dom.state()[0]]
+
+ utils.save_json_data(self.instance_record_path, instance_record)
+ conn.close()
+ self.LOG.debug(f'Instance: {name} succesfully suspended ...')
+ return 0
+
+
+ def resume_instance(self, name):
+ instance_record = utils.load_json_data(self.instance_record_path)
+ if name not in instance_record.keys():
+ self.LOG.debug(f'Instance: {name} does not exist')
+ return 1
+
+ conn = libvirt.open("qemu:///system")
+ dom = conn.lookupByName(name)
+ dom.resume()
+
+ instance_record[name]['state'] = constants.INSTANCE_STATE_MAP[dom.state()[0]]
+
+ utils.save_json_data(self.instance_record_path, instance_record)
+ conn.close()
+ self.LOG.debug(f'Instance: {name} succesfully resumed ...')
+ return 0
+
+
+ def console_instance(self, name):
+ instance_record = utils.load_json_data(self.instance_record_path)
+ if name not in instance_record.keys():
+ self.LOG.debug(f'Instance: {name} does not exist')
+ return 1
+
+ # instance_path = instance_record[name]['path']
+ # xml_path = os.path.join(instance_path, name)
+ # xml = utils.load_xml_data(xml_path)
+ # address = utils.xml_find_and_set(xml, 'devices/graphics[@type="vnc"]/listen', "address")
+ # port = utils.xml_find_and_set(xml, 'devices/graphics[@type="vnc"]', "port")
+
+ virt_viewer_bin = shutil.which('virt-viewer')
+ virt_viewer_cmd = ['sudo', virt_viewer_bin, name]
+ subprocess.Popen(' '.join(virt_viewer_cmd), shell=True, preexec_fn=os.setsid)
+
+ return 0
\ No newline at end of file
diff --git a/eulerlauncher/backends/mac/image_handler.py b/eulerlauncher/backends/mac/image_handler.py
deleted file mode 100644
index f9c8ec6753466f9183fc2d0a6a2fde0e08ac2f1e..0000000000000000000000000000000000000000
--- a/eulerlauncher/backends/mac/image_handler.py
+++ /dev/null
@@ -1,118 +0,0 @@
-import copy
-import lzma
-import wget
-import os
-import subprocess
-import shutil
-import ssl
-
-from eulerlauncher.utils import constants
-from eulerlauncher.utils import utils as omni_utils
-from eulerlauncher.utils import objs
-
-
-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
- 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
-
-
- 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)
-
- download_cmd = [self.wget_bin, images['remote'][img_to_download]['path'],
- '-O', os.path.join(self.image_dir, img_name), '--no-check-certificate']
- 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))
-
- # 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 ...')
-
-
- def delete_image(self, images, img_to_delete):
- if img_to_delete not in images['local'].keys():
- 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)
-
- return 0
-
- def load_and_transform(self, images, img_to_load, path, fmt, update=False):
-
- if update:
- self._delete_image(images, img_to_load)
-
- 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 ...')
diff --git a/eulerlauncher/backends/mac/instance_handler.py b/eulerlauncher/backends/mac/instance_handler.py
deleted file mode 100644
index a53e78d81925ece983d717e04f3151860cc6b26e..0000000000000000000000000000000000000000
--- a/eulerlauncher/backends/mac/instance_handler.py
+++ /dev/null
@@ -1,177 +0,0 @@
-import os
-import psutil
-import shutil
-import signal
-import subprocess
-import sys
-import time
-
-from oslo_utils import uuidutils
-
-from eulerlauncher.utils import constants
-from eulerlauncher.utils import utils as omni_utils
-from eulerlauncher.utils import objs
-from eulerlauncher.backends.mac import qemu
-
-
-class MacInstanceHandler(object):
-
- def __init__(self, conf, work_dir, instance_dir, image_dir,
- image_record_file, logger, base_dir) -> 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
-
- 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]
- 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_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)
-
- 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 = {
- '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']
- }
-
- all_instances['instances'][name] = instance_record_dict
- omni_utils.save_json_data(instance_record, all_instances)
-
- return {
- 'name': name,
- 'vm_state': self._check_vm_state(vm_dict),
- 'image': image_id,
- 'ip_address': vm_dict['ip_address']
- }
-
- 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 ...')
- else:
- self.LOG.debug(f'Instance: {name} unable to handled, 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)
-
- 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/__init__.py b/eulerlauncher/backends/win/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/eulerlauncher/backends/win/image_handler.py b/eulerlauncher/backends/win/image_handler.py
deleted file mode 100644
index 9f09f4d13bcea66cc39a418e200ccabfdcd582dd..0000000000000000000000000000000000000000
--- a/eulerlauncher/backends/win/image_handler.py
+++ /dev/null
@@ -1,123 +0,0 @@
-import copy
-import lzma
-import wget
-import os
-import shutil
-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 objs
-
-
-ssl._create_default_https_context = ssl._create_unverified_context
-
-
-class WinImageHandler(object):
-
- def __init__(self, conf, work_dir, image_dir, image_record_file, logger) -> None:
- self.conf = conf
- self.work_dir = work_dir
- self.image_dir = image_dir
- self.image_record_file = image_record_file
- self.LOG = logger
-
- 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)
- 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)
-
- # Convert the qcow2 img to vhdx
- vhdx_name = img_to_download + '.vhdx'
- self.LOG.debug(f'Converting image file: {img_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)))
-
- self.LOG.debug(f'Cleanup temp files ...')
- os.remove(os.path.join(self.image_dir, qcow2_name))
-
- # 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 ...')
-
- def delete_image(self, images, img_to_delete):
- if img_to_delete not in images['local'].keys():
- 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']
- 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)
-
- return 0
-
- def load_and_transform(self, images, img_to_load, path, fmt, update=False):
-
- if update:
- self._delete_image(images, img_to_load)
-
- 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)
-
- # Convert the qcow2 img to vhdx
- vhdx_name = img_to_load + '.vhdx'
- self.LOG.debug(f'Converting image file: {qcow2_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)))
- self.LOG.debug(f'Cleanup temp files ...')
- os.remove(os.path.join(self.image_dir, qcow2_name))
-
- # Record local image
- 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)
- 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
deleted file mode 100644
index 7b27055300490a449c7efdfa61fdb997e03cc2c0..0000000000000000000000000000000000000000
--- a/eulerlauncher/backends/win/instance_handler.py
+++ /dev/null
@@ -1,200 +0,0 @@
-import os
-import shutil
-import time
-
-from oslo_utils import uuidutils
-from os_win import constants as os_win_const
-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 objs
-
-
-_vmops = vmops.VMOps()
-
-class WinInstanceHandler(object):
-
- def __init__(self, conf, work_dir, instance_dir, image_dir, image_record_file, logger) -> 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.LOG = logger
-
- def list_instances(self):
- vms = _vmops.list_instances()
- return vms
-
- def check_names(self, name, all_instances):
- ret = _vmops.check_all_instance_names(name)
- return ret
-
- def create_instance(self, name, image_id, instance_record, all_instances, all_images):
- # Create dir for the instance
- vm_dict = {
- 'name': name,
- 'uuid': uuidutils.generate_uuid(),
- 'image': image_id,
- 'vm_state': constants.VM_STATE_MAP[99],
- 'ip_address': 'N/A',
- 'mac_address': 'N/A',
- 'identification': {
- 'type': 'name',
- 'id': name
- }
- }
-
- 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 + '.vhdx'))
- _vmops.build_and_run_vm(name, vm_dict['uuid'], image_id, False, 2, instance_path, root_disk_path)
-
- info = _vmops.get_info(name)
- vm_dict['vm_state'] = constants.VM_STATE_MAP[info['EnabledState']]
- ip = _vmops.get_instance_ip_addr(name)
- if ip:
- vm_dict['ip_address'] = ip
-
- instance_record_dict = {
- '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']
- }
-
- all_instances['instances'][name] = instance_record_dict
- omni_utils.save_json_data(instance_record, all_instances)
-
- return {
- 'name': name,
- 'vm_state': vm_dict['vm_state'],
- 'image': image_id,
- 'ip_address': vm_dict['ip_address']
- }
-
- def delete_instance(self, name, instance_record, all_instances):
- # Delete instance
- _vmops.delete_instance(name)
-
- # Cleanup files and records
- instance_dir = all_instances['instances'][name]['path']
- shutil.rmtree(instance_dir)
- del all_instances['instances'][name]
-
- omni_utils.save_json_data(instance_record, all_instances)
-
- return 0
-
- def reboot(self, instance, reboot_type='soft'):
- """Reboot the specified instance."""
- self.LOG.debug("Rebooting instance", instance=instance)
-
- if reboot_type == 'soft':
- if self._soft_shutdown(instance):
- self.power_on(instance)
- return
-
- self._set_vm_state(instance,
- os_win_const.HYPERV_VM_STATE_REBOOT)
-
- def _soft_shutdown(self, instance,
- timeout=5,
- retry_interval=1):
- """Perform a soft shutdown on the VM.
-
- :return: True if the instance was shutdown within time limit,
- False otherwise.
- """
- self.LOG.debug("Performing Soft shutdown on instance", instance=instance)
-
- while timeout > 0:
- # Perform a soft shutdown on the instance.
- # Wait maximum timeout for the instance to be shutdown.
- # If it was not shutdown, retry until it succeeds or a maximum of
- # time waited is equal to timeout.
- wait_time = min(retry_interval, timeout)
- try:
- self.LOG.debug("Soft shutdown instance, timeout remaining: %d",
- timeout, instance=instance)
- self._vmutils.soft_shutdown_vm(instance.name)
- if self._wait_for_power_off(instance.name, wait_time):
- self.LOG.info("Soft shutdown succeeded.",
- instance=instance)
- return True
- except os_win_exc.HyperVException as e:
- # Exception is raised when trying to shutdown the instance
- # while it is still booting.
- self.LOG.debug("Soft shutdown failed: %s", e, instance=instance)
- time.sleep(wait_time)
-
- timeout -= retry_interval
-
- self.LOG.warning("Timed out while waiting for soft shutdown.",
- instance=instance)
- return False
-
- def pause(self, instance):
- """Pause VM instance."""
- self.LOG.debug("Pause instance", instance=instance)
- self._set_vm_state(instance,
- os_win_const.HYPERV_VM_STATE_PAUSED)
-
- def unpause(self, instance):
- """Unpause paused VM instance."""
- self.LOG.debug("Unpause instance", instance=instance)
- self._set_vm_state(instance,
- os_win_const.HYPERV_VM_STATE_ENABLED)
-
- def suspend(self, instance):
- """Suspend the specified instance."""
- self.LOG.debug("Suspend instance", instance=instance)
- self._set_vm_state(instance,
- os_win_const.HYPERV_VM_STATE_SUSPENDED)
-
- def resume(self, instance):
- """Resume the suspended VM instance."""
- self.LOG.debug("Resume instance", instance=instance)
- self._set_vm_state(instance,
- os_win_const.HYPERV_VM_STATE_ENABLED)
-
- def power_off(self, instance, timeout=0, retry_interval=0):
- """Power off the specified instance."""
- self.LOG.debug("Power off instance", instance=instance)
-
- # We must make sure that the console log workers are stopped,
- # otherwise we won't be able to delete or move the VM log files.
- self._serial_console_ops.stop_console_handler(instance.name)
-
- if retry_interval <= 0:
- retry_interval = SHUTDOWN_TIME_INCREMENT
-
- try:
- if timeout and self._soft_shutdown(instance,
- timeout,
- retry_interval):
- return
-
- self._set_vm_state(instance,
- os_win_const.HYPERV_VM_STATE_DISABLED)
- except os_win_exc.HyperVVMNotFoundException:
- # The manager can call the stop API after receiving instance
- # power off events. If this is triggered when the instance
- # is being deleted, it might attempt to power off an unexisting
- # instance. We'll just pass in this case.
- self.LOG.debug("Instance not found. Skipping power off",
- instance=instance)
-
- def power_on(self, instance):
- """Power on the specified instance."""
- self.LOG.debug("Power on instance", instance=instance)
- self._set_vm_state(instance, os_win_const.HYPERV_VM_STATE_ENABLED)
diff --git a/eulerlauncher/backends/win/powershell.py b/eulerlauncher/backends/win/powershell.py
deleted file mode 100644
index ac6a60d89e26b004a12905b44d9c7b1f39554ec8..0000000000000000000000000000000000000000
--- a/eulerlauncher/backends/win/powershell.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import os
-from glob import glob
-import subprocess as sp
-
-
-class PowerShell:
- # from scapy
- def __init__(self, coding, ):
- cmd = [self._where('PowerShell.exe'),
- "-NoLogo", "-NonInteractive", # Do not print headers
- "-Command", "-"] # Listen commands from stdin
- startupinfo = sp.STARTUPINFO()
- startupinfo.dwFlags |= sp.STARTF_USESHOWWINDOW
- self.popen = sp.Popen(cmd, stdout=sp.PIPE, stdin=sp.PIPE, stderr=sp.STDOUT, startupinfo=startupinfo)
- self.coding = coding
-
- def __enter__(self):
- return self
-
- def __exit__(self, a, b, c):
- self.popen.kill()
-
- def run(self, cmd, timeout=15):
- b_cmd = cmd.encode(encoding=self.coding)
- try:
- b_outs, errs = self.popen.communicate(b_cmd, timeout=timeout)
- except sp.TimeoutExpired:
- self.popen.kill()
- b_outs, errs = self.popen.communicate()
- outs = b_outs.decode(encoding=self.coding)
- return outs, errs
-
- @staticmethod
- def _where(filename, dirs=None, env="PATH"):
- """Find file in current dir, in deep_lookup cache or in system path"""
- if dirs is None:
- dirs = []
- if not isinstance(dirs, list):
- dirs = [dirs]
- if glob(filename):
- return filename
- paths = [os.curdir] + os.environ[env].split(os.path.pathsep) + dirs
- try:
- return next(os.path.normpath(match)
- for path in paths
- for match in glob(os.path.join(path, filename))
- if match)
- except (StopIteration, RuntimeError):
- raise IOError("File not found: %s" % filename)
diff --git a/eulerlauncher/backends/win/vmops.py b/eulerlauncher/backends/win/vmops.py
deleted file mode 100644
index b8e4c75d4193bf3e7a807104b25b580bf98c27ae..0000000000000000000000000000000000000000
--- a/eulerlauncher/backends/win/vmops.py
+++ /dev/null
@@ -1,183 +0,0 @@
-import json
-
-from os_win import constants as os_win_const
-from os_win import exceptions as os_win_exc
-from os_win.utils.compute import vmutils10
-from os_win import utilsfactory
-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.backends.win import powershell
-
-SWITCH_NAME = 'Default Switch'
-
-
-class VMUtils_omni(vmutils10.VMUtils10):
-
- def __init__(self) -> None:
- super().__init__()
-
- def get_instance_notes(self, instance_name):
- instance_notes = self._get_instance_notes(instance_name)
- return instance_notes
-
- def get_vm_nic_uids(self, vm_name):
- nics = self._get_vm_nics(vm_name)
- return nics
-
-class VMOps(object):
- _ROOT_DISK_CTRL_ADDR = 0
-
- def __init__(self, virtapi=None):
- self._virtapi = virtapi
- self._vmutils = VMUtils_omni()
- self._netutils = utilsfactory.get_networkutils()
- self._hostutils = utilsfactory.get_hostutils()
-
- def _set_vm_state(self, instance, req_state):
- instance_name = instance.name
- self._vmutils.set_vm_state(instance_name, req_state)
-
- def list_instance_uuids(self):
- instance_uuids = []
- for (instance_name, notes) in self._vmutils.list_instance_notes():
- if notes and uuidutils.is_uuid_like(notes[0]):
- instance_uuids.append(str(notes[0]))
- else:
- pass
- #LOG.debug("Notes not found or not resembling a GUID for "
- # "instance: %s", instance_name)
- return instance_uuids
-
- def check_all_instance_names(self, name):
- instance_names = self._vmutils.list_instances()
- if name in instance_names:
- return 1
- else:
- return 0
-
- def list_instances(self):
- instance_names = self._vmutils.list_instances()
- vm_list = []
- for instance_name in instance_names:
- vm = objs.Instance(name=instance_name)
- meta = self.get_meta(instance_name)
- if not meta or not meta['creator'] == 'eulerlauncher':
- continue
- else:
- vm.metadata = meta
- vm.uuid = meta['uuid']
- info = self.get_info(instance_name)
- vm.info = info
- vm.vm_state = constants.VM_STATE_MAP[info['EnabledState']]
- ip_address = self.get_instance_ip_addr(instance_name)
- vm.ip = ip_address
- vm.image = meta['image']
- vm_list.append(vm)
-
- return vm_list
-
-
- 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)
- with powershell.PowerShell('GBK') as ps:
- outs, errs = ps.run('arp -a | findstr /i {}'.format(mac_address))
- ip_address = outs.strip(' ').split(' ')[0]
-
- return ip_address
-
-
- def get_info(self, instance):
- """Get information about the VM."""
- # LOG.debug("get_info called for instance", instance=instance)
-
- instance_name = instance
- if not self._vmutils.vm_exists(instance_name):
- raise # exception.InstanceNotFound(instance_id=instance.uuid)
-
- info = self._vmutils.get_vm_summary_info(instance_name)
-
- return info
-
- def create_vm(self, vm_name, vnuma_enabled, vm_gen, instance_path,
- meta_data):
- self._vmutils.create_vm(vm_name,
- vnuma_enabled,
- vm_gen,
- instance_path,
- [json.dumps(meta_data)])
-
- def build_and_run_vm(self, vm_name, uuid, image_name, vnuma_enabled, vm_gen, instance_path, root_disk_path):
- meta_data = {
- 'uuid': uuid,
- 'image': image_name,
- 'creator': 'eulerlauncher'
- }
-
- # Create an instance
- self.create_vm(vm_name, vnuma_enabled, vm_gen, instance_path, meta_data)
- # Create a scsi controller for this instance
- self._vmutils.create_scsi_controller(vm_name)
- # Attach the root disk to the driver
- self.attach_disk(vm_name, root_disk_path, constants.DISK)
- # Set default flavor
- self._vmutils.update_vm(vm_name, 4096, 0, '2', 0, False, 0)
- # Start the instance
- self.power_up(vm_name)
- nic_name = vm_name + '_eth0'
- self.add_nic(vm_name, nic_name)
- self.connect_vnic_to_switch(SWITCH_NAME, nic_name)
- return 0
-
- def get_meta(self, instance_name, expect_existing=False):
- try:
- instance_notes = self._vmutils.get_instance_notes(instance_name)
- if instance_notes:
- return json.loads(instance_notes[0])
- else:
- return instance_notes
- except os_win_exc.HyperVVMNotFoundException:
- raise
-
- def delete_instance(self, vm_name):
- # Stop the VM first.
- self._vmutils.stop_vm_jobs(vm_name)
- self._vmutils.set_vm_state(vm_name, os_win_const.HYPERV_VM_STATE_DISABLED)
- self._vmutils.destroy_vm(vm_name)
-
- while(1):
- if not self._vmutils.vm_exists(vm_name):
- break
- return 0
-
- def get_vm_disks(self, vm_name):
- return self._vmutils.get_vm_disks(vm_name)
-
- def attach_disk(self, instance_name, path, drive_type):
- self._vmutils.attach_scsi_drive(instance_name, path, drive_type)
-
- def power_up(self, instance_name):
- req_state = os_win_const.HYPERV_VM_STATE_ENABLED
- self._vmutils.set_vm_state(instance_name, req_state)
-
- def add_nic(self, instance_name, nic_name):
- self._vmutils.create_nic(instance_name, nic_name)
-
- def get_vm_nics(self, instance_name, nic_name):
- return self._vmutils._get_nic_data_by_name(nic_name)
-
- def list_switch_ports(self, switch_name):
- return self._netutils.get_switch_ports(switch_name)
-
- def connect_vnic_to_switch(self, switch_name, vnic_name):
- self._netutils.connect_vnic_to_vswitch(switch_name, vnic_name)
-
- def get_switch_port(self, switch_name, port_id):
- return self._netutils.get_port_by_id(port_id, switch_name)
-
- def get_host_ips(self):
- return self._hostutils.get_local_ips()
diff --git a/eulerlauncher/cli.py b/eulerlauncher/cli.py
index 56972a1573780b1c5660695f3e7a3cc55009d430..e46cec50dea3df3fc748fdcfbaa528a1d38d6d96 100644
--- a/eulerlauncher/cli.py
+++ b/eulerlauncher/cli.py
@@ -6,35 +6,18 @@ from eulerlauncher.grpcs import client
launcher_client = client.Client()
-# List all instances on the host
-@click.command()
-def list():
-
- try:
- ret = launcher_client.list_instances()
- except Exception:
- print('Calling to EulerLauncherd daemon failed, please check EulerLauncherd daemon status ...')
- else:
- tb = pt.PrettyTable()
-
- tb.field_names = ["Name", "Image", "State", "IP"]
- try:
- for instance in ret['instances']:
- tb.add_row(
- [instance['name'],
- instance['image'],
- instance['vmState'],
- instance['ipAddress']])
- except KeyError:
- pass
-
- print(tb)
+@click.group(
+ name="image",
+ help="Command for managing images "
+)
+def image():
+ pass
# List all usable images
-@click.command()
-def images():
+@image.command()
+def list():
try:
ret = launcher_client.list_images()
@@ -52,9 +35,9 @@ def images():
print(tb)
-@click.command()
+@image.command()
@click.argument('name')
-def download_image(name):
+def download(name):
try:
ret = launcher_client.download_image(name)
@@ -64,10 +47,10 @@ def download_image(name):
print(ret['msg'])
-@click.command()
+@image.command()
@click.argument('name')
@click.option('--path', help='Image file to load')
-def load_image(name, path):
+def load(name, path):
try:
ret = launcher_client.load_image(name, path)
@@ -77,9 +60,9 @@ def load_image(name, path):
print(ret['msg'])
-@click.command()
+@image.command()
@click.argument('name')
-def delete_image(name):
+def delete(name):
try:
ret = launcher_client.delete_image(name)
@@ -89,9 +72,56 @@ def delete_image(name):
print(ret['msg'])
-@click.command()
+@click.group(
+ name="instance",
+ help="Command for managing instances "
+)
+def instance():
+ pass
+
+
+@instance.command()
+@click.argument('vm_name')
+@click.option('--image', help='Image to build instance')
+def launch(vm_name, image):
+
+ try:
+ ret = launcher_client.create_instance(vm_name, image)
+ except Exception:
+ print('Calling to EulerLauncherd daemon failed, please check EulerLauncherd daemon status ...')
+ else:
+ print(ret['msg'])
+
+
+# List all instances on the host
+@instance.command()
+def list():
+
+ try:
+ ret = launcher_client.list_instances()
+ except Exception:
+ print('Calling to EulerLauncherd daemon failed, please check EulerLauncherd daemon status ...')
+ else:
+ tb = pt.PrettyTable()
+
+ tb.field_names = ["Name", "Image", "State", "IP"]
+
+ try:
+ for instance in ret['instances']:
+ tb.add_row(
+ [instance['name'],
+ instance['image'],
+ instance['vmState'],
+ instance['ipAddress']])
+ except KeyError:
+ pass
+
+ print(tb)
+
+
+@instance.command()
@click.argument('name')
-def delete_instance(name):
+def delete(name):
try:
ret = launcher_client.delete_instance(name)
@@ -100,43 +130,49 @@ def delete_instance(name):
else:
print(ret['msg'])
-@click.command()
-@click.argument('vm_name')
-@click.option('--image', help='Image to build vm')
-def launch(vm_name, image):
+
+@instance.command()
+@click.argument('name')
+def suspend(name):
try:
- ret = launcher_client.create_instance(vm_name, image)
+ ret = launcher_client.suspend_instance(name)
except Exception:
print('Calling to EulerLauncherd daemon failed, please check EulerLauncherd daemon status ...')
else:
+ print(ret['msg'])
- 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'])
+@instance.command()
+@click.argument('name')
+def resume(name):
+
+ try:
+ ret = launcher_client.resume_instance(name)
+ except Exception:
+ print('Calling to EulerLauncherd daemon failed, please check EulerLauncherd daemon status ...')
+ else:
+ print(ret['msg'])
+
+
+@instance.command()
+@click.argument('name')
+def console(name):
+
+ try:
+ ret = launcher_client.console_instance(name)
+ except Exception:
+ print('Calling to EulerLauncherd daemon failed, please check EulerLauncherd daemon status ...')
+ else:
+ print(ret['msg'])
@click.group()
-def cli():
+def entrance():
pass
if __name__ == '__main__':
- cli.add_command(list)
- cli.add_command(images)
- cli.add_command(download_image)
- cli.add_command(load_image)
- cli.add_command(launch)
- cli.add_command(delete_image)
- cli.add_command(delete_instance)
- cli()
\ No newline at end of file
+ entrance.add_command(image)
+ entrance.add_command(instance)
+ entrance()
\ No newline at end of file
diff --git a/eulerlauncher/eulerlauncherd.py b/eulerlauncher/eulerlauncherd.py
index 4bd0be7542a1457d53209c23dc5428ae0fb9b252..c4b550dffd275b71710af36bc7f485081198ea09 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,15 +7,16 @@ import platform
import pystray
import requests
import signal
-import subprocess
import sys
import time
+import configparser
+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 exceptions
from eulerlauncher.utils import constants
-from eulerlauncher.utils import objs
from eulerlauncher.utils import utils
@@ -29,12 +29,11 @@ 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):
- log_dir = config.conf.get('default', 'log_dir')
- debug = config.conf.get('default', 'debug')
+def init_log(CONF):
+ log_dir = CONF.get('default', 'log_dir')
+ debug = CONF.get('default', 'debug')
if not os.path.exists(log_dir):
os.makedirs(log_dir)
@@ -50,63 +49,63 @@ def config_logging(config):
filename=log_file, level=log_level, filemode='a+')
-def init(arch, config, LOG):
- work_dir = config.conf.get('default', 'work_dir')
+def init_workdir(arch, CONF, LOG):
+ LOG.debug('Initializing work directory ...')
+ work_dir = 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')
+ instance_record_path = os.path.join(instance_dir, 'instances.json')
+ image_record_path = 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):
+ if not os.path.exists(instance_record_path):
+ LOG.debug('Create %s as instance database ...' % instance_record_path)
instances = {
- 'instances': {}
}
- utils.save_json_data(instance_record_file, instances)
+ utils.save_json_data(instance_record_path, instances)
LOG.debug('Checking for image directory ...')
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_path):
+ LOG.debug('Create %s as image database ...' % image_record_path)
+ 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_STATE_MAP[1]
+ }
+ utils.save_json_data(image_record_path, image_record)
-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)
- 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,25 +120,24 @@ 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 = configparser.ConfigParser()
+ if not os.path.exists(conf_file):
+ raise exceptions.NoSuchFile(file=conf_file)
+ CONF.read(conf_file)
- config_logging(CONF)
+ init_log(CONF)
LOG = logging.getLogger(__name__)
-
+ LOG.debug('Initializing EulerLauncherd ...')
+
host_arch_raw = platform.uname().machine
- host_os_raw = platform.uname().system
-
host_arch = constants.ARCH_MAP[host_arch_raw]
+ host_os_raw = platform.uname().system
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 +145,28 @@ 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)
- ))
-
- except Exception as e:
- print('Error: ' + str(e))
- sys.exit(0)
-
- server = init_launcherd(conf_file, base_dir)
-
- icon.run()
- server.stop(None)
+ 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)
+ ))
+
+ except Exception as e:
+ print('Error: ' + str(e))
sys.exit(0)
-
+
+ server = init_launcherd(conf_file)
+
+ icon.run()
+ server.stop(None)
+ sys.exit(0)
\ No newline at end of file
diff --git a/eulerlauncher/grpcs/client.py b/eulerlauncher/grpcs/client.py
index 66adb9afa25f9ddfecc4e33297e7d7cea29ddfaf..1fcd17761efa72db2f0923e860540ab9277da792 100644
--- a/eulerlauncher/grpcs/client.py
+++ b/eulerlauncher/grpcs/client.py
@@ -1,11 +1,9 @@
import grpc
-import os
from eulerlauncher.grpcs.eulerlauncher_grpc import images_pb2, images_pb2_grpc
from eulerlauncher.grpcs.eulerlauncher_grpc import instances_pb2, instances_pb2_grpc
from eulerlauncher.grpcs import images, instances
-from eulerlauncher.utils import constants
-from eulerlauncher.utils import utils as omnivirt_utils
+from eulerlauncher.utils import utils
class Client(object):
@@ -20,7 +18,8 @@ class Client(object):
self._images = images.Image(images_client)
self._instances = instances.Instance(instances_client)
- @omnivirt_utils.response2dict
+
+ @utils.response2dict
def list_images(self, filters=None):
""" [IMAGE] List images
@@ -30,48 +29,32 @@ class Client(object):
return self._images.list()
- @omnivirt_utils.response2dict
+
+ @utils.response2dict
def download_image(self, name):
""" Download image
"""
return self._images.download(name)
- @omnivirt_utils.response2dict
+
+ @utils.response2dict
def load_image(self, name, path):
""" Load local image file
"""
- if not os.path.exists(path):
- err_msg = {
- 'ret': 1,
- 'msg': f'No such file or directory: {path}, please check again.'
- }
- return err_msg
-
- supported = False
- for tp in constants.IMAGE_LOAD_SUPPORTED_TYPES:
- if path.endswith(tp):
- supported = True
- break
-
- if not supported:
- err_msg = {
- 'ret': 1,
- 'msg': f'Image file format does not supported: {path}, please check again.'
- }
- return err_msg
-
return self._images.load(name, path)
- @omnivirt_utils.response2dict
+
+ @utils.response2dict
def delete_image(self, name):
""" Delete the requested image
"""
return self._images.delete(name)
- @omnivirt_utils.response2dict
+
+ @utils.response2dict
def list_instances(self):
""" List instances
:return: dict -- list of instances' info
@@ -79,7 +62,8 @@ class Client(object):
return self._instances.list()
- @omnivirt_utils.response2dict
+
+ @utils.response2dict
def create_instance(self, name, image):
""" Create instance
:return: dict -- dict of instance's info
@@ -87,9 +71,32 @@ class Client(object):
return self._instances.create(name, image)
- @omnivirt_utils.response2dict
+
+ @utils.response2dict
def delete_instance(self, name):
""" Delete the requested instance
"""
return self._instances.delete(name)
+
+ @utils.response2dict
+ def suspend_instance(self, name):
+ """ Suspend the requested instance
+ """
+
+ return self._instances.suspend(name)
+
+ @utils.response2dict
+ def resume_instance(self, name):
+ """ Resume the requested instance
+ """
+
+ return self._instances.resume(name)
+
+
+ @utils.response2dict
+ def console_instance(self, name):
+ """ connect the requested instance
+ """
+
+ return self._instances.console(name)
\ No newline at end of file
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/images.proto b/eulerlauncher/grpcs/eulerlauncher_grpc/images.proto
index 26996d9dfd1c61817d7d3fc9fbc077fe3b02136b..f5097688c9ac48e844585e3eed087c61546ffea5 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/images.proto
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/images.proto
@@ -1,5 +1,5 @@
syntax = "proto3";
-package omnivirt;
+package eulerlauncher;
option cc_generic_services = true;
@@ -27,19 +27,23 @@ message ListImageResponse {
repeated Image images = 1;
}
+
message DownloadImageRequest {
string name = 1;
}
+
message LoadImageRequest {
string name = 1;
string path = 2;
}
+
message DeleteImageRequest {
string name = 1;
}
+
message GeneralImageResponse {
uint32 ret = 1;
string msg = 2;
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2.py b/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2.py
index 6b2f860ebc20149da3530d08e18adeca7a89c574..ab1e0b60d70db0bac7be3380076f46a07793deb9 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!
-# source: images.proto
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: eulerlauncher/grpcs/eulerlauncher_grpc/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,
+ '',
+ 'eulerlauncher/grpcs/eulerlauncher_grpc/images.proto'
+)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -13,28 +24,28 @@ _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 = _descriptor_pool.Default().AddSerializedFile(b'\n3eulerlauncher/grpcs/eulerlauncher_grpc/images.proto\x12\reulerlauncher\"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\"9\n\x11ListImageResponse\x12$\n\x06images\x18\x01 \x03(\x0b\x32\x14.eulerlauncher.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\xf4\x02\n\x10ImageGrpcService\x12R\n\x0blist_images\x12\x1f.eulerlauncher.ListImageRequest\x1a .eulerlauncher.ListImageResponse\"\x00\x12\\\n\x0e\x64ownload_image\x12#.eulerlauncher.DownloadImageRequest\x1a#.eulerlauncher.GeneralImageResponse\"\x00\x12T\n\nload_image\x12\x1f.eulerlauncher.LoadImageRequest\x1a#.eulerlauncher.GeneralImageResponse\"\x00\x12X\n\x0c\x64\x65lete_image\x12!.eulerlauncher.DeleteImageRequest\x1a#.eulerlauncher.GeneralImageResponse\"\x00\x42\x03\x80\x01\x01\x62\x06proto3')
- 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, 'eulerlauncher.grpcs.eulerlauncher_grpc.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=70
+ _globals['_IMAGE']._serialized_end=125
+ _globals['_LISTIMAGEREQUEST']._serialized_start=127
+ _globals['_LISTIMAGEREQUEST']._serialized_end=145
+ _globals['_LISTIMAGERESPONSE']._serialized_start=147
+ _globals['_LISTIMAGERESPONSE']._serialized_end=204
+ _globals['_DOWNLOADIMAGEREQUEST']._serialized_start=206
+ _globals['_DOWNLOADIMAGEREQUEST']._serialized_end=242
+ _globals['_LOADIMAGEREQUEST']._serialized_start=244
+ _globals['_LOADIMAGEREQUEST']._serialized_end=290
+ _globals['_DELETEIMAGEREQUEST']._serialized_start=292
+ _globals['_DELETEIMAGEREQUEST']._serialized_end=326
+ _globals['_GENERALIMAGERESPONSE']._serialized_start=328
+ _globals['_GENERALIMAGERESPONSE']._serialized_end=376
+ _globals['_IMAGEGRPCSERVICE']._serialized_start=379
+ _globals['_IMAGEGRPCSERVICE']._serialized_end=751
# @@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..2eeacd4800b6ef005009035bb5ecf46d047e645d 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2_grpc.py
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/images_pb2_grpc.py
@@ -1,8 +1,28 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
+import warnings
-from eulerlauncher.grpcs.eulerlauncher_grpc import images_pb2 as images__pb2
+from eulerlauncher.grpcs.eulerlauncher_grpc import images_pb2 as eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2
+
+GRPC_GENERATED_VERSION = '1.68.1'
+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 eulerlauncher/grpcs/eulerlauncher_grpc/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):
@@ -15,25 +35,25 @@ class ImageGrpcServiceStub(object):
channel: A grpc.Channel.
"""
self.list_images = channel.unary_unary(
- '/omnivirt.ImageGrpcService/list_images',
- request_serializer=images__pb2.ListImageRequest.SerializeToString,
- response_deserializer=images__pb2.ListImageResponse.FromString,
- )
+ '/eulerlauncher.ImageGrpcService/list_images',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.ListImageRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_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,
- )
+ '/eulerlauncher.ImageGrpcService/download_image',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.DownloadImageRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_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,
- )
+ '/eulerlauncher.ImageGrpcService/load_image',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.LoadImageRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_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,
- )
+ '/eulerlauncher.ImageGrpcService/delete_image',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.DeleteImageRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.GeneralImageResponse.FromString,
+ _registered_method=True)
class ImageGrpcServiceServicer(object):
@@ -68,28 +88,29 @@ def add_ImageGrpcServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'list_images': grpc.unary_unary_rpc_method_handler(
servicer.list_images,
- request_deserializer=images__pb2.ListImageRequest.FromString,
- response_serializer=images__pb2.ListImageResponse.SerializeToString,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.ListImageRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.ListImageResponse.SerializeToString,
),
'download_image': grpc.unary_unary_rpc_method_handler(
servicer.download_image,
- request_deserializer=images__pb2.DownloadImageRequest.FromString,
- response_serializer=images__pb2.GeneralImageResponse.SerializeToString,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.DownloadImageRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.GeneralImageResponse.SerializeToString,
),
'load_image': grpc.unary_unary_rpc_method_handler(
servicer.load_image,
- request_deserializer=images__pb2.LoadImageRequest.FromString,
- response_serializer=images__pb2.GeneralImageResponse.SerializeToString,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.LoadImageRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.GeneralImageResponse.SerializeToString,
),
'delete_image': grpc.unary_unary_rpc_method_handler(
servicer.delete_image,
- request_deserializer=images__pb2.DeleteImageRequest.FromString,
- response_serializer=images__pb2.GeneralImageResponse.SerializeToString,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.DeleteImageRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.GeneralImageResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
- 'omnivirt.ImageGrpcService', rpc_method_handlers)
+ 'eulerlauncher.ImageGrpcService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
+ server.add_registered_method_handlers('eulerlauncher.ImageGrpcService', rpc_method_handlers)
# This class is part of an EXPERIMENTAL API.
@@ -107,11 +128,21 @@ class ImageGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- 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)
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.ImageGrpcService/list_images',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.ListImageRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.ListImageResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def download_image(request,
@@ -124,11 +155,21 @@ class ImageGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- 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)
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.ImageGrpcService/download_image',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.DownloadImageRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.GeneralImageResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def load_image(request,
@@ -141,11 +182,21 @@ class ImageGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- 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)
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.ImageGrpcService/load_image',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.LoadImageRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.GeneralImageResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def delete_image(request,
@@ -158,8 +209,18 @@ class ImageGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- 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)
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.ImageGrpcService/delete_image',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.DeleteImageRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_images__pb2.GeneralImageResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/instances.proto b/eulerlauncher/grpcs/eulerlauncher_grpc/instances.proto
index c2e751cb2fc354d7f0903a9bc7529f278501167d..5bac8b8c6908a566be5e3fab2c11a49886226ae7 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/instances.proto
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/instances.proto
@@ -1,5 +1,5 @@
syntax = "proto3";
-package omnivirt;
+package eulerlauncher;
option cc_generic_services = true;
@@ -8,6 +8,9 @@ service InstanceGrpcService {
rpc list_instances (ListInstancesRequest) returns (ListInstancesResponse) {}
rpc create_instance (CreateInstanceRequest) returns (CreateInstanceResponse) {}
rpc delete_instance (DeleteInstanceRequest) returns (DeleteInstanceResponse) {}
+ rpc suspend_instance (SuspendInstanceRequest) returns (SuspendInstanceResponse) {}
+ rpc resume_instance (ResumeInstanceRequest) returns (ResumeInstanceResponse) {}
+ rpc console_instance (ConsoleInstanceRequest) returns (ConsoleInstanceResponse) {}
}
@@ -27,22 +30,59 @@ message ListInstancesResponse {
repeated Instance instances = 1;
}
+
message CreateInstanceRequest {
string name = 1;
string image = 2;
}
+
message CreateInstanceResponse {
uint32 ret = 1;
string msg = 2;
optional Instance instance = 3;
}
+
message DeleteInstanceRequest {
string name = 1;
}
+
message DeleteInstanceResponse {
uint32 ret = 1;
string msg = 2;
}
+
+
+message SuspendInstanceRequest {
+ string name = 1;
+}
+
+
+message SuspendInstanceResponse {
+ uint32 ret = 1;
+ string msg = 2;
+}
+
+
+message ResumeInstanceRequest {
+ string name = 1;
+}
+
+
+message ResumeInstanceResponse {
+ uint32 ret = 1;
+ string msg = 2;
+}
+
+
+message ConsoleInstanceRequest {
+ string name = 1;
+}
+
+
+message ConsoleInstanceResponse {
+ uint32 ret = 1;
+ string msg = 2;
+}
\ No newline at end of file
diff --git a/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2.py b/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2.py
index 9877833f058ff6798506e937cee9f7ce7d1e555e..598e434f2535d94f0b177c8f532545b04b55c4c0 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!
-# source: instances.proto
+# NO CHECKED-IN PROTOBUF GENCODE
+# source: eulerlauncher/grpcs/eulerlauncher_grpc/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,
+ '',
+ 'eulerlauncher/grpcs/eulerlauncher_grpc/instances.proto'
+)
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -13,28 +24,40 @@ _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 = _descriptor_pool.Default().AddSerializedFile(b'\n6eulerlauncher/grpcs/eulerlauncher_grpc/instances.proto\x12\reulerlauncher\"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\"C\n\x15ListInstancesResponse\x12*\n\tinstances\x18\x01 \x03(\x0b\x32\x17.eulerlauncher.Instance\"4\n\x15\x43reateInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05image\x18\x02 \x01(\t\"o\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\x17.eulerlauncher.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(\t\"&\n\x16SuspendInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"3\n\x17SuspendInstanceResponse\x12\x0b\n\x03ret\x18\x01 \x01(\r\x12\x0b\n\x03msg\x18\x02 \x01(\t\"%\n\x15ResumeInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"2\n\x16ResumeInstanceResponse\x12\x0b\n\x03ret\x18\x01 \x01(\r\x12\x0b\n\x03msg\x18\x02 \x01(\t\"&\n\x16\x43onsoleInstanceRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"3\n\x17\x43onsoleInstanceResponse\x12\x0b\n\x03ret\x18\x01 \x01(\r\x12\x0b\n\x03msg\x18\x02 \x01(\t2\xe4\x04\n\x13InstanceGrpcService\x12]\n\x0elist_instances\x12#.eulerlauncher.ListInstancesRequest\x1a$.eulerlauncher.ListInstancesResponse\"\x00\x12`\n\x0f\x63reate_instance\x12$.eulerlauncher.CreateInstanceRequest\x1a%.eulerlauncher.CreateInstanceResponse\"\x00\x12`\n\x0f\x64\x65lete_instance\x12$.eulerlauncher.DeleteInstanceRequest\x1a%.eulerlauncher.DeleteInstanceResponse\"\x00\x12\x63\n\x10suspend_instance\x12%.eulerlauncher.SuspendInstanceRequest\x1a&.eulerlauncher.SuspendInstanceResponse\"\x00\x12`\n\x0fresume_instance\x12$.eulerlauncher.ResumeInstanceRequest\x1a%.eulerlauncher.ResumeInstanceResponse\"\x00\x12\x63\n\x10\x63onsole_instance\x12%.eulerlauncher.ConsoleInstanceRequest\x1a&.eulerlauncher.ConsoleInstanceResponse\"\x00\x42\x03\x80\x01\x01\x62\x06proto3')
- 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, 'eulerlauncher.grpcs.eulerlauncher_grpc.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=73
+ _globals['_INSTANCE']._serialized_end=150
+ _globals['_LISTINSTANCESREQUEST']._serialized_start=152
+ _globals['_LISTINSTANCESREQUEST']._serialized_end=174
+ _globals['_LISTINSTANCESRESPONSE']._serialized_start=176
+ _globals['_LISTINSTANCESRESPONSE']._serialized_end=243
+ _globals['_CREATEINSTANCEREQUEST']._serialized_start=245
+ _globals['_CREATEINSTANCEREQUEST']._serialized_end=297
+ _globals['_CREATEINSTANCERESPONSE']._serialized_start=299
+ _globals['_CREATEINSTANCERESPONSE']._serialized_end=410
+ _globals['_DELETEINSTANCEREQUEST']._serialized_start=412
+ _globals['_DELETEINSTANCEREQUEST']._serialized_end=449
+ _globals['_DELETEINSTANCERESPONSE']._serialized_start=451
+ _globals['_DELETEINSTANCERESPONSE']._serialized_end=501
+ _globals['_SUSPENDINSTANCEREQUEST']._serialized_start=503
+ _globals['_SUSPENDINSTANCEREQUEST']._serialized_end=541
+ _globals['_SUSPENDINSTANCERESPONSE']._serialized_start=543
+ _globals['_SUSPENDINSTANCERESPONSE']._serialized_end=594
+ _globals['_RESUMEINSTANCEREQUEST']._serialized_start=596
+ _globals['_RESUMEINSTANCEREQUEST']._serialized_end=633
+ _globals['_RESUMEINSTANCERESPONSE']._serialized_start=635
+ _globals['_RESUMEINSTANCERESPONSE']._serialized_end=685
+ _globals['_CONSOLEINSTANCEREQUEST']._serialized_start=687
+ _globals['_CONSOLEINSTANCEREQUEST']._serialized_end=725
+ _globals['_CONSOLEINSTANCERESPONSE']._serialized_start=727
+ _globals['_CONSOLEINSTANCERESPONSE']._serialized_end=778
+ _globals['_INSTANCEGRPCSERVICE']._serialized_start=781
+ _globals['_INSTANCEGRPCSERVICE']._serialized_end=1393
# @@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..271412742427cc88f87fd1e377f821bc6953e53d 100644
--- a/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2_grpc.py
+++ b/eulerlauncher/grpcs/eulerlauncher_grpc/instances_pb2_grpc.py
@@ -1,8 +1,28 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc
+import warnings
-from eulerlauncher.grpcs.eulerlauncher_grpc import instances_pb2 as instances__pb2
+from eulerlauncher.grpcs.eulerlauncher_grpc import instances_pb2 as eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2
+
+GRPC_GENERATED_VERSION = '1.68.1'
+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 eulerlauncher/grpcs/eulerlauncher_grpc/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):
@@ -15,20 +35,35 @@ class InstanceGrpcServiceStub(object):
channel: A grpc.Channel.
"""
self.list_instances = channel.unary_unary(
- '/omnivirt.InstanceGrpcService/list_instances',
- request_serializer=instances__pb2.ListInstancesRequest.SerializeToString,
- response_deserializer=instances__pb2.ListInstancesResponse.FromString,
- )
+ '/eulerlauncher.InstanceGrpcService/list_instances',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ListInstancesRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_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,
- )
+ '/eulerlauncher.InstanceGrpcService/create_instance',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.CreateInstanceRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_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,
- )
+ '/eulerlauncher.InstanceGrpcService/delete_instance',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.DeleteInstanceRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.DeleteInstanceResponse.FromString,
+ _registered_method=True)
+ self.suspend_instance = channel.unary_unary(
+ '/eulerlauncher.InstanceGrpcService/suspend_instance',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.SuspendInstanceRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.SuspendInstanceResponse.FromString,
+ _registered_method=True)
+ self.resume_instance = channel.unary_unary(
+ '/eulerlauncher.InstanceGrpcService/resume_instance',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ResumeInstanceRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ResumeInstanceResponse.FromString,
+ _registered_method=True)
+ self.console_instance = channel.unary_unary(
+ '/eulerlauncher.InstanceGrpcService/console_instance',
+ request_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ConsoleInstanceRequest.SerializeToString,
+ response_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ConsoleInstanceResponse.FromString,
+ _registered_method=True)
class InstanceGrpcServiceServicer(object):
@@ -52,28 +87,62 @@ class InstanceGrpcServiceServicer(object):
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
+ def suspend_instance(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def resume_instance(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def console_instance(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
def add_InstanceGrpcServiceServicer_to_server(servicer, server):
rpc_method_handlers = {
'list_instances': grpc.unary_unary_rpc_method_handler(
servicer.list_instances,
- request_deserializer=instances__pb2.ListInstancesRequest.FromString,
- response_serializer=instances__pb2.ListInstancesResponse.SerializeToString,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ListInstancesRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ListInstancesResponse.SerializeToString,
),
'create_instance': grpc.unary_unary_rpc_method_handler(
servicer.create_instance,
- request_deserializer=instances__pb2.CreateInstanceRequest.FromString,
- response_serializer=instances__pb2.CreateInstanceResponse.SerializeToString,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.CreateInstanceRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.CreateInstanceResponse.SerializeToString,
),
'delete_instance': grpc.unary_unary_rpc_method_handler(
servicer.delete_instance,
- request_deserializer=instances__pb2.DeleteInstanceRequest.FromString,
- response_serializer=instances__pb2.DeleteInstanceResponse.SerializeToString,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.DeleteInstanceRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.DeleteInstanceResponse.SerializeToString,
+ ),
+ 'suspend_instance': grpc.unary_unary_rpc_method_handler(
+ servicer.suspend_instance,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.SuspendInstanceRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.SuspendInstanceResponse.SerializeToString,
+ ),
+ 'resume_instance': grpc.unary_unary_rpc_method_handler(
+ servicer.resume_instance,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ResumeInstanceRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ResumeInstanceResponse.SerializeToString,
+ ),
+ 'console_instance': grpc.unary_unary_rpc_method_handler(
+ servicer.console_instance,
+ request_deserializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ConsoleInstanceRequest.FromString,
+ response_serializer=eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ConsoleInstanceResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
- 'omnivirt.InstanceGrpcService', rpc_method_handlers)
+ 'eulerlauncher.InstanceGrpcService', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,))
+ server.add_registered_method_handlers('eulerlauncher.InstanceGrpcService', rpc_method_handlers)
# This class is part of an EXPERIMENTAL API.
@@ -91,11 +160,21 @@ class InstanceGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- 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)
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.InstanceGrpcService/list_instances',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ListInstancesRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ListInstancesResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def create_instance(request,
@@ -108,11 +187,21 @@ class InstanceGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- 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)
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.InstanceGrpcService/create_instance',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.CreateInstanceRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.CreateInstanceResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
@staticmethod
def delete_instance(request,
@@ -125,8 +214,99 @@ class InstanceGrpcService(object):
wait_for_ready=None,
timeout=None,
metadata=None):
- 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)
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.InstanceGrpcService/delete_instance',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.DeleteInstanceRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.DeleteInstanceResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
+
+ @staticmethod
+ def suspend_instance(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.InstanceGrpcService/suspend_instance',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.SuspendInstanceRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.SuspendInstanceResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
+
+ @staticmethod
+ def resume_instance(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.InstanceGrpcService/resume_instance',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ResumeInstanceRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ResumeInstanceResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
+
+ @staticmethod
+ def console_instance(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(
+ request,
+ target,
+ '/eulerlauncher.InstanceGrpcService/console_instance',
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ConsoleInstanceRequest.SerializeToString,
+ eulerlauncher_dot_grpcs_dot_eulerlauncher__grpc_dot_instances__pb2.ConsoleInstanceResponse.FromString,
+ options,
+ channel_credentials,
+ insecure,
+ call_credentials,
+ compression,
+ wait_for_ready,
+ timeout,
+ metadata,
+ _registered_method=True)
diff --git a/eulerlauncher/grpcs/instances.py b/eulerlauncher/grpcs/instances.py
index ec6bc292e07034c3048cb506ae546462e468b134..73a4c8c202c6c7f79cab8765fe73f90a8972b919 100644
--- a/eulerlauncher/grpcs/instances.py
+++ b/eulerlauncher/grpcs/instances.py
@@ -4,20 +4,44 @@ class Instance(object):
def __init__(self, client):
self.client = client
+
def list(self):
"""Get list of instance"""
request = instances_pb2.ListInstancesRequest()
response = self.client.list_instances(request)
return response
+
def create(self, name, image):
"""Create instance"""
request = instances_pb2.CreateInstanceRequest(name=name, image=image)
response = self.client.create_instance(request)
return response
+
def delete(self, name):
"""Delete instance"""
request = instances_pb2.DeleteInstanceRequest(name=name)
response = self.client.delete_instance(request)
return response
+
+
+ def suspend(self, name):
+ """Suspend instance"""
+ request = instances_pb2.SuspendInstanceRequest(name=name)
+ response = self.client.suspend_instance(request)
+ return response
+
+
+ def resume(self, name):
+ """Resume instance"""
+ request = instances_pb2.ResumeInstanceRequest(name=name)
+ response = self.client.resume_instance(request)
+ return response
+
+
+ def console(self, name):
+ """Connect instance"""
+ request = instances_pb2.ConsoleInstanceRequest(name=name)
+ response = self.client.console_instance(request)
+ return response
\ No newline at end of file
diff --git a/eulerlauncher/install.py b/eulerlauncher/install.py
index 30db7ec10654d26e81197fa2149aaab49fef37b7..547ba3bffda0d24c56b3fd4086778db0c4034cf5 100644
--- a/eulerlauncher/install.py
+++ b/eulerlauncher/install.py
@@ -1,7 +1,6 @@
import os
import subprocess
-
if __name__ == '__main__':
base_dir = os.path.dirname(__file__)
diff --git a/eulerlauncher/macos-gui.py b/eulerlauncher/macos-gui.py
index 3562e4f6db2f6a590aa21af157161104c6efda4d..fe4e2011bf63d87ad56d6373ca18b82608f7dc81 100644
--- a/eulerlauncher/macos-gui.py
+++ b/eulerlauncher/macos-gui.py
@@ -1,37 +1,22 @@
import os
import PIL.Image
-import platform
import pystray
import subprocess
+import shutil
import signal
import sys
-from eulerlauncher.utils import constants
-from eulerlauncher.utils import objs
-
-
CONF_DIR_SHELL = '/Library/Application\ Support/org.openeuler.eulerlauncher/eulerlauncher.conf'
CONF_DIR = '/Library/Application Support/org.openeuler.eulerlauncher/eulerlauncher.conf'
-# Avoid create zombie children in MacOS and Linux
-signal.signal(signal.SIGCHLD, signal.SIG_IGN)
if __name__ == '__main__':
try:
- host_arch_raw = platform.uname().machine
- host_arch = constants.ARCH_MAP[host_arch_raw]
base_dir = os.path.dirname(__file__)
-
-
- conf_file = CONF_DIR
logo_file = os.path.join(base_dir,'./etc/favicon.png')
-
- CONF = objs.Conf(conf_file)
-
logo = PIL.Image.open(logo_file)
def on_clicked(icon, item):
-
icon.stop()
icon = pystray.Icon('EulerLauncher', logo, menu=pystray.Menu(
@@ -41,11 +26,24 @@ 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]
+ os.environ['PATH'] += ':/opt/homebrew/bin:/opt/homebrew/sbin'
+
+ libvirtd_bin = shutil.which('libvirtd')
+ libvirtd_cmd = ['sudo', libvirtd_bin]
+ libvirtd = subprocess.Popen(' '.join(libvirtd_cmd), shell=True, preexec_fn=os.setsid)
+
+ virtlogd_bin = shutil.which('virtlogd')
+ virtlogd_cmd = ['sudo', virtlogd_bin]
+ virtlogd = subprocess.Popen(' '.join(virtlogd_cmd), shell=True, preexec_fn=os.setsid)
+
+ launcherd_bin = os.path.join(base_dir, './bin/eulerlauncherd')
+ launcherd_cmd = ['sudo', launcherd_bin, CONF_DIR_SHELL]
launcherd = subprocess.Popen(' '.join(launcherd_cmd), shell=True, preexec_fn=os.setsid)
def term_handler(signum, frame):
subprocess.check_call(['sudo', 'kill', str(launcherd.pid)])
+ subprocess.check_call(['sudo', 'kill', str(virtlogd.pid)])
+ subprocess.check_call(['sudo', 'kill', str(libvirtd.pid)])
# Avoid create orphan children in MacOS and Linux
signal.signal(signal.SIGTERM, term_handler)
@@ -55,4 +53,9 @@ if __name__ == '__main__':
# Shutdown eulerlauncherd, we created it with sudo, so kill it with sudo
subprocess.check_call(['sudo', 'kill', str(launcherd.pid)])
os.waitpid(launcherd.pid, 0)
+ subprocess.check_call(['sudo', 'kill', str(virtlogd.pid)])
+ os.waitpid(virtlogd.pid, 0)
+ subprocess.check_call(['sudo', 'kill', str(libvirtd.pid)])
+ os.waitpid(libvirtd.pid, 0)
+
sys.exit(0)
\ No newline at end of file
diff --git a/eulerlauncher/services/image_service.py b/eulerlauncher/services/image_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..ee65b6cb32da5d7a16318af120bf4a97391e9784
--- /dev/null
+++ b/eulerlauncher/services/image_service.py
@@ -0,0 +1,75 @@
+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.get('default', 'work_dir')
+ self.image_dir = os.path.join(self.work_dir, 'images')
+ self.image_record_path = os.path.join(self.image_dir, 'images.json')
+ if host_os == 'Win':
+ pass
+ # 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 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..d585e1ed8858a2edc53ed5ff215278f0e7ca08ef 100644
--- a/eulerlauncher/services/instance_service.py
+++ b/eulerlauncher/services/instance_service.py
@@ -1,81 +1,100 @@
-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
- self.work_dir = self.CONF.conf.get('default', 'work_dir')
+ def __init__(self, host_arch, host_os, CONF, LOG) -> None:
+ self.CONF = CONF
+ self.LOG = LOG
+ self.work_dir = self.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.instance_record_path = 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_path = 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)
+ pass
+ # 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.LOG)
elif host_os == 'MacOS':
- from eulerlauncher.backends.mac import instance_handler as mac_instance_handler
+ from eulerlauncher.backends 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()
+ def list_instances(self, request, context):
+ 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)
+ elif ret == 3:
+ msg = f'Error: Libvirt error creating instance: {request.name}'
+ 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=ret, msg=msg)
+
+
+ def suspend_instance(self, request, context):
+ self.LOG.debug(f"Get request to suspend instance: {request.name} ...")
+ ret = self.backend.suspend_instance(request.name)
+ msg = ''
+ if ret == 0:
+ msg = f'Successfully suspended instance: {request.name}.'
+ elif ret == 1:
+ msg = f'Error: Instance with name {request.name} does not exist.'
+ return instances_pb2.SuspendInstanceResponse(ret=ret, msg=msg)
+
+
+ def resume_instance(self, request, context):
+ self.LOG.debug(f"Get request to resume instance: {request.name} ...")
+ ret = self.backend.resume_instance(request.name)
+ msg = ''
+ if ret == 0:
+ msg = f'Successfully resumed instance: {request.name}.'
+ elif ret == 1:
+ msg = f'Error: Instance with name {request.name} does not exist.'
+ return instances_pb2.ResumeInstanceResponse(ret=ret, msg=msg)
+
+
+ def console_instance(self, request, context):
+ self.LOG.debug(f"Get request to connect instance: {request.name} ...")
+ ret = self.backend.console_instance(request.name)
+ msg = ''
+ if ret == 0:
+ msg = f'Successfully connected 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.ConsoleInstanceResponse(ret=ret, msg=msg)
\ No newline at end of file
diff --git a/eulerlauncher/utils/constants.py b/eulerlauncher/utils/constants.py
index 9383d2d5f2d0edf75c689631eb017ec0d846b989..daca935303639babf32e222736ffc0533dd40b27 100644
--- a/eulerlauncher/utils/constants.py
+++ b/eulerlauncher/utils/constants.py
@@ -1,37 +1,35 @@
-STORAGE_PROTOCOL_ISCSI = 'iscsi'
-STORAGE_PROTOCOL_FC = 'fibre_channel'
-STORAGE_PROTOCOL_SMBFS = 'smbfs'
-STORAGE_PROTOCOL_RBD = 'rbd'
-
-DISK = "VHD"
-
-IMAGE_LOCATION_REMOTE = 'Remote'
-IMAGE_LOCATION_LOCAL = 'Local'
-
-IMAGE_STATUS_INIT = 'N/A'
-IMAGE_STATUS_DOWLOADABLE = 'Downloadable'
-IMAGE_STATUS_DOWNLOADING = 'Downloading'
-IMAGE_STATUS_LOADING = 'Loading'
-IMAGE_STATUS_READY = 'Ready'
-
-IMAGE_LOAD_SUPPORTED_TYPES = ['qcow2.xz', 'qcow2']
-
-ARCH_MAP = {
- 'AMD64': 'x86_64',
- 'arm64': 'aarch64',
- 'x86_64': 'x86_64'
-}
-
-VM_STATE_MAP = {
- 2: 'Running',
- 3: 'Stopped',
- 10: 'Rebooting',
- 32768: 'Paused',
- 32769: 'Suspended',
- 99: 'N/A'
- }
-
-OS_MAP = {
- 'Darwin': 'MacOS',
- 'Windows': 'Win'
+IMAGE_LOCATION_REMOTE = 'Remote'
+IMAGE_LOCATION_LOCAL = 'Local'
+
+INSTANCE_STATE_MAP = {
+ 0: 'N/A',
+ 1: 'Running',
+ 2: 'Blocked',
+ 3: 'Paused',
+ 4: 'Shutdown',
+ 5: 'Shutoff',
+ 6: 'Crashed',
+ 7: 'Suspended',
+ 99: 'N/A'
+}
+
+IMAGE_STATE_MAP = {
+ 0: 'N/A',
+ 1: 'Downloadable',
+ 2: 'Downloading',
+ 3: 'Loading',
+ 4: 'Ready'
+}
+
+IMAGE_LOAD_SUPPORTED_TYPES = ['qcow2.xz', 'qcow2']
+
+ARCH_MAP = {
+ 'AMD64': 'x86_64',
+ 'arm64': 'aarch64',
+ 'x86_64': 'x86_64'
+}
+
+OS_MAP = {
+ 'Darwin': 'MacOS',
+ 'Windows': 'Win'
}
\ No newline at end of file
diff --git a/eulerlauncher/utils/objs.py b/eulerlauncher/utils/objs.py
deleted file mode 100644
index 714e26d3247e638c9c7748080bb0550d2f9006d5..0000000000000000000000000000000000000000
--- a/eulerlauncher/utils/objs.py
+++ /dev/null
@@ -1,54 +0,0 @@
-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):
-
- def __init__(self, config_file) -> None:
- self.conf = configparser.ConfigParser()
- if not os.path.exists(config_file):
- raise exceptions.NoSuchFile(file=config_file)
- self.conf.read(config_file)
diff --git a/eulerlauncher/utils/utils.py b/eulerlauncher/utils/utils.py
index 8381c74aaddaa9d9418fdc9e08dfa1c014ab1e7b..530eb76753678c47b24a839655a8871ed3d696fd 100644
--- a/eulerlauncher/utils/utils.py
+++ b/eulerlauncher/utils/utils.py
@@ -1,17 +1,14 @@
import functools
import json
-import os
import random
-from threading import Thread
import uuid
-
+import subprocess
+import time
+from threading import Thread
+from lxml import etree
from google.protobuf.json_format import MessageToDict
-from eulerlauncher.utils import exceptions
-from eulerlauncher.utils import objs
-
-
def asyncwrapper(fn):
def wrapper(*args, **kwargs):
thr = Thread(target=fn, args=args, kwargs=kwargs)
@@ -30,37 +27,56 @@ def response2dict(fn):
return wrap
-def parse_config(args):
- if len(args) != 2 or args[0] != '--config-file':
- raise exceptions.NoConfigFileProvided
- if not os.path.exists(args[1]):
- raise exceptions.NoSuchFile(file=args[1])
-
- return objs.Conf(args[1])
-
+def check_format(file_name, to_check):
+
+ ret = False
+ ret_fmt = None
-def format_mac_addr(mac_str):
- ret = ''
- if len(mac_str) != 12:
- return ret
- mac_low = mac_str.lower()
- for i in range(0, 5):
- ret = ret + mac_low[2 * i] + mac_low[2 * i + 1] + '-'
- ret = ret + mac_low[-2] + mac_low[-1]
+ for fmt in to_check:
+ if file_name.endswith(fmt):
+ ret = True
+ ret_fmt = fmt
+ break
- return ret
+ return ret, ret_fmt
+
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 xml_find_and_set(xml, xpath, attribute=None, value=None):
+ namespaces = xml.getroot().nsmap
+ elements = xml.xpath(xpath, namespaces=namespaces)
+ 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
+
+
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 generate_mac():
+
+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_address():
local_mac = uuid.uuid1().hex[-12:]
mac = [random.randint(0x00, 0xff), random.randint(0x00, 0xff)]
@@ -70,25 +86,34 @@ def generate_mac():
return (':'.join(s))
-def catch_exception(func):
-
- def wrap(*args, **kwargs):
- try:
- return func(*args, **kwargs)
- except Exception:
- raise exceptions.OmniVirtdNotAvailable
-
- return wrap
-def check_file_tail(file_name, to_check):
-
- ret = False
- ret_fmt = None
-
- for fmt in to_check:
- if file_name.endswith(fmt):
- ret = True
- ret_fmt = fmt
+def parse_ip_address(mac_address):
+ ip_address = ''
+ cmd = 'arp -a'
+ start_time = time.time()
+ while(ip_address == '' 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_address == mac_0:
+ ip_address = arp_ip
+ founded = True
+ break
+ if founded:
break
- return ret, ret_fmt
+ return ip_address
diff --git a/requirements-win.txt b/requirements-win.txt
deleted file mode 100644
index b67b36dc4415cf837515d153a8423b9e6e45fb9a..0000000000000000000000000000000000000000
--- a/requirements-win.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-argparse
-click
-configparser
-dnspython
-grpcio
-grpcio-tools
-lxml
-os-win
-oslo.concurrency
-oslo.config
-oslo.context
-oslo.i18n
-oslo.log
-oslo.serialization
-oslo.utils
-Pillow
-prettytable
-protobuf
-psutil
-pystray
-PyYAML
-six
-urllib3
-wget
diff --git a/requirements.txt b/requirements.txt
index db5e0f68c92003b71fc38050787376e243cb4a4a..339a5ec972071f40d113861bcf8c4bd91bbf8b93 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,9 +4,7 @@ configparser
dnspython
grpcio
grpcio-tools
-pkg-config
lxml
-os-win
oslo.concurrency
oslo.config
oslo.context
@@ -23,3 +21,4 @@ PyYAML
six
urllib3
wget
+libvirt-python
\ No newline at end of file
diff --git a/resources/libvirt/libvirt-aarch64.xml b/resources/libvirt/libvirt-aarch64.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ab03dbb9a846fd80654c81611e756ec4348d0bf7
--- /dev/null
+++ b/resources/libvirt/libvirt-aarch64.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+ hvm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/libvirt/libvirt-x86_64.xml b/resources/libvirt/libvirt-x86_64.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1389e9e84bb169e7850308af44ec09225da06ce9
--- /dev/null
+++ b/resources/libvirt/libvirt-x86_64.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ 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/setup.cfg b/setup.cfg
index 5841eef71b88e004dc06a724e19d98f6b8b139e2..f0977ddadff30e24d6cf2b4b29ebc25de49c0b5d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = eulerlauncher
-version = 0.2
+version = 0.3.2rc
summary = A tool to run openEuler instances on all platforms
description_file =
README.md
diff --git a/specs/EulerLauncher-MacOS.spec b/specs/EulerLauncher-Mac.spec
similarity index 82%
rename from specs/EulerLauncher-MacOS.spec
rename to specs/EulerLauncher-Mac.spec
index 8952fca46ba4eb075a554fdcf7e45e50327179e3..ae23a3f5811fae35e7945a800a3a9d1202a5743c 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')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
@@ -19,6 +19,7 @@ a = Analysis(
cipher=block_cipher,
noarchive=False,
)
+
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
@@ -37,13 +38,14 @@ exe = EXE(
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
- argv_emulation=False,
+ argv_emulation=True,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
uac_admin=True,
icon=['etc/images/favicon.ico'],
)
+
app = BUNDLE(
exe,
name='EulerLauncher.app',
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/cli-mac.spec b/specs/cli-mac.spec
index 4f5036659ec535fa44d3b409b88a9163dabf358f..419869d654c7e6aafebecbd6437f245d23761779 100644
--- a/specs/cli-mac.spec
+++ b/specs/cli-mac.spec
@@ -1,9 +1,7 @@
# -*- mode: python ; coding: utf-8 -*-
-
block_cipher = None
-
a = Analysis(
['../eulerlauncher/cli.py'],
pathex=[],
@@ -19,6 +17,7 @@ a = Analysis(
cipher=block_cipher,
noarchive=False,
)
+
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
@@ -41,4 +40,4 @@ exe = EXE(
target_arch=None,
codesign_identity=None,
entitlements_file=None,
-)
+)
\ No newline at end of file
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={},