Merge pull request #2229 from GNS3/fix/3472

Fix support for the GNS3 VM on macOS with VirtualBox 7
This commit is contained in:
Jeremy Grossmann 2023-05-31 20:46:39 +09:30 committed by GitHub
commit cc4d6759e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -122,9 +122,9 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
continue continue
return interface return interface
async def _look_for_vboxnet(self, interface_number): async def _look_for_vboxnet(self, backend_type, interface_number):
""" """
Look for the VirtualBox network name associated with a host only interface. Look for the VirtualBox network name associated with an interface.
:returns: None or vboxnet name :returns: None or vboxnet name
""" """
@ -133,7 +133,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
for info in result.splitlines(): for info in result.splitlines():
if '=' in info: if '=' in info:
name, value = info.split('=', 1) name, value = info.split('=', 1)
if name == "hostonlyadapter{}".format(interface_number): if name == "{}{}".format(backend_type, interface_number):
return value.strip('"') return value.strip('"')
return None return None
@ -159,7 +159,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
return True return True
return False return False
async def _check_vboxnet_exists(self, vboxnet): async def _check_vboxnet_exists(self, vboxnet, vboxnet_type):
""" """
Check if the vboxnet interface exists Check if the vboxnet interface exists
@ -167,7 +167,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
:returns: boolean :returns: boolean
""" """
properties = await self._execute("list", ["hostonlyifs"]) properties = await self._execute("list", ["{}".format(vboxnet_type)])
for prop in properties.splitlines(): for prop in properties.splitlines():
try: try:
name, value = prop.split(':', 1) name, value = prop.split(':', 1)
@ -230,29 +230,42 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
if nat_interface_number < 0: if nat_interface_number < 0:
raise GNS3VMError('VM "{}" must have a NAT interface configured in order to start'.format(self.vmname)) raise GNS3VMError('VM "{}" must have a NAT interface configured in order to start'.format(self.vmname))
hostonly_interface_number = await self._look_for_interface("hostonly") if sys.platform.startswith("darwin") and parse_version(self._system_properties["API version"]) >= parse_version("7_0"):
if hostonly_interface_number < 0: # VirtualBox 7.0+ on macOS requires a host-only network interface
raise GNS3VMError('VM "{}" must have a host-only interface configured in order to start'.format(self.vmname)) backend_type = "hostonly-network"
backend_description = "host-only network"
vboxnet_type = "hostonlynets"
interface_number = await self._look_for_interface("hostonlynetwork")
if interface_number < 0:
raise GNS3VMError('VM "{}" must have a network adapter attached to a host-only network in order to start'.format(self.vmname))
else:
backend_type = "hostonlyadapter"
backend_description = "host-only adapter"
vboxnet_type = "hostonlyifs"
interface_number = await self._look_for_interface("hostonly")
vboxnet = await self._look_for_vboxnet(hostonly_interface_number) if interface_number < 0:
raise GNS3VMError('VM "{}" must have a network adapter attached to a {} in order to start'.format(self.vmname, backend_description))
vboxnet = await self._look_for_vboxnet(backend_type, interface_number)
if vboxnet is None: if vboxnet is None:
raise GNS3VMError('A VirtualBox host-only network could not be found on network adapter {} for "{}"'.format(hostonly_interface_number, self._vmname)) raise GNS3VMError('A VirtualBox host-only network could not be found on network adapter {} for "{}"'.format(interface_number, self._vmname))
if not (await self._check_vboxnet_exists(vboxnet)): if not (await self._check_vboxnet_exists(vboxnet, vboxnet_type)):
if sys.platform.startswith("win") and vboxnet == "vboxnet0": if sys.platform.startswith("win") and vboxnet == "vboxnet0":
# The GNS3 VM is configured with vboxnet0 by default which is not available # The GNS3 VM is configured with vboxnet0 by default which is not available
# on Windows. Try to patch this with the first available vboxnet we find. # on Windows. Try to patch this with the first available vboxnet we find.
first_available_vboxnet = await self._find_first_available_vboxnet() first_available_vboxnet = await self._find_first_available_vboxnet()
if first_available_vboxnet is None: if first_available_vboxnet is None:
raise GNS3VMError('Please add a VirtualBox host-only network with DHCP enabled and attached it to network adapter {} for "{}"'.format(hostonly_interface_number, self._vmname)) raise GNS3VMError('Please add a VirtualBox host-only network with DHCP enabled and attached it to network adapter {} for "{}"'.format(interface_number, self._vmname))
await self.set_hostonly_network(hostonly_interface_number, first_available_vboxnet) await self.set_hostonly_network(interface_number, first_available_vboxnet)
vboxnet = first_available_vboxnet vboxnet = first_available_vboxnet
else: else:
raise GNS3VMError('VirtualBox host-only network "{}" does not exist, please make the sure the network adapter {} configuration is valid for "{}"'.format(vboxnet, raise GNS3VMError('VirtualBox host-only network "{}" does not exist, please make the sure the network adapter {} configuration is valid for "{}"'.format(vboxnet,
hostonly_interface_number, interface_number,
self._vmname)) self._vmname))
if not (await self._check_dhcp_server(vboxnet)): if backend_type == "hostonlyadapter" and not (await self._check_dhcp_server(vboxnet)):
raise GNS3VMError('DHCP must be enabled on VirtualBox host-only network "{}"'.format(vboxnet)) raise GNS3VMError('DHCP must be enabled on VirtualBox host-only network "{}"'.format(vboxnet))
vm_state = await self._get_state() vm_state = await self._get_state()
@ -296,7 +309,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
await self._execute("controlvm", [self._vmname, "natpf{}".format(nat_interface_number), await self._execute("controlvm", [self._vmname, "natpf{}".format(nat_interface_number),
"GNS3VM,tcp,{},{},,{}".format(ip_address, api_port, self.port)]) "GNS3VM,tcp,{},{},,{}".format(ip_address, api_port, self.port)])
self.ip_address = await self._get_ip(hostonly_interface_number, api_port) self.ip_address = await self._get_ip(interface_number, api_port)
log.info("GNS3 VM has been started with IP {}".format(self.ip_address)) log.info("GNS3 VM has been started with IP {}".format(self.ip_address))
self.running = True self.running = True