From 2eeccf941c6050f7298b6ee40bc467a188790dcb Mon Sep 17 00:00:00 2001
From: Zhu Huankai <zhuhuankai1@huawei.com>
Date: Fri, 15 Oct 2021 15:20:35 +0800
Subject: [PATCH 3/4] virt: adapt hydropper for stratovirt2.0

recode virt and add standvm code.

Signed-off-by: Zhu Huankai <zhuhuankai1@huawei.com>
---
 tests/hydropper/README.cn.md                  |   4 +-
 tests/hydropper/README.md                     |   4 +-
 tests/hydropper/config/config.ini             |   3 +
 .../test_config/vm_config/micro_vm.json       |  21 +-
 .../test_config/vm_config/stand_vm.json       |  27 ++
 tests/hydropper/conftest.py                   |  27 ++
 tests/hydropper/utils/config.py               |   9 +
 tests/hydropper/utils/exception.py            |   6 +
 tests/hydropper/virt/basevm.py                | 235 ++-----------
 tests/hydropper/virt/microvm.py               | 192 ++++++++++-
 tests/hydropper/virt/standvm.py               | 325 ++++++++++++++++++
 11 files changed, 627 insertions(+), 226 deletions(-)
 create mode 100644 tests/hydropper/config/test_config/vm_config/stand_vm.json
 create mode 100644 tests/hydropper/virt/standvm.py

diff --git a/tests/hydropper/README.cn.md b/tests/hydropper/README.cn.md
index c74493d..eeec079 100644
--- a/tests/hydropper/README.cn.md
+++ b/tests/hydropper/README.cn.md
@@ -72,8 +72,8 @@ $ pytest -k microvm
 # 执行test_microvm_cmdline中的全部用例
 $ pytest testcases/microvm/functional/test_microvm_cmdline.py
 
-# 执行test_microvm_with_json用例
-$ pytest testcases/microvm/functional/test_microvm_cmdline.py::test_microvm_with_json
+# 执行test_microvm_without_daemonize用例
+$ pytest testcases/microvm/functional/test_microvm_cmdline.py::test_microvm_without_daemonize
 ```
 
 ### 增加测试用例
diff --git a/tests/hydropper/README.md b/tests/hydropper/README.md
index a44ab42..1bcd65e 100644
--- a/tests/hydropper/README.md
+++ b/tests/hydropper/README.md
@@ -74,8 +74,8 @@ $ pytest -k microvm
 # Run all cases in test_microvm_cmdline.py
 $ pytest testcases/microvm/functional/test_microvm_cmdline.py
 
-# Run test_microvm_with_json
-$ pytest testcases/microvm/functional/test_microvm_cmdline.py::test_microvm_with_json
+# Run test_microvm_without_daemonize
+$ pytest testcases/microvm/functional/test_microvm_cmdline.py::test_microvm_without_daemonize
 ```
 
 ### Add new testcases
diff --git a/tests/hydropper/config/config.ini b/tests/hydropper/config/config.ini
index c6d2a88..68d40f5 100644
--- a/tests/hydropper/config/config.ini
+++ b/tests/hydropper/config/config.ini
@@ -17,6 +17,7 @@ CONCURRENT_QUANTITY = 10
 # Default Configuration Parameters
 # Stratovirt binary file path
 STRATOVIRT_MICROVM_BINARY = /usr/bin/stratovirt
+STRATOVIRT_STANDVM_BINARY = /usr/bin/stratovirt
 
 # Configure common basic parameters in the JSON file.
 STRATOVIRT_MICROVM_CONFIG = config/test_config/vm_config/micro_vm.json
@@ -30,9 +31,11 @@ STRATOVIRT_MICROVM_CONFIG = config/test_config/vm_config/micro_vm.json
 #   def test_xxx(test_microvm_with_initrd):
 #
 STRATOVIRT_ROOTFS = /home/microvm_image/openEuler-stratovirt.img
+STRATOVIRT_STAND_ROOTFS = /home/standvm_image/openEuler-stratovirt.img
 
 # Kernel
 STRATOVIRT_VMLINUX = /home/microvm_image/vmlinux.bin
+STRATOVIRT_STAND_VMLINUX = /home/standvm_image/std-vmlinuxz
 
 # User-defined parameters.
 # Users can add parameters here. Then adapt configparser in config.py to use them.
diff --git a/tests/hydropper/config/test_config/vm_config/micro_vm.json b/tests/hydropper/config/test_config/vm_config/micro_vm.json
index 227045e..687ffc1 100644
--- a/tests/hydropper/config/test_config/vm_config/micro_vm.json
+++ b/tests/hydropper/config/test_config/vm_config/micro_vm.json
@@ -3,16 +3,25 @@
     "kernel_image_path": "${VMLINUX}",
     "boot_args": "rw console=hvc0 lastbus=0 reboot=k panic=1 tsc=reliable ipv6.disable=1 root=/dev/vda"
   },
-  "drive": [
+  "block": [
     {
-      "drive_id": "rootfs",
-      "path_on_host": "${ROOTFS}",
-      "direct": true,
-      "read_only": false
+      "drive": [
+        {
+          "drive_id": "rootfs",
+          "path_on_host": "${ROOTFS}",
+          "direct": true,
+          "read_only": false
+        }
+      ],
+      "device": [
+        {
+          "drive_id": "rootfs"
+        }
+      ]
     }
   ],
   "machine-config": {
     "vcpu_count": "${VCPU}",
     "mem_size": "${MEMSIZE}"
   }
-}
+}
\ No newline at end of file
diff --git a/tests/hydropper/config/test_config/vm_config/stand_vm.json b/tests/hydropper/config/test_config/vm_config/stand_vm.json
new file mode 100644
index 0000000..687ffc1
--- /dev/null
+++ b/tests/hydropper/config/test_config/vm_config/stand_vm.json
@@ -0,0 +1,27 @@
+{
+  "boot-source": {
+    "kernel_image_path": "${VMLINUX}",
+    "boot_args": "rw console=hvc0 lastbus=0 reboot=k panic=1 tsc=reliable ipv6.disable=1 root=/dev/vda"
+  },
+  "block": [
+    {
+      "drive": [
+        {
+          "drive_id": "rootfs",
+          "path_on_host": "${ROOTFS}",
+          "direct": true,
+          "read_only": false
+        }
+      ],
+      "device": [
+        {
+          "drive_id": "rootfs"
+        }
+      ]
+    }
+  ],
+  "machine-config": {
+    "vcpu_count": "${VCPU}",
+    "mem_size": "${MEMSIZE}"
+  }
+}
\ No newline at end of file
diff --git a/tests/hydropper/conftest.py b/tests/hydropper/conftest.py
index e6d417e..f0768c0 100644
--- a/tests/hydropper/conftest.py
+++ b/tests/hydropper/conftest.py
@@ -16,9 +16,11 @@ import uuid
 import shutil
 import tempfile
 import time
