diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index c4fc1414..8561fe5d 100644 --- a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py +++ b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py @@ -23,6 +23,8 @@ import socket from .base_gns3_vm import BaseGNS3VM from .gns3_vm_error import GNS3VMError +from gns3server.utils import parse_version +from gns3server.utils.asyncio import wait_run_in_executor from ...compute.virtualbox import ( VirtualBox, @@ -38,6 +40,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM): self._engine = "virtualbox" super().__init__(controller) + self._system_properties = {} self._virtualbox_manager = VirtualBox() async def _execute(self, subcommand, args, timeout=60): @@ -63,6 +66,42 @@ class VirtualBoxGNS3VM(BaseGNS3VM): return value.strip('"') return "unknown" + async def _get_system_properties(self): + """ + Returns the VM state (e.g. running, paused etc.) + + :returns: state (string) + """ + + properties = await self._execute("list", ["systemproperties"]) + for prop in properties.splitlines(): + try: + name, value = prop.split(':', 1) + except ValueError: + continue + self._system_properties[name.strip()] = value.strip() + + async def _check_requirements(self): + """ + Checks if the GNS3 VM can run on VirtualBox + """ + + if not self._system_properties: + await self._get_system_properties() + if "API version" not in self._system_properties: + raise VirtualBoxError("Can't access to VirtualBox API version:\n{}".format(self._system_properties)) + from cpuinfo import get_cpu_info + cpu_info = await wait_run_in_executor(get_cpu_info) + vendor_id = cpu_info['vendor_id'] + if vendor_id == "GenuineIntel": + if parse_version(self._system_properties["API version"]) < parse_version("6_1"): + raise VirtualBoxError("VirtualBox version 6.1 or above is required to run the GNS3 VM with nested virtualization enabled on Intel processors") + elif vendor_id == "AuthenticAMD": + if parse_version(self._system_properties["API version"]) < parse_version("6_0"): + raise VirtualBoxError("VirtualBox version 6.0 or above is required to run the GNS3 VM with nested virtualization enabled on AMD processors") + else: + log.warning("Could not determine CPU vendor: {}".format(vendor_id)) + async def _look_for_interface(self, network_backend): """ Look for an interface with a specific network backend. @@ -173,13 +212,16 @@ class VirtualBoxGNS3VM(BaseGNS3VM): List all VirtualBox VMs """ - return (await self._virtualbox_manager.list_vms()) + await self._check_requirements() + return await self._virtualbox_manager.list_vms() async def start(self): """ Start the GNS3 VM. """ + await self._check_requirements() + # get a NAT interface number nat_interface_number = await self._look_for_interface("nat") if nat_interface_number < 0: diff --git a/requirements.txt b/requirements.txt index 81ff0d1b..1e7fe651 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ raven>=5.23.0 psutil==5.6.3 async-timeout==3.0.1 distro>=1.3.0 +py-cpuinfo==5.0.0