mirror of
https://github.com/GNS3/gns3-server
synced 2025-02-09 22:52:48 +00:00
Automatically add vboxnet and DHCP server if not present for VirtualBox GNS3 VM. Ref #2266
This commit is contained in:
parent
285b19d97f
commit
702fea89fb
@ -15,11 +15,13 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import logging
|
import logging
|
||||||
import asyncio
|
import asyncio
|
||||||
import socket
|
import socket
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
from .base_gns3_vm import BaseGNS3VM
|
from .base_gns3_vm import BaseGNS3VM
|
||||||
from .gns3_vm_error import GNS3VMError
|
from .gns3_vm_error import GNS3VMError
|
||||||
@ -80,9 +82,6 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
self._system_properties[name.strip()] = value.strip()
|
self._system_properties[name.strip()] = value.strip()
|
||||||
if "API Version" in self._system_properties:
|
|
||||||
# API version is not consistent between VirtualBox versions, the key is named "API Version" in VirtualBox 7
|
|
||||||
self._system_properties["API version"] = self._system_properties.pop("API Version")
|
|
||||||
|
|
||||||
async def _check_requirements(self):
|
async def _check_requirements(self):
|
||||||
"""
|
"""
|
||||||
@ -92,16 +91,16 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
|||||||
if not self._system_properties:
|
if not self._system_properties:
|
||||||
await self._get_system_properties()
|
await self._get_system_properties()
|
||||||
if "API version" not in self._system_properties:
|
if "API version" not in self._system_properties:
|
||||||
raise VirtualBoxError("Can't access to VirtualBox API version:\n{}".format(self._system_properties))
|
raise GNS3VMError("Can't access to VirtualBox API version:\n{}".format(self._system_properties))
|
||||||
from cpuinfo import get_cpu_info
|
from cpuinfo import get_cpu_info
|
||||||
cpu_info = await wait_run_in_executor(get_cpu_info)
|
cpu_info = await wait_run_in_executor(get_cpu_info)
|
||||||
vendor_id = cpu_info.get('vendor_id_raw')
|
vendor_id = cpu_info.get('vendor_id_raw')
|
||||||
if vendor_id == "GenuineIntel":
|
if vendor_id == "GenuineIntel":
|
||||||
if parse_version(self._system_properties["API version"]) < parse_version("6_1"):
|
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")
|
raise GNS3VMError("VirtualBox version 6.1 or above is required to run the GNS3 VM with nested virtualization enabled on Intel processors")
|
||||||
elif vendor_id == "AuthenticAMD":
|
elif vendor_id == "AuthenticAMD":
|
||||||
if parse_version(self._system_properties["API version"]) < parse_version("6_0"):
|
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")
|
raise GNS3VMError("VirtualBox version 6.0 or above is required to run the GNS3 VM with nested virtualization enabled on AMD processors")
|
||||||
else:
|
else:
|
||||||
log.warning("Could not determine CPU vendor: {}".format(vendor_id))
|
log.warning("Could not determine CPU vendor: {}".format(vendor_id))
|
||||||
|
|
||||||
@ -162,6 +161,44 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
async def _add_dhcp_server(self, vboxnet):
|
||||||
|
"""
|
||||||
|
Add a DHCP server for vboxnet.
|
||||||
|
|
||||||
|
:param vboxnet: vboxnet name
|
||||||
|
"""
|
||||||
|
|
||||||
|
hostonlyifs = await self._execute("list", ["hostonlyifs"])
|
||||||
|
pattern = r"IPAddress:\s+(\d+\.\d+\.\d+\.\d+)\nNetworkMask:\s+(\d+\.\d+\.\d+\.\d+)"
|
||||||
|
match = re.search(pattern, hostonlyifs)
|
||||||
|
|
||||||
|
if match:
|
||||||
|
ip_address = match.group(1)
|
||||||
|
netmask = match.group(2)
|
||||||
|
else:
|
||||||
|
raise GNS3VMError("Could not find IP address and netmask for vboxnet {}".format(vboxnet))
|
||||||
|
|
||||||
|
try:
|
||||||
|
interface = ipaddress.IPv4Interface(f"{ip_address}/{netmask}")
|
||||||
|
subnet = ipaddress.IPv4Network(str(interface.network))
|
||||||
|
dhcp_server_ip = str(interface.ip + 1)
|
||||||
|
netmask = str(subnet.netmask)
|
||||||
|
lower_ip = str(interface.ip + 2)
|
||||||
|
upper_ip = str(subnet.network_address + subnet.num_addresses - 2)
|
||||||
|
except ValueError:
|
||||||
|
raise GNS3VMError("Invalid IP address and netmask for vboxnet {}: {}/{}".format(vboxnet, ip_address, netmask))
|
||||||
|
|
||||||
|
dhcp_server_args = [
|
||||||
|
"add",
|
||||||
|
"--network=HostInterfaceNetworking-{}".format(vboxnet),
|
||||||
|
"--server-ip={}".format(dhcp_server_ip),
|
||||||
|
"--netmask={}".format(netmask),
|
||||||
|
"--lower-ip={}".format(lower_ip),
|
||||||
|
"--upper-ip={}".format(upper_ip),
|
||||||
|
"--enable"
|
||||||
|
]
|
||||||
|
await self._execute("dhcpserver", dhcp_server_args)
|
||||||
|
|
||||||
async def _check_vboxnet_exists(self, vboxnet, vboxnet_type):
|
async def _check_vboxnet_exists(self, vboxnet, vboxnet_type):
|
||||||
"""
|
"""
|
||||||
Check if the vboxnet interface exists
|
Check if the vboxnet interface exists
|
||||||
@ -264,12 +301,20 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
|||||||
await self.set_hostonly_network(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,
|
try:
|
||||||
interface_number,
|
await self._execute("hostonlyif", ["create"])
|
||||||
self._vmname))
|
except GNS3VMError:
|
||||||
|
raise GNS3VMError('VirtualBox host-only network "{}" does not exist and could not be automatically created, please make the sure the network adapter {} configuration is valid for "{}"'.format(
|
||||||
|
vboxnet,
|
||||||
|
interface_number,
|
||||||
|
self._vmname
|
||||||
|
))
|
||||||
|
|
||||||
if backend_type == "hostonlyadapter" and 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))
|
try:
|
||||||
|
await self._add_dhcp_server(vboxnet)
|
||||||
|
except GNS3VMError as e:
|
||||||
|
raise GNS3VMError("Could not add DHCP server for vboxnet {}: {}, please configure manually".format(vboxnet, e))
|
||||||
|
|
||||||
vm_state = await self._get_state()
|
vm_state = await self._get_state()
|
||||||
log.info('"{}" state is {}'.format(self._vmname, vm_state))
|
log.info('"{}" state is {}'.format(self._vmname, vm_state))
|
||||||
@ -302,7 +347,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
|||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise GNS3VMError("Error while getting random port: {}".format(e))
|
raise GNS3VMError("Error while getting random port: {}".format(e))
|
||||||
|
|
||||||
if (await self._check_vbox_port_forwarding()):
|
if await self._check_vbox_port_forwarding():
|
||||||
# delete the GNS3VM NAT port forwarding rule if it exists
|
# delete the GNS3VM NAT port forwarding rule if it exists
|
||||||
log.info("Removing GNS3VM NAT port forwarding rule from interface {}".format(nat_interface_number))
|
log.info("Removing GNS3VM NAT port forwarding rule from interface {}".format(nat_interface_number))
|
||||||
await self._execute("controlvm", [self._vmname, "natpf{}".format(nat_interface_number), "delete", "GNS3VM"])
|
await self._execute("controlvm", [self._vmname, "natpf{}".format(nat_interface_number), "delete", "GNS3VM"])
|
||||||
|
Loading…
Reference in New Issue
Block a user