+import platform
 from subprocess import run
 import pytest
 from virt.microvm import MicroVM
+from virt.standvm import StandVM
 from monitor.monitor_thread import MonitorThread
 from utils.config import CONFIG
 
@@ -72,6 +74,21 @@ def init_microvm(root_path, bin_path=CONFIG.stratovirt_microvm_bin, **kwargs):
 
     return testvm
 
+def init_standvm(root_path, bin_path=CONFIG.stratovirt_standvm_bin, **kwargs):
+    """Auxiliary to init a standardvm"""
+    vm_uuid = str(uuid.uuid4())
+    if "aarch" in platform.machine():
+        testvm = StandVM(root_path, "standvm", vm_uuid,
+                        bin_path=bin_path, machine="virt",
+                        **kwargs
+                        )
+    else:
+        testvm = StandVM(root_path, "standvm", vm_uuid,
+                        bin_path=bin_path, machine="q35",
+                        **kwargs
+                        )
+
+    return testvm
 
 def init_microvm_with_json(root_path, vm_config_json, vmtag):
     """Init a microvm from a json file"""
@@ -133,6 +150,16 @@ def microvm(test_session_root_path):
     testvm.kill()
 
 
+@pytest.fixture()
+def standvm(test_session_root_path):
+    """Instantiate a standardvm"""
+    # pylint: disable=redefined-outer-name
+    # The pytest.fixture triggers a pylint rule.
+    testvm = init_standvm(test_session_root_path)
+    yield testvm
+    testvm.kill()
+
+
 @pytest.fixture()
 def microvm_with_tcp(test_session_root_path):
     """Init a microvm"""
diff --git a/tests/hydropper/utils/config.py b/tests/hydropper/utils/config.py
index d86c969..9c3ad7a 100644
--- a/tests/hydropper/utils/config.py
+++ b/tests/hydropper/utils/config.py
@@ -71,14 +71,19 @@ class ParserConfig(Singleton):
 
         # parser stratovirt config
         self.stratovirt_microvm_bin = self.get_option("stratovirt.params", "STRATOVIRT_MICROVM_BINARY", None)
+        self.stratovirt_standvm_bin = self.get_option("stratovirt.params", "STRATOVIRT_STANDVM_BINARY", None)
         self.stratovirt_microvm_boottime_bin = self.get_option("stratovirt.params",
                                                                "STRATOVIRT_MICROVM_BOOTTIME_BINARY", None)
         self.stratovirt_microvm_config = self.get_option("stratovirt.params", "STRATOVIRT_MICROVM_CONFIG",
                                                          "config/test_config/vm_config/micro_vm.json")
+        self.stratovirt_standvm_config = self.get_option("stratovirt.params", "STRATOVIRT_STANDVM_CONFIG",
+                                                         "config/test_config/vm_config/stand_vm.json")
         self.stratovirt_binary_name = self.get_option("stratovirt.params",
                                                       "STRATOVIRT_BINARY_NAME", "microvm")
         self.stratovirt_vmlinux = self.get_option("stratovirt.params", "STRATOVIRT_VMLINUX", None)
+        self.stratovirt_stand_vmlinux = self.get_option("stratovirt.params", "STRATOVIRT_STAND_VMLINUX", None)
         self.stratovirt_rootfs = self.get_option("stratovirt.params", "STRATOVIRT_ROOTFS", None)
+        self.stratovirt_stand_rootfs = self.get_option("stratovirt.params", "STRATOVIRT_STAND_ROOTFS", None)
         self.stratovirt_initrd = self.get_option("stratovirt.params", "STRATOVIRT_INITRD", None)
         self.stratovirt_use_config_file = bool(self.get_option("stratovirt.params", "STRATOVIRT_USE_CONFIG_FILE",
                                                                "false") == "true")
@@ -155,5 +160,9 @@ class ParserConfig(Singleton):
         """Get default microvm vmconfig file"""
         return self.stratovirt_microvm_config
 
+    def get_default_standvm_vmconfig(self):
+        """Get default standvm vmconfig file"""
+        return self.stratovirt_standvm_config
+
 
 CONFIG = ParserConfig()
diff --git a/tests/hydropper/utils/exception.py b/tests/hydropper/utils/exception.py
index c4f9834..5763a6a 100644
--- a/tests/hydropper/utils/exception.py
+++ b/tests/hydropper/utils/exception.py
@@ -131,3 +131,9 @@ class QMPTimeoutError(QMPError):
 
 class VMLifeError(Exception):
     """Vmlife error exception"""
+
+# standvm error
+class PflashError(Exception):
+    "Lack of code storage file"
+    def __str__(self):
+        return "code_storage_file is not found"
\ No newline at end of file
diff --git a/tests/hydropper/virt/basevm.py b/tests/hydropper/virt/basevm.py
index d44c4e4..b360d97 100644
--- a/tests/hydropper/virt/basevm.py
+++ b/tests/hydropper/virt/basevm.py
@@ -19,7 +19,6 @@ import logging
 import socket
 import errno
 import aexpect
-from aexpect.exceptions import ExpectError
 from retrying import retry
 from utils.config import CONFIG
 from utils import utils_common
@@ -28,7 +27,6 @@ from utils import remote
 from utils.utils_logging import TestLog
 from utils.session import ConsoleManager
 from utils.resources import NETWORKS
-from utils.resources import VSOCKS
 from utils.exception import VMLifeError
 from utils.exception import QMPError
 from utils.exception import QMPConnectError
@@ -45,21 +43,15 @@ SERIAL_TIMEOUT = 0.5 if CONFIG.timeout_factor > 1 else None
 
 class BaseVM:
     """Class to represent a extract base vm."""
-    logger = TestLog.get_global_log()
 
