mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-04 22:41:12 +02:00
Merge branch 'master' into Inappropriate_Logic-5node.py11635999804432162276.diff
This commit is contained in:
15 files changed
+152
-76
No files matched your search
@@ -191,29 +191,28 @@ class Controller:
|
||||
Save the controller configuration on disk
|
||||
"""
|
||||
|
||||
if self._config_loaded is False:
|
||||
return
|
||||
controller_settings = dict()
|
||||
if self._config_loaded:
|
||||
controller_settings = {"computes": [],
|
||||
"templates": [],
|
||||
"gns3vm": self.gns3vm.__json__(),
|
||||
"iou_license": self._iou_license_settings,
|
||||
"appliances_etag": self._appliance_manager.appliances_etag,
|
||||
"version": __version__}
|
||||
|
||||
controller_settings = {"computes": [],
|
||||
"templates": [],
|
||||
"gns3vm": self.gns3vm.__json__(),
|
||||
"iou_license": self._iou_license_settings,
|
||||
"appliances_etag": self._appliance_manager.appliances_etag,
|
||||
"version": __version__}
|
||||
for template in self._template_manager.templates.values():
|
||||
if not template.builtin:
|
||||
controller_settings["templates"].append(template.__json__())
|
||||
|
||||
for template in self._template_manager.templates.values():
|
||||
if not template.builtin:
|
||||
controller_settings["templates"].append(template.__json__())
|
||||
|
||||
for compute in self._computes.values():
|
||||
if compute.id != "local" and compute.id != "vm":
|
||||
controller_settings["computes"].append({"host": compute.host,
|
||||
"name": compute.name,
|
||||
"port": compute.port,
|
||||
"protocol": compute.protocol,
|
||||
"user": compute.user,
|
||||
"password": compute.password,
|
||||
"compute_id": compute.id})
|
||||
for compute in self._computes.values():
|
||||
if compute.id != "local" and compute.id != "vm":
|
||||
controller_settings["computes"].append({"host": compute.host,
|
||||
"name": compute.name,
|
||||
"port": compute.port,
|
||||
"protocol": compute.protocol,
|
||||
"user": compute.user,
|
||||
"password": compute.password,
|
||||
"compute_id": compute.id})
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.dirname(self._config_file), exist_ok=True)
|
||||
@@ -229,8 +228,7 @@ class Controller:
|
||||
|
||||
try:
|
||||
if not os.path.exists(self._config_file):
|
||||
self._config_loaded = True
|
||||
self.save()
|
||||
self.save() # this will create the config file
|
||||
with open(self._config_file) as f:
|
||||
controller_settings = json.load(f)
|
||||
except (OSError, ValueError) as e:
|
||||
@@ -255,6 +253,8 @@ class Controller:
|
||||
if not previous_version or \
|
||||
parse_version(__version__.split("+")[0]) > parse_version(previous_version.split("+")[0]):
|
||||
self._appliance_manager.install_builtin_appliances()
|
||||
elif not os.listdir(self._appliance_manager.builtin_appliances_path()):
|
||||
self._appliance_manager.install_builtin_appliances()
|
||||
|
||||
self._appliance_manager.appliances_etag = controller_settings.get("appliances_etag")
|
||||
self._appliance_manager.load_appliances()
|
||||
|
||||
@@ -21,6 +21,7 @@ import uuid
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import shutil
|
||||
import platformdirs
|
||||
|
||||
|
||||
try:
|
||||
@@ -81,13 +82,13 @@ class ApplianceManager:
|
||||
os.makedirs(appliances_path, exist_ok=True)
|
||||
return appliances_path
|
||||
|
||||
def _builtin_appliances_path(self, delete_first=False):
|
||||
def builtin_appliances_path(self, delete_first=False):
|
||||
"""
|
||||
Get the built-in appliance storage directory
|
||||
"""
|
||||
|
||||
config = Config.instance()
|
||||
appliances_dir = os.path.join(config.config_dir, "appliances")
|
||||
appname = vendor = "GNS3"
|
||||
appliances_dir = os.path.join(platformdirs.user_data_dir(appname, vendor, roaming=True), "appliances")
|
||||
if delete_first:
|
||||
shutil.rmtree(appliances_dir, ignore_errors=True)
|
||||
os.makedirs(appliances_dir, exist_ok=True)
|
||||
@@ -98,7 +99,7 @@ class ApplianceManager:
|
||||
At startup we copy the built-in appliances files.
|
||||
"""
|
||||
|
||||
dst_path = self._builtin_appliances_path(delete_first=True)
|
||||
dst_path = self.builtin_appliances_path(delete_first=True)
|
||||
log.info(f"Installing built-in appliances in '{dst_path}'")
|
||||
from . import Controller
|
||||
try:
|
||||
@@ -112,7 +113,7 @@ class ApplianceManager:
|
||||
"""
|
||||
|
||||
self._appliances = {}
|
||||
for directory, builtin in ((self._builtin_appliances_path(), True,), (self._custom_appliances_path(), False,)):
|
||||
for directory, builtin in ((self.builtin_appliances_path(), True,), (self._custom_appliances_path(), False,)):
|
||||
if directory and os.path.isdir(directory):
|
||||
for file in os.listdir(directory):
|
||||
if not file.endswith('.gns3a') and not file.endswith('.gns3appliance'):
|
||||
@@ -215,7 +216,7 @@ class ApplianceManager:
|
||||
from . import Controller
|
||||
Controller.instance().save()
|
||||
json_data = await response.json()
|
||||
appliances_dir = self._builtin_appliances_path()
|
||||
appliances_dir = self.builtin_appliances_path()
|
||||
downloaded_appliance_files = []
|
||||
for appliance in json_data:
|
||||
if appliance["type"] == "file":
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import re
|
||||
import sys
|
||||
import aiohttp
|
||||
import logging
|
||||
import asyncio
|
||||
import socket
|
||||
import ipaddress
|
||||
|
||||
from .base_gns3_vm import BaseGNS3VM
|
||||
from .gns3_vm_error import GNS3VMError
|
||||
@@ -80,9 +82,6 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
except ValueError:
|
||||
continue
|
||||
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):
|
||||
"""
|
||||
@@ -92,16 +91,16 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
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))
|
||||
raise GNS3VMError("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.get('vendor_id_raw')
|
||||
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")
|
||||
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":
|
||||
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:
|
||||
log.warning("Could not determine CPU vendor: {}".format(vendor_id))
|
||||
|
||||
@@ -162,6 +161,44 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
return True
|
||||
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):
|
||||
"""
|
||||
Check if the vboxnet interface exists
|
||||
@@ -264,12 +301,20 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
await self.set_hostonly_network(interface_number, first_available_vboxnet)
|
||||
vboxnet = first_available_vboxnet
|
||||
else:
|
||||
raise GNS3VMError('VirtualBox host-only network "{}" does not exist, please make the sure the network adapter {} configuration is valid for "{}"'.format(vboxnet,
|
||||
interface_number,
|
||||
self._vmname))
|
||||
try:
|
||||
await self._execute("hostonlyif", ["create"])
|
||||
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)):
|
||||
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()
|
||||
log.info('"{}" state is {}'.format(self._vmname, vm_state))
|
||||
@@ -302,7 +347,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM):
|
||||
except OSError as 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
|
||||
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"])
|
||||
|
||||
Reference in new issue
Block a user