-    def __init__(self, root_path, name, uuid, bin_path,
-                 wrapper=None, args=None, mon_sock=None,
+    def __init__(self, root_path, name, uuid, bin_path, args=None, mon_sock=None,
                  vnetnums=1, rng=False, max_bytes=0, vsocknums=0, balloon=False,
                  vmtype=CONFIG.vmtype, machine=None, freeze=False,
                  daemon=False, config=None, ipalloc="static", incoming=False,
                  error_test=False, dump_guest_core=True, mem_share=True):
-        if wrapper is None:
-            wrapper = []
         if args is None:
             args = []
         self.qmp_protocol = None
-        # self.__qmp = None
-        # self.__qmp_set = True
         # Copy args in case ew modify them.
         self._args = list(args)
         self._console_address = None
@@ -104,6 +96,8 @@ class BaseVM:
         self.ssh_session = None
         self.taps = list()
         self.vhost_type = None
+        self.vhostfd = None
+        self.net_iothread = None
         self.vmid = uuid
         self.vmtype = vmtype
         self.vnetnums = vnetnums
@@ -111,10 +105,8 @@ class BaseVM:
         self.max_bytes = max_bytes
         self.vsock_cid = list()
         self.vsocknums = vsocknums
-        self.with_json = False
         self.withmac = False
         self.withpid = False
-        self.wrapper = wrapper
         self.balloon = balloon
         self.deflate_on_oom = False
 
@@ -150,7 +142,7 @@ class BaseVM:
 
         self._pre_shutdown()
         if self.daemon or self.is_running():
-            if self.qmp_protocol.qmp_set:
+            if self.qmp_protocol:
                 try:
                     if not has_quit:
                         self.qmp_protocol.qmp_command('quit')
@@ -219,7 +211,7 @@ class BaseVM:
                 command = ''
             LOG.warning(msg, exitcode, command)
 
-        if self.qmp_protocol.qmp_set:
+        if self.qmp_protocol:
             self.qmp_protocol.close_sock()
 
         if self.serial_session:
@@ -244,7 +236,7 @@ class BaseVM:
                                             self._name + "_" + self.vmid + ".sock")
             self._remove_files.append(self._vm_monitor)
 
-        self.parser_config_to_args()
+        # self.parser_config_to_args()
 
     def create_serial_control(self):
         """Create serial control"""
@@ -297,37 +289,6 @@ class BaseVM:
                              CONFIG.vm_password, local_file, dest_file,
                              output_func=self.serial_log.debug, timeout=60.0)
 
-    def launch(self):
-        """Start a vm and establish a qmp connection"""
-        del self._args
-        self._args = list(self.init_args)
-        self._pre_launch()
-        self.full_command = (self.wrapper + [self.bin_path] + self._base_args() + self._args)
-        LOG.debug(self.full_command)
-        if not self.env.keys():
-            self._popen = subprocess.Popen(self.full_command,
-                                           stdin=subprocess.PIPE,
-                                           stdout=subprocess.PIPE,
-                                           shell=False,
-                                           close_fds=True)
-        else:
-            _tempenv = os.environ.copy()
-            for key, _ in self.env.items():
-                _tempenv[key] = self.env[key]
-            self._popen = subprocess.Popen(self.full_command,
-                                           stdin=subprocess.PIPE,
-                                           stdout=subprocess.PIPE,
-                                           shell=False,
-                                           close_fds=True,
-                                           env=_tempenv)
-
-        if self.daemon:
-            self._popen.wait()
-            self.pid = self.get_pid()
-        else:
-            self.pid = self._popen.pid
-        if not self.error_test:
-            self._post_launch()
 
     def post_launch_serial(self):
         """Create a serial and wait for active"""
@@ -339,11 +300,8 @@ class BaseVM:
 
     def post_launch_qmp(self):
         """Set a QMPMonitorProtocol"""
-        if isinstance(self.mon_sock, tuple):
-            self.qmp_protocol = QMPProtocol(self.mon_sock)
-        else:
-            self.qmp_protocol = QMPProtocol(self._vm_monitor)
-        if self.qmp_protocol.qmp_set:
+        self.qmp_protocol = QMPProtocol(self._vm_monitor)
+        if self.qmp_protocol:
             self.qmp_protocol.connect()
 
     def post_launch_vnet(self):
@@ -437,87 +395,36 @@ class BaseVM:
         else:
             args.extend(['-machine', self._machine])
 
-    def _base_args(self):
+    def _common_args(self):
         args = []
         if self._name:
             args.extend(['-name', self._name])
         # uuid is not supported yet, no need to add uuid
         if self.logpath:
             args.extend(['-D', self.logpath])
+
         if "stratovirt" in self.vmtype:
-            if isinstance(self.mon_sock, tuple):
-                args.extend(['-qmp',
-                                "tcp:" + str(self.mon_sock[0]) + ":" + str(self.mon_sock[1])])
-            else:
-                args.extend(['-qmp', "unix:" + self.mon_sock + ",server,nowait"])
-        else:
-            moncdev = 'socket,id=mon,path=%s' % self.mon_sock
-            args.extend(['-chardev', moncdev, '-mon',
-                            'chardev=mon,mode=control'])
+            args.extend(['-qmp', "unix:" + self.mon_sock + ",server,nowait"])
 
         if self.withpid:
             self.pidfile = os.path.join(self._sock_dir, self._name + "_" + "pid.file")
             args.extend(['-pidfile', self.pidfile])
+
         if self._machine is not None:
             self._machine_args(args)
 
-        if self._console_set:
-            self._console_address = os.path.join(self._sock_dir,
-                                                 self._name + "_" + self.vmid + "-console.sock")
-            # It doesn't need to create it first.
-            self._remove_files.append(self._console_address)
-            args.extend(['-device', 'virtio-serial-device', '-chardev', 'socket,path=%s,id=virtioconsole0,server,nowait' % self._console_address, '-device', 'virtconsole,chardev=virtioconsole0,id=console_0'])
-
-        if self.vnetnums > 0:
-            for _ in range(self.vnetnums - len(self.taps)):
-                tapinfo = NETWORKS.generator_tap()
-                LOG.debug("current tapinfo is %s" % tapinfo)
-                self.taps.append(tapinfo)
-
-            for tapinfo in self.taps:
-                tapname = tapinfo["name"]
-                _tempargs = "tap,id=%s,ifname=%s" % (tapname, tapname)
-                if self.vhost_type:
-                    _tempargs += ",vhost=on"
-                _devargs = "virtio-net-device,netdev=%s,id=%s" % (tapname, tapname)
-                if self.withmac:
-                    _devargs += ",mac=%s" % tapinfo["mac"]
-                args.extend(['-netdev', _tempargs, '-device', _devargs])
-
-        if self.rng:
-            rngcfg = 'rng-random,id=objrng0,filename=/dev/urandom'
-            if self.max_bytes == 0:
-                devcfg = 'virtio-rng-device,rng=objrng0'
-            else:
-                devcfg = 'virtio-rng-device,rng=objrng0,max-bytes=%s,period=1000' % self.max_bytes
-            args.extend(['-object', rngcfg, '-device', devcfg])
-
-        if self.vsocknums > 0:
-            if VSOCKS.init_vsock():
-                for _ in range(self.vsocknums - len(self.vsock_cid)):
-                    sockcid = VSOCKS.find_contextid()
-                    self.vsock_cid.append(sockcid)
-                    args.extend(['-device',
-                                 'vhost-vsock-device,id=vsock-%s,'
-                                 'guest-cid=%s' % (sockcid, sockcid)])
-
-        if self.balloon:
-            if self.deflate_on_oom:
-                ballooncfg = 'deflate-on-oom=true'
-            else:
-                ballooncfg = 'deflate-on-oom=false'
-            args.extend(['-device', 'virtio-balloon-device', ballooncfg])
-
         if "stratovirt" in self.vmtype and not self.seccomp:
-            self._args.append('-disable-seccomp')
+            args.append('-disable-seccomp')
 
         if self.daemon:
-            self._args.append('-daemonize')
+            args.append('-daemonize')
 
         if self.freeze:
-            self._args.extend(['-S'])
+            args.extend(['-S'])
+
         return args
 
+
     def is_running(self):
         """Returns true if the VM is running."""
         return self._popen is not None and self._popen.poll() is None
@@ -529,90 +436,23 @@ class BaseVM:
         return self._popen.poll()
 
     def add_drive(self, **kwargs):
-        """Add drive"""
+        """Add drive and device"""
         drivetemp = dict()
+        devicetemp = dict()
         drivetemp["drive_id"] = kwargs.get("drive_id", utils_network.generate_random_name())
+        devicetemp["drive_id"] = drivetemp["drive_id"]
         drivetemp["path_on_host"] = kwargs.get('path_on_host', None)
         drivetemp["read_only"] = kwargs.get("read_only", "true")
-        if "drive" in self.configdict:
-            self.configdict["drive"].append(drivetemp)
+        if "drive" in self.configdict["block"][0]:
+            self.configdict["block"][0]["drive"].append(drivetemp)
         else:
-            self.configdict["drive"] = [drivetemp]
-
-    def basic_config(self, **kwargs):
-        """Change configdict"""
-        if "vcpu_count" in kwargs:
-            self.configdict["machine-config"]["vcpu_count"] = kwargs.get("vcpu_count")
-            del kwargs["vcpu_count"]
-        if "max_vcpus" in kwargs:
-            self.configdict["machine-config"]["max_vcpus"] = kwargs.get("max_vcpus")
-            del kwargs["max_vcpus"]
-        if "mem_size" in kwargs:
-            self.configdict["machine-config"]["mem_size"] = kwargs.get("mem_size")
-            del kwargs["mem_size"]
-        if "mem_path" in kwargs:
-            self.configdict["machine-config"]["mem_path"] = kwargs.get("mem_path")
-            del kwargs["mem_path"]
-        if "vhost_type" in kwargs:
-            self.vhost_type = kwargs.get("vhost_type")
-            del kwargs["vhost_type"]
-
-        for key, value in kwargs.items():
-            if hasattr(self, key):
-                setattr(self, key, value)
-
-    def parser_config_to_args(self):
-        """Parser json config to args"""
-        if self.configdict is None:
-            return
+            self.configdict["block"][0]["drive"] = [drivetemp]
 
-        if self.with_json:
-            with open(self.config_json, "w") as fpdest:
-                json.dump(self.configdict, fpdest)
-            self.add_args('-config', self.config_json)
+        if "device" in self.configdict["block"][0]:
+            self.configdict["block"][0]["device"].append(devicetemp)
         else:
-            configdict = self.configdict
-            if "boot-source" in configdict:
-                if "kernel_image_path" in configdict["boot-source"]:
-                    self.add_args('-kernel', configdict["boot-source"]["kernel_image_path"])
-                if "boot_args" in configdict["boot-source"]:
-                    self.add_args('-append', configdict["boot-source"]["boot_args"])
-                if "initrd" in configdict["boot-source"]:
-                    self.add_args('-initrd', configdict["boot-source"]["initrd"])
-
-            if "machine-config" in configdict:
-                _temp_cpu_value = ""
-                if "vcpu_count" in configdict["machine-config"]:
-                    _temp_cpu_value = str(configdict["machine-config"]["vcpu_count"])
-                if "max_vcpus" in configdict["machine-config"]:
-                    _temp_cpu_value += ",maxcpus=%s" % configdict["machine-config"]["max_vcpus"]
-                if _temp_cpu_value != "":
-                    self.add_args('-smp', _temp_cpu_value)
-                _temp_mem_value = ""
-                if "mem_size" in configdict["machine-config"]:
-                    _temp_mem_value = str(configdict["machine-config"]["mem_size"])
-                if "mem_slots" in configdict["machine-config"] and \
-                        "max_mem" in configdict["machine-config"]:
-                    _temp_mem_value += ",slots=%s,maxmem=%s" % \
-                                       (configdict["machine-config"]["mem_slots"],
-                                        configdict["machine-config"]["max_mem"])
-                if _temp_mem_value != "":
-                    self.add_args('-m', _temp_mem_value)
-                if "mem_path" in configdict["machine-config"]:
-                    self.add_args('-mem-path', configdict["machine-config"]["mem_path"])
-
-            for drive in configdict.get("drive", []):
-                _temp_drive_value = ""
-                if "drive_id" in drive:
-                    _temp_drive_value = "id=%s" % drive["drive_id"]
-                if "path_on_host" in drive:
-                    _temp_drive_value += ",file=%s" % drive["path_on_host"]
-                if "read_only" in drive:
-                    _temp = "on" if drive["read_only"] else "off"
-                    _temp_drive_value += ",readonly=%s" % _temp
-                if _temp_drive_value != "":
-                    self.add_args('-drive', _temp_drive_value)
-                    self.add_args('-device', 'virtio-blk-device,drive=%s' % drive["drive_id"])
+            self.configdict["block"][0]["device"] = [devicetemp]
+
 
     def add_env(self, key, value):
         """Add key, value to self.env"""
@@ -626,13 +466,6 @@ class BaseVM:
         """Add the machine type to cmdline"""
         self._machine = machine_type
 
-    def console_enable(self):
-        """Set console"""
-        self._console_set = True
-
-    def console_disable(self):
-        """Unset console"""
-        self._console_set = False
 
     def set_device_type(self, device_type):
         """Set device type"""
@@ -743,7 +576,7 @@ class BaseVM:
         LOG.debug("hotplug disk %s to vm" % diskpath)
         devid = "drive-%d" % index
         resp = self.qmp_protocol.qmp_command("blockdev-add", node_name="drive-%d" % index,
-                                file={"driver": "file", "filename": diskpath})
+                                             file={"driver": "file", "filename": diskpath})
 
         LOG.debug("blockdev-add return %s" % resp)
         if check:
@@ -821,10 +654,7 @@ class BaseVM:
         """Reconnect qmp when sock is dead"""
         if self.qmp_protocol:
             self.qmp_protocol.close_sock()
-        if isinstance(self.mon_sock, tuple):
-            self.qmp_protocol = QMPProtocol(self.mon_sock)
-        else:
-            self.qmp_protocol = QMPProtocol(self._vm_monitor)
+        self.qmp_protocol = QMPProtocol(self._vm_monitor)
         if self.qmp_protocol:
             self.qmp_protocol.connect()
 
@@ -849,13 +679,12 @@ class BaseVM:
             self._events.append(event)
 
 class QMPProtocol:
-    
+
     '''Set qmp monitor protocol'''
     def __init__(self, address):
-        self.qmp_set = True
         self.events = list()
         self.address = address
-        self.sock =  socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
 
     def __sock_recv(self, only_event=False):
         """Get data from socket"""
@@ -980,4 +809,4 @@ class QMPProtocol:
             if only_event:
                 return self.events.pop(0)
             return self.events
-        return None
\ No newline at end of file
+        return None
diff --git a/tests/hydropper/virt/microvm.py b/tests/hydropper/virt/microvm.py
index e889736..7b83989 100644
--- a/tests/hydropper/virt/microvm.py
+++ b/tests/hydropper/virt/microvm.py
@@ -14,20 +14,24 @@
 import os
 import json
 import logging
+import subprocess
 from virt.basevm import BaseVM
+from utils.utils_logging import TestLog
 from utils.config import CONFIG
+from utils.resources import NETWORKS
+from utils.resources import VSOCKS
 from monitor.mem_usage_info import MemoryUsageExceededInfo
 
 LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
 logging.basicConfig(filename="/var/log/pytest.log", level=logging.DEBUG, format=LOG_FORMAT)
+LOG = TestLog.get_global_log()
 
 class MicroVM(BaseVM):
     """Class to represent a microvm"""
     def __init__(self, root_path, name, uuid, bin_path=CONFIG.stratovirt_microvm_bin,
                  vmconfig=CONFIG.get_default_microvm_vmconfig(),
                  vmlinux=CONFIG.stratovirt_vmlinux, rootfs=CONFIG.stratovirt_rootfs, initrd=CONFIG.stratovirt_initrd,
-                 vcpus=4, max_vcpus=8, memslots=0, maxmem=None,
-                 memsize=2048, socktype="unix", loglevel="info"):
+                 vcpus=4, memsize=2048, socktype="unix", loglevel="info"):
         self.name = name
         self.vmid = uuid
         if "unix" in socktype:
@@ -40,10 +44,7 @@ class MicroVM(BaseVM):
         self.rootfs = rootfs
         self.initrd = initrd
         self.vcpus = vcpus
-        self.max_vcpus = max_vcpus
-        self.memslots = memslots
         self.memsize = memsize
-        self.maxmem = maxmem
         self.inited = False
         self.init_vmjson(root_path)
         self._args = list()
@@ -91,17 +92,12 @@ class MicroVM(BaseVM):
                 _vm_json["boot-source"]["kernel_image_path"] = self.vmlinux
                 if "initrd" in _vm_json["boot-source"]:
                     _vm_json["boot-source"]["initrd"] = self.initrd
-            if "drive" in _vm_json:
-                _vm_json["drive"][0]["path_on_host"] = self.rootfs
+            if "block" in _vm_json:
+                # one by default
+                _vm_json["block"][0]["drive"][0]["path_on_host"] = self.rootfs
             if "machine-config" in _vm_json:
                 _vm_json["machine-config"]["vcpu_count"] = int(self.vcpus)
                 _vm_json["machine-config"]["mem_size"] = self.memsize
-                if "max_vcpus" in _vm_json["machine-config"]:
-                    _vm_json["machine-config"]["max_vcpus"] = int(self.max_vcpus)
-                if "mem_slots" in _vm_json["machine-config"]:
-                    _vm_json["machine-config"]["mem_slots"] = int(self.memslots)
-                if self.maxmem is None and "max_mem" in _vm_json["machine-config"]:
-                    _vm_json["machine-config"]["max_mem"] = self.memsize
 
             with open(self.vm_json_file, "w") as fpdest:
                 json.dump(_vm_json, fpdest)
@@ -110,3 +106,173 @@ class MicroVM(BaseVM):
     def add_fake_pci_bridge_args(self):
         """Add fake pcibridge config"""
         self._args.extend(['-serial'])
+
+    def launch(self):
+        """Start a microvm and establish a qmp connection"""
+        del self._args
+        self._args = list(self.init_args)
+        self._pre_launch()
+        self.parser_config_to_args()
+        self.full_command = ([self.bin_path] + self._base_args() + self._args)
+        LOG.debug(self.full_command)
+        if not self.env.keys():
+            self._popen = subprocess.Popen(self.full_command,
+                                           stdin=subprocess.PIPE,
+                                           stdout=subprocess.PIPE,
+                                           shell=False,
+                                           close_fds=True)
+        else:
+            _tempenv = os.environ.copy()
+            for key, _ in self.env.items():
+                _tempenv[key] = self.env[key]
+            self._popen = subprocess.Popen(self.full_command,
+                                           stdin=subprocess.PIPE,
+                                           stdout=subprocess.PIPE,
+                                           shell=False,
+                                           close_fds=True,
+                                           env=_tempenv)
+
+        if self.daemon:
+            self._popen.wait()
+            self.pid = self.get_pid()
+        else:
+            self.pid = self._popen.pid
+        if not self.error_test:
+            self._post_launch()
+
+    def _base_args(self):
+        args = self._common_args()
+        if self._console_set:
+            self._console_address = os.path.join(self._sock_dir,
+                                                 self._name + "_" + self.vmid + "-console.sock")
+            # It doesn't need to create it first.
+            self._remove_files.append(self._console_address)
+            args.extend(['-device', 'virtio-serial-device', '-chardev',
+                         'socket,path=%s,id=virtioconsole0,server,nowait' % self._console_address,
+                         '-device', 'virtconsole,chardev=virtioconsole0,id=console_0'])
+
+        if self.vnetnums > 0:
+            for _ in range(self.vnetnums - len(self.taps)):
+                tapinfo = NETWORKS.generator_tap()
+                LOG.debug("current tapinfo is %s" % tapinfo)
+                self.taps.append(tapinfo)
+
+            for tapinfo in self.taps:
+                tapname = tapinfo["name"]
+                _temp_net_args = "tap,id=%s,ifname=%s" % (tapname, tapname)
+                if self.vhost_type:
+                    _temp_net_args += ",vhost=on"
+                if self.vhostfd:
+                    _temp_net_args += ",vhostfd=%s" % self.vhostfd
+                _temp_device_args = "virtio-net-device,netdev=%s,id=%s" % (tapname, tapname)
+                if self.net_iothread:
+                    _temp_device_args += ",iothread=%s" % self.net_iothread
+                if self.withmac:
+                    _temp_device_args += ",mac=%s" % tapinfo["mac"]
+                args.extend(['-netdev', _temp_net_args, '-device', _temp_device_args])
+
+        if self.rng:
+            _temp_rng_args = 'rng-random,id=objrng0,filename=/dev/urandom'
+            if self.max_bytes == 0:
+                _temp_device_args = 'virtio-rng-device,rng=objrng0'
+            else:
+                _temp_device_args = 'virtio-rng-device,rng=objrng0,max-bytes=%s,period=1000' % self.max_bytes
+            args.extend(['-object', _temp_rng_args, '-device', _temp_device_args])
+
+        if self.vsocknums > 0:
+            if VSOCKS.init_vsock():
+                for _ in range(self.vsocknums - len(self.vsock_cid)):
+                    sockcid = VSOCKS.find_contextid()
+                    self.vsock_cid.append(sockcid)
+                    args.extend(['-device',
+                                 'vhost-vsock-device,id=vsock-%s,'
+                                 'guest-cid=%s' % (sockcid, sockcid)])
+
+        if self.balloon:
+            if self.deflate_on_oom:
+                _temp_balloon_args = 'deflate-on-oom=true'
+            else:
+                _temp_balloon_args = 'deflate-on-oom=false'
+            args.extend(['-device', 'virtio-balloon-device', _temp_balloon_args])
+
+        return args
+
+    def basic_config(self, **kwargs):
+        """Change configdict"""
+        if "vcpu_count" in kwargs:
+            self.configdict["machine-config"]["vcpu_count"] = kwargs.get("vcpu_count")
+            del kwargs["vcpu_count"]
+        if "mem_size" in kwargs:
+            self.configdict["machine-config"]["mem_size"] = kwargs.get("mem_size")
+            del kwargs["mem_size"]
+        if "mem_path" in kwargs:
+            self.configdict["machine-config"]["mem_path"] = kwargs.get("mem_path")
+            del kwargs["mem_path"]
+        if "vhost_type" in kwargs:
+            self.vhost_type = kwargs.get("vhost_type")
+            del kwargs["vhost_type"]
+
+        for key, value in kwargs.items():
+            if hasattr(self, key):
+                setattr(self, key, value)
+
+    def parser_config_to_args(self):
+        """Parser json config to args"""
+        if self.configdict is None:
+            return
+
+        configdict = self.configdict
+        if "boot-source" in configdict:
+            if "kernel_image_path" in configdict["boot-source"]:
+                self.add_args('-kernel', configdict["boot-source"]["kernel_image_path"])
+            if "boot_args" in configdict["boot-source"]:
+                self.add_args('-append', configdict["boot-source"]["boot_args"])
+            if "initrd" in configdict["boot-source"]:
+                self.add_args('-initrd', configdict["boot-source"]["initrd"])
+
+        if "machine-config" in configdict:
+            # make smp cmdline
+            _temp_cpu_args = ""
+            if "vcpu_count" in configdict["machine-config"]:
+                _temp_cpu_args = str(configdict["machine-config"]["vcpu_count"])
+            if _temp_cpu_args != "":
+                self.add_args('-smp', _temp_cpu_args)
+            # make mem cmdline
+            _temp_mem_args = ""
+            if "mem_size" in configdict["machine-config"]:
+                _temp_mem_args = str(configdict["machine-config"]["mem_size"])
+            if _temp_mem_args != "":
+                self.add_args('-m', _temp_mem_args)
+            if "mem_path" in configdict["machine-config"]:
+                self.add_args('-mem-path', configdict["machine-config"]["mem_path"])
+
+        # make block cmdline
+        for block in configdict.get("block", []):
+            # make drive cmdline
+            for drive in block.get("drive", []):
+                _temp_drive_args = ""
+                if "drive_id" in drive:
+                    _temp_drive_args = "id=%s" % drive["drive_id"]
+                if "path_on_host" in drive:
+                    _temp_drive_args += ",file=%s" % drive["path_on_host"]
+                if "read_only" in drive:
+                    _temp = "on" if drive["read_only"] else "off"
+                    _temp_drive_args += ",readonly=%s" % _temp
+                if "direct" in drive:
+                    _temp = "on" if drive["direct"] else "off"
+                    _temp_drive_args += ",direct=%s" % _temp
+                if "iops" in drive:
+                    _temp_drive_args += ",throttling.iops-total=%s" % drive["iops"]
+                if _temp_drive_args != "":
+                    self.add_args('-drive', _temp_drive_args)
+
+            # make block device cmdline
+            for device in block.get("device", []):
+                _temp_device_args = ""
+                _temp_device_args = "virtio-blk-device,drive=%s" % device["drive_id"]
+                if "iothread" in device:
+                    _temp_device_args += ",iothread=%s" % device["iothread"]
+                if "serial" in device:
+                    _temp_device_args += ",serial=%s" % device["serial"]
+                if _temp_device_args != "":
+                    self.add_args('-device', _temp_device_args)
diff --git a/tests/hydropper/virt/standvm.py b/tests/hydropper/virt/standvm.py
new file mode 100644
index 0000000..a57af85
--- /dev/null
+++ b/tests/hydropper/virt/standvm.py
@@ -0,0 +1,325 @@
+# Copyright (c) 2021 Huawei Technologies Co.,Ltd. All rights reserved.
+#
+# StratoVirt is licensed under Mulan PSL v2.
+# You can use this software according to the terms and conditions of the Mulan
+# PSL v2.
+# You may obtain a copy of Mulan PSL v2 at:
+#         http:#license.coscl.org.cn/MulanPSL2
+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
+# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+# NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+# See the Mulan PSL v2 for more details.
+"""class standardvm"""
+
+import os
+import json
+import logging
+import subprocess
+from virt.basevm import BaseVM
+from utils.config import CONFIG
+from utils.exception import PflashError
+from utils.resources import NETWORKS
+from utils.resources import VSOCKS
+from utils.utils_logging import TestLog
+
+LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
+logging.basicConfig(filename="/var/log/pytest.log", level=logging.DEBUG, format=LOG_FORMAT)
+LOG = TestLog.get_global_log()
+
+class StandVM(BaseVM):
+    """Class to represent a standardvm"""
+    def __init__(self, root_path, name, uuid, bin_path=CONFIG.stratovirt_standvm_bin, machine=None,
+                 vmconfig=CONFIG.get_default_standvm_vmconfig(), vmlinux=CONFIG.stratovirt_stand_vmlinux,
+                 rootfs=CONFIG.stratovirt_stand_rootfs, initrd=CONFIG.stratovirt_initrd, pcie_root_port=0,
+                 vcpus=4, memsize=2048, socktype="unix", loglevel="info"):
+        self.name = name
+        self.vmid = uuid
+        if "unix" in socktype:
+            sock_path = os.path.join(root_path, self.name + "_" + self.vmid + ".sock")
+        else:
+            sock_path = ("127.0.0.1", 32542)
+        self.vmconfig_template_file = vmconfig
+        self.vm_json_file = None
+        self.vmlinux = vmlinux
+        self.rootfs = rootfs
+        self.initrd = initrd
+        self.vcpus = vcpus
+        self.memsize = memsize
+        self.multifunction = {"net": False, "console": False, "vsock": False,
+                              "balloon": False, "rng": False, "pcie_root_port": False, "vfio": False}
+        self.code_storage_file = None
+        self.code_storage_readonly = True
+        self.data_storage_file = None
+        self.inited = False
+        self.pcie_root_port = pcie_root_port
+        self.vfio = False
+        self.init_vmjson(root_path)
+        self._args = list()
+        self.bus_slot = dict()
+        self.bus_slot_init()
+        super(StandVM, self).__init__(root_path=root_path,
+                                      name=name,
+                                      uuid=uuid,
+                                      args=self._args,
+                                      bin_path=bin_path,
+                                      mon_sock=sock_path,
+                                      machine=machine,
+                                      daemon=True,
+                                      config=self.vm_json_file)
+        self.add_env("RUST_BACKTRACE", "1")
+        if CONFIG.rust_san_check:
+            self.add_env("RUSTFLAGS", "-Zsanitizer=address")
+        self.add_env("STRATOVIRT_LOG_LEVEL", loglevel)
+
+    def bus_slot_init(self):
+        """
+            addr=0x0.0x0: None
+            addr=0x1.0x0: Virtio-console
+            addr=0x2.0x0: Virtio-balloon
+            addr=0x3.0x0: Virtio-vsock
+            addr=0x4.0x0: VFIO
+            addr=0x5.0x0 -> addr=0x8.0x0: pcie_root_port
+            addr=0x9.0x0 -> addr=0x17.0x0: None
+            addr=0x18.0x0 -> addr=0x1b.0x0: Virtio-net
+            addr=0x1c.0x0 -> addr=0x1f.0x0: Virtio-blk
+        """
+        for i in range(32):
+            self.bus_slot[i] = None
+
+    def init_vmjson(self, root_path):
+        """Generate a temp vm json file"""
+        self.vm_json_file = os.path.join(root_path, self.name + "_" + self.vmid + ".json")
+        with open(self.vmconfig_template_file, "r") as cfp:
+            _vm_json = json.load(cfp)
+            if "boot-source" in _vm_json:
+                _vm_json["boot-source"]["kernel_image_path"] = self.vmlinux
+                if "initrd" in _vm_json["boot-source"]:
+                    _vm_json["boot-source"]["initrd"] = self.initrd
+            if "block" in _vm_json:
+                # one by default
+                _vm_json["block"][0]["drive"][0]["path_on_host"] = self.rootfs
+            if "machine-config" in _vm_json:
+                _vm_json["machine-config"]["vcpu_count"] = int(self.vcpus)
+                _vm_json["machine-config"]["mem_size"] = self.memsize
+
+            with open(self.vm_json_file, "w") as fpdest:
+                json.dump(_vm_json, fpdest)
+                self.inited = True
+
+    def launch(self):
+        """Start a standvm and establish a qmp connection"""
+        del self._args
+        self._args = list(self.init_args)
+        self._pre_launch()
+        self.parser_config_to_args()
+        self.full_command = ([self.bin_path] + self._base_args() + self._args)
+        LOG.debug(self.full_command)
+        LOG.debug(self.bus_slot)
+        if not self.env.keys():
+            self._popen = subprocess.Popen(self.full_command,
+                                           stdin=subprocess.PIPE,
+                                           stdout=subprocess.PIPE,
+                                           shell=False,
+                                           close_fds=True)
+        else:
+            _tempenv = os.environ.copy()
+            for key, _ in self.env.items():
+                _tempenv[key] = self.env[key]
+            self._popen = subprocess.Popen(self.full_command,
+                                           stdin=subprocess.PIPE,
+                                           stdout=subprocess.PIPE,
+                                           shell=False,
+                                           close_fds=True,
+                                           env=_tempenv)
+
+        if self.daemon:
+            self._popen.wait()
+            self.pid = self.get_pid()
+        else:
+            self.pid = self._popen.pid
+        if not self.error_test:
+            self._post_launch()
+
+    def _base_args(self):
+        args = self._common_args()
+        if self._console_set:
+            self._console_address = os.path.join(self._sock_dir,
+                                                 self._name + "_" + self.vmid + "-console.sock")
+            # It doesn't need to create it first.
+            self._remove_files.append(self._console_address)
+            self.bus_slot[1] = 'console'
+            _temp_console_args = "virtio-serial-pci,bus=pcie.0,addr=0x1.0x0"
+            if self.multifunction["console"]:
+                _temp_console_args += ",multifunction=on"
+            args.extend(['-device', _temp_console_args, '-chardev',
+                         'socket,path=%s,id=virtioconsole1,server,nowait' % self._console_address,
+                         '-device', 'virtconsole,chardev=virtioconsole1,id=console_0'])
+
+        if self.vnetnums > 0:
+            for _ in range(self.vnetnums - len(self.taps)):
+                tapinfo = NETWORKS.generator_tap()
+                LOG.debug("current tapinfo is %s" % tapinfo)
+                self.taps.append(tapinfo)
+
+            LOG.debug(self.vnetnums)
+            LOG.debug(self.taps)
+
+            for i, tapinfo in enumerate(self.taps):
+                tapname = tapinfo["name"]
+                i += 24
+                self.bus_slot[i] = 'net'
+                _temp_net_args = "tap,id=%s,ifname=%s" % (tapname, tapname)
+                if self.vhost_type:
+                    _temp_net_args += ",vhost=on"
+                if self.vhostfd:
+                    _temp_net_args += ",vhostfd=%s" % self.vhostfd
+                _temp_device_args = "virtio-net-pci,netdev=%s,id=%s,bus=pcie.0,addr=%s.0x0" % (tapname, tapname, hex(i))
+                if self.multifunction["net"]:
+                    _temp_device_args += ",multifunction=on"
+                if self.net_iothread:
+                    _temp_device_args += ",iothread=%s" % self.net_iothread
+                if self.withmac:
+                    _temp_device_args += ",mac=%s" % tapinfo["mac"]
+                args.extend(['-netdev', _temp_net_args, '-device', _temp_device_args])
+
+        if self.rng:
+            _temp_rng_args = 'rng-random,id=objrng0,filename=/dev/urandom'
+            if self.max_bytes == 0:
+                _temp_device_args = 'virtio-rng-pci,rng=objrng0'
+            else:
+                _temp_device_args = 'virtio-rng-pci,rng=objrng0,max-bytes=%s,period=1000,id=pcie.0,addr=0x1.0x0' % self.max_bytes
+            if self.multifunction["rng"]:
+                _temp_device_args += ",multifunction=on"
+            args.extend(['-object', _temp_rng_args, '-device', _temp_device_args])
+
+        if self.vsocknums == 1:
+            if VSOCKS.init_vsock():
+                for _ in range(self.vsocknums - len(self.vsock_cid)):
+                    sockcid = VSOCKS.find_contextid()
+                    self.vsock_cid.append(sockcid)
+                    self.bus_slot[3] = 'vsock'
+                    _temp_vsock_args = "vhost-vsock-pci,id=vsock-%s,guest-cid=%s,bus=pcie.0,addr=0x3.0x0" % (sockcid, sockcid)
+                    if self.multifunction["vsock"]:
+                        _temp_vsock_args += ",multifunction=on"
+                    args.extend(['-device', _temp_vsock_args])
+
+        if self.balloon:
+            self.bus_slot[2] = 'balloon'
+            _temp_balloon_args = "virtio-balloon-pci,bus=pcie.0,addr=0x2.0x0"
+            if self.deflate_on_oom:
+                _temp_balloon_args = 'deflate-on-oom=true'
+            else:
+                _temp_balloon_args = 'deflate-on-oom=false'
+            if self.multifunction["balloon"]:
+                _temp_balloon_args += ",multifunction=on"
+            args.extend(['-device', _temp_balloon_args])
+
+        if self.pcie_root_port > 0:
+            for port_id in range(5, self.pcie_root_port + 5):
+                self.bus_slot[port_id] = 'pcie_root_port'
+                _temp_pcie_args = "pcie-root-port,port=0x%s,addr=0x%s,bus=pcie.0,id=pcie.%s" % (port_id, port_id, port_id)
+                if self.multifunction["pcie_root_port"]:
+                    _temp_pcie_args += ",multifunction=on"
+                args.extend(['-device', _temp_pcie_args])
+
+        if self.code_storage_file is None:
+            raise PflashError
+        _temp_pflash_args = "file=%s,if=pflash,unit=0" % self.code_storage_file
+        if self.code_storage_readonly:
+            _temp_pflash_args += ",readonly=true"
+        args.extend(['-drive', _temp_pflash_args])
+
+        if self.data_storage_file:
+            _temp_pflash_args = "file=%s,if=pflash,unit=1," %  self.data_storage_file
+            args.extend(['-drive', _temp_pflash_args])
+
+        if self.vfio:
+            self.bus_slot[4] = 'vfio'
+            _temp_vfio_args = "vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x04.0x0"
+            if self.multifunction["vfio"]:
+                _temp_vfio_args += ",multifunction=on"
+                args.extend(['-device', _temp_vfio_args])
+
+        return args
+
+    def basic_config(self, **kwargs):
+        """Change configdict"""
+        if "vcpu_count" in kwargs:
+            self.configdict["machine-config"]["vcpu_count"] = kwargs.get("vcpu_count")
+            del kwargs["vcpu_count"]
+        if "mem_size" in kwargs:
+            self.configdict["machine-config"]["mem_size"] = kwargs.get("mem_size")
+            del kwargs["mem_size"]
+        if "mem_path" in kwargs:
+            self.configdict["machine-config"]["mem_path"] = kwargs.get("mem_path")
+            del kwargs["mem_path"]
+        if "vhost_type" in kwargs:
+            self.vhost_type = kwargs.get("vhost_type")
+            del kwargs["vhost_type"]
+
+        for key, value in kwargs.items():
+            if hasattr(self, key):
+                setattr(self, key, value)
+
+    def parser_config_to_args(self):
+        """Parser json config to args"""
+        if self.configdict is None:
+            return
+
+        configdict = self.configdict
+        if "boot-source" in configdict:
+            if "kernel_image_path" in configdict["boot-source"]:
+                self.add_args('-kernel', configdict["boot-source"]["kernel_image_path"])
+            if "boot_args" in configdict["boot-source"]:
+                self.add_args('-append', configdict["boot-source"]["boot_args"])
+            if "initrd" in configdict["boot-source"]:
+                self.add_args('-initrd', configdict["boot-source"]["initrd"])
+
+        if "machine-config" in configdict:
+            # make smp cmdline
+            _temp_cpu_args = ""
+            if "vcpu_count" in configdict["machine-config"]:
+                _temp_cpu_args = str(configdict["machine-config"]["vcpu_count"])
+            if _temp_cpu_args != "":
+                self.add_args('-smp', _temp_cpu_args)
+            # make mem cmdline
+            _temp_mem_args = ""
+            if "mem_size" in configdict["machine-config"]:
+                _temp_mem_args = str(configdict["machine-config"]["mem_size"])
+            if _temp_mem_args != "":
+                self.add_args('-m', _temp_mem_args)
+            if "mem_path" in configdict["machine-config"]:
+                self.add_args('-mem-path', configdict["machine-config"]["mem_path"])
+
+        # make block cmdline
+        for block in configdict.get("block", []):
+            # make drive cmdline
+            for drive in block.get("drive", []):
+                _temp_drive_args = ""
+                if "drive_id" in drive:
+                    _temp_drive_args = "id=%s" % drive["drive_id"]
+                if "path_on_host" in drive:
+                    _temp_drive_args += ",file=%s" % drive["path_on_host"]
+                if "read_only" in drive:
+                    _temp = "on" if drive["read_only"] else "off"
+                    _temp_drive_args += ",readonly=%s" % _temp
+                if "direct" in drive:
+                    _temp = "on" if drive["direct"] else "off"
+                    _temp_drive_args += ",direct=%s" % _temp
+                if "iops" in drive:
+                    _temp_drive_args += ",throttling.iops-total=%s" % drive["iops"]
+                if _temp_drive_args != "":
+                    self.add_args('-drive', _temp_drive_args)
+
+            # make block device cmdline
+            for i, device in enumerate(block.get("device", [])):
+                i += 28
+                self.bus_slot[i] = 'block'
+                _temp_device_args = ""
+                _temp_device_args = "virtio-blk-pci,drive=%s,bus=pcie.0,addr=%s.0x0" % (device["drive_id"], hex(i))
+                if "iothread" in device:
+                    _temp_device_args += ",iothread=%s" % device["iothread"]
+                if "serial" in device:
+                    _temp_device_args += ",serial=%s" % device["serial"]
+                if _temp_device_args != "":
+                    self.add_args('-device', _temp_device_args)
-- 
2.30.0

