mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
Drop Windows support
This commit is contained in:
1 parent
4fb0cd9321
commit
74c675d5b0
47 files changed
+223
-1004
No files matched your search
@@ -32,10 +32,7 @@ if (
|
||||
or os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1"
|
||||
):
|
||||
# IOU & Docker only runs on Linux but test suite works on UNIX platform
|
||||
if not sys.platform.startswith("win"):
|
||||
from .docker import Docker
|
||||
|
||||
MODULES.append(Docker)
|
||||
from .iou import IOU
|
||||
|
||||
MODULES.append(IOU)
|
||||
from .docker import Docker
|
||||
from .iou import IOU
|
||||
MODULES.append(Docker)
|
||||
MODULES.append(IOU)
|
||||
@@ -301,10 +301,6 @@ class BaseManager:
|
||||
:returns: True or False
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
# do not check anything on Windows
|
||||
return True
|
||||
|
||||
if sys.platform.startswith("darwin"):
|
||||
if os.stat(executable).st_uid == 0:
|
||||
return True
|
||||
@@ -425,11 +421,10 @@ class BaseManager:
|
||||
valid_directory_prefices.append(extra_dir)
|
||||
|
||||
# Windows path should not be send to a unix server
|
||||
if not sys.platform.startswith("win"):
|
||||
if re.match(r"^[A-Z]:", path) is not None:
|
||||
raise NodeError(
|
||||
f"'{path}' is not allowed on this remote server. Please only use a file from '{img_directory}'"
|
||||
)
|
||||
if re.match(r"^[A-Z]:", path) is not None:
|
||||
raise NodeError(
|
||||
f"'{path}' is not allowed on this remote server. Please only use a file from '{img_directory}'"
|
||||
)
|
||||
|
||||
if not os.path.isabs(orig_path):
|
||||
|
||||
|
||||
@@ -892,34 +892,6 @@ class BaseNode:
|
||||
await self._ubridge_send(
|
||||
'bridge add_nio_linux_raw {name} "{interface}"'.format(name=bridge_name, interface=ethernet_interface)
|
||||
)
|
||||
elif sys.platform.startswith("win"):
|
||||
# on Windows we use Winpcap/Npcap
|
||||
windows_interfaces = interfaces()
|
||||
npf_id = None
|
||||
source_mac = None
|
||||
for interface in windows_interfaces:
|
||||
# Winpcap/Npcap uses a NPF ID to identify an interface on Windows
|
||||
if "netcard" in interface and ethernet_interface in interface["netcard"]:
|
||||
npf_id = interface["id"]
|
||||
source_mac = interface["mac_address"]
|
||||
elif ethernet_interface in interface["name"]:
|
||||
npf_id = interface["id"]
|
||||
source_mac = interface["mac_address"]
|
||||
if npf_id:
|
||||
await self._ubridge_send(
|
||||
'bridge add_nio_ethernet {name} "{interface}"'.format(name=bridge_name, interface=npf_id)
|
||||
)
|
||||
else:
|
||||
raise NodeError(f"Could not find NPF id for interface {ethernet_interface}")
|
||||
|
||||
if block_host_traffic:
|
||||
if source_mac:
|
||||
await self._ubridge_send(
|
||||
'bridge set_pcap_filter {name} "not ether src {mac}"'.format(name=bridge_name, mac=source_mac)
|
||||
)
|
||||
log.info(f"PCAP filter applied on '{ethernet_interface}' for source MAC {source_mac}")
|
||||
else:
|
||||
log.warning(f"Could not block host network traffic on {ethernet_interface} (no MAC address found)")
|
||||
else:
|
||||
# on other platforms we just rely on the pcap library
|
||||
await self._ubridge_send(
|
||||
|
||||
@@ -310,31 +310,27 @@ class Cloud(BaseNode):
|
||||
"uBridge requires root access or the capability to interact with Ethernet and TAP adapters"
|
||||
)
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
await self._add_ubridge_ethernet_connection(bridge_name, port_info["interface"])
|
||||
|
||||
else:
|
||||
if port_info["type"] == "ethernet":
|
||||
network_interfaces = [interface["name"] for interface in self._interfaces()]
|
||||
if not port_info["interface"] in network_interfaces:
|
||||
raise NodeError(
|
||||
f"Interface '{port_info['interface']}' could not be found on this system, please update '{self.name}'"
|
||||
)
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
await self._add_linux_ethernet(port_info, bridge_name)
|
||||
elif sys.platform.startswith("darwin"):
|
||||
await self._add_osx_ethernet(port_info, bridge_name)
|
||||
else:
|
||||
await self._add_windows_ethernet(port_info, bridge_name)
|
||||
|
||||
elif port_info["type"] == "tap":
|
||||
await self._ubridge_send(
|
||||
'bridge add_nio_tap {name} "{interface}"'.format(
|
||||
name=bridge_name, interface=port_info["interface"]
|
||||
)
|
||||
if port_info["type"] == "ethernet":
|
||||
network_interfaces = [interface["name"] for interface in self._interfaces()]
|
||||
if not port_info["interface"] in network_interfaces:
|
||||
raise NodeError(
|
||||
f"Interface '{port_info['interface']}' could not be found on this system, please update '{self.name}'"
|
||||
)
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
await self._add_linux_ethernet(port_info, bridge_name)
|
||||
elif sys.platform.startswith("darwin"):
|
||||
await self._add_osx_ethernet(port_info, bridge_name)
|
||||
else:
|
||||
await self._add_windows_ethernet(port_info, bridge_name)
|
||||
|
||||
elif port_info["type"] == "tap":
|
||||
await self._ubridge_send(
|
||||
'bridge add_nio_tap {name} "{interface}"'.format(
|
||||
name=bridge_name, interface=port_info["interface"]
|
||||
)
|
||||
)
|
||||
|
||||
elif port_info["type"] == "udp":
|
||||
await self._ubridge_send(
|
||||
"bridge add_nio_udp {name} {lport} {rhost} {rport}".format(
|
||||
|
||||
@@ -348,23 +348,10 @@ class Dynamips(BaseManager):
|
||||
nio.suspend = nio_settings.get("suspend", False)
|
||||
elif nio_settings["type"] == "nio_generic_ethernet":
|
||||
ethernet_device = nio_settings["ethernet_device"]
|
||||
if sys.platform.startswith("win"):
|
||||
# replace the interface name by the GUID on Windows
|
||||
windows_interfaces = interfaces()
|
||||
npf_interface = None
|
||||
for interface in windows_interfaces:
|
||||
if interface["name"] == ethernet_device:
|
||||
npf_interface = interface["id"]
|
||||
if not npf_interface:
|
||||
raise DynamipsError(f"Could not find interface {ethernet_device} on this host")
|
||||
else:
|
||||
ethernet_device = npf_interface
|
||||
if not is_interface_up(ethernet_device):
|
||||
raise DynamipsError(f"Ethernet interface {ethernet_device} is down")
|
||||
nio = NIOGenericEthernet(node.hypervisor, ethernet_device)
|
||||
elif nio_settings["type"] == "nio_linux_ethernet":
|
||||
if sys.platform.startswith("win"):
|
||||
raise DynamipsError("This NIO type is not supported on Windows")
|
||||
ethernet_device = nio_settings["ethernet_device"]
|
||||
nio = NIOLinuxEthernet(node.hypervisor, ethernet_device)
|
||||
elif nio_settings["type"] == "nio_tap":
|
||||
@@ -564,7 +551,6 @@ class Dynamips(BaseManager):
|
||||
|
||||
await vm.set_idlepc("0x0")
|
||||
was_auto_started = False
|
||||
old_priority = None
|
||||
try:
|
||||
status = await vm.get_status()
|
||||
if status != "running":
|
||||
@@ -576,8 +562,6 @@ class Dynamips(BaseManager):
|
||||
if not idlepcs:
|
||||
raise DynamipsError("No Idle-PC values found")
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
old_priority = vm.set_process_priority_windows(vm.hypervisor.process.pid)
|
||||
for idlepc in idlepcs:
|
||||
match = re.search(r"^0x[0-9a-f]{8}$", idlepc.split()[0])
|
||||
if not match:
|
||||
@@ -606,8 +590,6 @@ class Dynamips(BaseManager):
|
||||
except DynamipsError:
|
||||
raise
|
||||
finally:
|
||||
if old_priority is not None:
|
||||
vm.set_process_priority_windows(vm.hypervisor.process.pid, old_priority)
|
||||
if was_auto_started:
|
||||
await vm.stop()
|
||||
return validated_idlepc
|
||||
|
||||
@@ -118,11 +118,6 @@ class Hypervisor(DynamipsHypervisor):
|
||||
|
||||
self._command = self._build_command()
|
||||
env = os.environ.copy()
|
||||
if sys.platform.startswith("win"):
|
||||
# add the Npcap directory to $PATH to force Dynamips to use npcap DLL instead of Winpcap (if installed)
|
||||
system_root = os.path.join(os.path.expandvars("%SystemRoot%"), "System32", "Npcap")
|
||||
if os.path.isdir(system_root):
|
||||
env["PATH"] = system_root + ";" + env["PATH"]
|
||||
try:
|
||||
log.info(f"Starting Dynamips: {self._command}")
|
||||
self._stdout_file = os.path.join(self.working_dir, f"dynamips_i{self._id}_stdout.txt")
|
||||
|
||||
@@ -103,10 +103,7 @@ class Router(BaseNode):
|
||||
self._idlesleep = 30
|
||||
self._ghost_file = ""
|
||||
self._ghost_status = 0
|
||||
if sys.platform.startswith("win"):
|
||||
self._exec_area = 16 # 16 MB by default on Windows (Cygwin)
|
||||
else:
|
||||
self._exec_area = 64 # 64 MB on other systems
|
||||
self._exec_area = 64
|
||||
self._disk0 = 0 # Megabytes
|
||||
self._disk1 = 0 # Megabytes
|
||||
self._auto_delete_disks = False
|
||||
@@ -711,29 +708,6 @@ class Router(BaseNode):
|
||||
log.info(f'Router "{self._name}" [{self._id}]: idle-PC set to {idlepc}')
|
||||
self._idlepc = idlepc
|
||||
|
||||
def set_process_priority_windows(self, pid, priority=None):
|
||||
"""
|
||||
Sets process priority on Windows
|
||||
|
||||
:param pid: process PID
|
||||
"""
|
||||
|
||||
import win32api
|
||||
import win32process
|
||||
import win32con
|
||||
import pywintypes
|
||||
|
||||
old_priority = None
|
||||
try:
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
|
||||
old_priority = win32process.GetPriorityClass(handle)
|
||||
if priority is None:
|
||||
priority = win32process.BELOW_NORMAL_PRIORITY_CLASS
|
||||
win32process.SetPriorityClass(handle, priority)
|
||||
except pywintypes.error as e:
|
||||
log.error(f"Cannot set priority for Dynamips process (PID={pid}) ")
|
||||
return old_priority
|
||||
|
||||
async def get_idle_pc_prop(self):
|
||||
"""
|
||||
Gets the idle PC proposals.
|
||||
@@ -751,13 +725,8 @@ class Router(BaseNode):
|
||||
await asyncio.sleep(20) # leave time to the router to boot
|
||||
|
||||
log.info(f'Router "{self._name}" [{self._id}] has started calculating Idle-PC values')
|
||||
old_priority = None
|
||||
if sys.platform.startswith("win"):
|
||||
old_priority = self.set_process_priority_windows(self._hypervisor.process.pid)
|
||||
begin = time.time()
|
||||
idlepcs = await self._hypervisor.send(f'vm get_idle_pc_prop "{self._name}" 0')
|
||||
if old_priority is not None:
|
||||
self.set_process_priority_windows(self._hypervisor.process.pid, old_priority)
|
||||
log.info(
|
||||
'Router "{name}" [{id}] has finished calculating Idle-PC values after {time:.4f} seconds'.format(
|
||||
name=self._name, id=self._id, time=time.time() - begin
|
||||
|
||||
@@ -114,29 +114,15 @@ class Qemu(BaseManager):
|
||||
else:
|
||||
log.warning("The PATH environment variable doesn't exist")
|
||||
# look for Qemu binaries in the current working directory and $PATH
|
||||
if sys.platform.startswith("win"):
|
||||
# add specific Windows paths
|
||||
if hasattr(sys, "frozen"):
|
||||
# add any qemu dir in the same location as gns3server.exe to the list of paths
|
||||
if sys.platform.startswith("darwin") and hasattr(sys, "frozen"):
|
||||
# add specific locations on Mac OS X regardless of what's in $PATH
|
||||
paths.update(["/usr/bin", "/usr/local/bin", "/opt/local/bin"])
|
||||
try:
|
||||
exec_dir = os.path.dirname(os.path.abspath(sys.executable))
|
||||
for f in os.listdir(exec_dir):
|
||||
if f.lower().startswith("qemu"):
|
||||
paths.add(os.path.join(exec_dir, f))
|
||||
|
||||
if "PROGRAMFILES(X86)" in os.environ and os.path.exists(os.environ["PROGRAMFILES(X86)"]):
|
||||
paths.add(os.path.join(os.environ["PROGRAMFILES(X86)"], "qemu"))
|
||||
if "PROGRAMFILES" in os.environ and os.path.exists(os.environ["PROGRAMFILES"]):
|
||||
paths.add(os.path.join(os.environ["PROGRAMFILES"], "qemu"))
|
||||
elif sys.platform.startswith("darwin"):
|
||||
if hasattr(sys, "frozen"):
|
||||
# add specific locations on Mac OS X regardless of what's in $PATH
|
||||
paths.update(["/usr/bin", "/usr/local/bin", "/opt/local/bin"])
|
||||
try:
|
||||
exec_dir = os.path.dirname(os.path.abspath(sys.executable))
|
||||
paths.add(os.path.abspath(os.path.join(exec_dir, "qemu/bin")))
|
||||
# If the user run the server by hand from outside
|
||||
except FileNotFoundError:
|
||||
paths.add("/Applications/GNS3.app/Contents/MacOS/qemu/bin")
|
||||
paths.add(os.path.abspath(os.path.join(exec_dir, "qemu/bin")))
|
||||
# If the user run the server by hand from outside
|
||||
except FileNotFoundError:
|
||||
paths.add("/Applications/GNS3.app/Contents/MacOS/qemu/bin")
|
||||
return paths
|
||||
|
||||
@staticmethod
|
||||
@@ -205,31 +191,16 @@ class Qemu(BaseManager):
|
||||
:param qemu_path: path to Qemu executable.
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
# Qemu on Windows doesn't return anything with parameter -version
|
||||
# look for a version number in version.txt file in the same directory instead
|
||||
version_file = os.path.join(os.path.dirname(qemu_path), "version.txt")
|
||||
if os.path.isfile(version_file):
|
||||
try:
|
||||
with open(version_file, "rb") as file:
|
||||
version = file.read().decode("utf-8").strip()
|
||||
match = re.search(r"[0-9\.]+", version)
|
||||
if match:
|
||||
return version
|
||||
except (UnicodeDecodeError, OSError) as e:
|
||||
log.warning(f"could not read {version_file}: {e}")
|
||||
return ""
|
||||
else:
|
||||
try:
|
||||
output = await subprocess_check_output(qemu_path, "-version", "-nographic")
|
||||
match = re.search(r"version\s+([0-9a-z\-\.]+)", output)
|
||||
if match:
|
||||
version = match.group(1)
|
||||
return version
|
||||
else:
|
||||
raise QemuError(f"Could not determine the Qemu version for {qemu_path}")
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
raise QemuError(f"Error while looking for the Qemu version: {e}")
|
||||
try:
|
||||
output = await subprocess_check_output(qemu_path, "-version", "-nographic")
|
||||
match = re.search(r"version\s+([0-9a-z\-\.]+)", output)
|
||||
if match:
|
||||
version = match.group(1)
|
||||
return version
|
||||
else:
|
||||
raise QemuError(f"Could not determine the Qemu version for {qemu_path}")
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
raise QemuError(f"Error while looking for the Qemu version: {e}")
|
||||
|
||||
@staticmethod
|
||||
async def _get_qemu_img_version(qemu_img_path):
|
||||
@@ -250,38 +221,6 @@ class Qemu(BaseManager):
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
raise QemuError(f"Error while looking for the Qemu-img version: {e}")
|
||||
|
||||
@staticmethod
|
||||
def get_haxm_windows_version():
|
||||
"""
|
||||
Gets the HAXM version number (Windows).
|
||||
|
||||
:returns: HAXM version number. Returns None if HAXM is not installed.
|
||||
"""
|
||||
|
||||
assert sys.platform.startswith("win")
|
||||
import winreg
|
||||
|
||||
hkey = winreg.OpenKey(
|
||||
winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products"
|
||||
)
|
||||
version = None
|
||||
for index in range(winreg.QueryInfoKey(hkey)[0]):
|
||||
product_id = winreg.EnumKey(hkey, index)
|
||||
try:
|
||||
product_key = winreg.OpenKey(hkey, fr"{product_id}\InstallProperties")
|
||||
try:
|
||||
if winreg.QueryValueEx(product_key, "DisplayName")[0].endswith(
|
||||
"Hardware Accelerated Execution Manager"
|
||||
):
|
||||
version = winreg.QueryValueEx(product_key, "DisplayVersion")[0]
|
||||
break
|
||||
finally:
|
||||
winreg.CloseKey(product_key)
|
||||
except OSError:
|
||||
continue
|
||||
winreg.CloseKey(hkey)
|
||||
return version
|
||||
|
||||
@staticmethod
|
||||
def get_legacy_vm_workdir(legacy_vm_id, name):
|
||||
"""
|
||||
|
||||
@@ -32,8 +32,9 @@ import gns3server
|
||||
import subprocess
|
||||
import time
|
||||
import json
|
||||
import shlex
|
||||
|
||||
from gns3server.utils import parse_version, shlex_quote
|
||||
from gns3server.utils import parse_version
|
||||
from gns3server.utils.asyncio import subprocess_check_output, cancellable_wait_run_in_executor
|
||||
from .qemu_error import QemuError
|
||||
from .utils.qcow2 import Qcow2, Qcow2Error
|
||||
@@ -220,8 +221,6 @@ class QemuVM(BaseNode):
|
||||
"""
|
||||
|
||||
if qemu_path and os.pathsep not in qemu_path:
|
||||
if sys.platform.startswith("win") and ".exe" not in qemu_path.lower():
|
||||
qemu_path += "w.exe"
|
||||
new_qemu_path = shutil.which(qemu_path, path=os.pathsep.join(self._manager.paths_list()))
|
||||
if new_qemu_path is None:
|
||||
raise QemuError(f"QEMU binary path {qemu_path} is not found in the path")
|
||||
@@ -271,10 +270,7 @@ class QemuVM(BaseNode):
|
||||
def platform(self, platform):
|
||||
|
||||
self._platform = platform
|
||||
if sys.platform.startswith("win"):
|
||||
self.qemu_path = f"qemu-system-{platform}w.exe"
|
||||
else:
|
||||
self.qemu_path = f"qemu-system-{platform}"
|
||||
self.qemu_path = f"qemu-system-{platform}"
|
||||
|
||||
def _disk_setter(self, variable, value):
|
||||
"""
|
||||
@@ -901,8 +897,8 @@ class QemuVM(BaseNode):
|
||||
options = options.replace("-enable-kvm", "-machine accel=kvm")
|
||||
|
||||
if "-enable-hax" in options:
|
||||
if not sys.platform.startswith("win"):
|
||||
# HAXM is only available on Windows
|
||||
if not sys.platform.startswith("darwin"):
|
||||
# HAXM is only available on macOS
|
||||
options = options.replace("-enable-hax", "")
|
||||
else:
|
||||
options = options.replace("-enable-hax", "-machine accel=hax")
|
||||
@@ -1002,52 +998,25 @@ class QemuVM(BaseNode):
|
||||
if self._process_priority == "normal":
|
||||
return
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
try:
|
||||
import win32api
|
||||
import win32con
|
||||
import win32process
|
||||
except ImportError:
|
||||
log.error(f"pywin32 must be installed to change the priority class for QEMU VM {self._name}")
|
||||
else:
|
||||
log.info(f"Setting QEMU VM {self._name} priority class to {self._process_priority}")
|
||||
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, 0, self._process.pid)
|
||||
if self._process_priority == "realtime":
|
||||
priority = win32process.REALTIME_PRIORITY_CLASS
|
||||
elif self._process_priority == "very high":
|
||||
priority = win32process.HIGH_PRIORITY_CLASS
|
||||
elif self._process_priority == "high":
|
||||
priority = win32process.ABOVE_NORMAL_PRIORITY_CLASS
|
||||
elif self._process_priority == "low":
|
||||
priority = win32process.BELOW_NORMAL_PRIORITY_CLASS
|
||||
elif self._process_priority == "very low":
|
||||
priority = win32process.IDLE_PRIORITY_CLASS
|
||||
else:
|
||||
priority = win32process.NORMAL_PRIORITY_CLASS
|
||||
try:
|
||||
win32process.SetPriorityClass(handle, priority)
|
||||
except win32process.error as e:
|
||||
log.error(f'Could not change process priority for QEMU VM "{self._name}": {e}')
|
||||
if self._process_priority == "realtime":
|
||||
priority = -20
|
||||
elif self._process_priority == "very high":
|
||||
priority = -15
|
||||
elif self._process_priority == "high":
|
||||
priority = -5
|
||||
elif self._process_priority == "low":
|
||||
priority = 5
|
||||
elif self._process_priority == "very low":
|
||||
priority = 19
|
||||
else:
|
||||
if self._process_priority == "realtime":
|
||||
priority = -20
|
||||
elif self._process_priority == "very high":
|
||||
priority = -15
|
||||
elif self._process_priority == "high":
|
||||
priority = -5
|
||||
elif self._process_priority == "low":
|
||||
priority = 5
|
||||
elif self._process_priority == "very low":
|
||||
priority = 19
|
||||
else:
|
||||
priority = 0
|
||||
try:
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
"renice", "-n", str(priority), "-p", str(self._process.pid)
|
||||
)
|
||||
await process.wait()
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
log.error(f'Could not change process priority for QEMU VM "{self._name}": {e}')
|
||||
priority = 0
|
||||
try:
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
"renice", "-n", str(priority), "-p", str(self._process.pid)
|
||||
)
|
||||
await process.wait()
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
log.error(f'Could not change process priority for QEMU VM "{self._name}": {e}')
|
||||
|
||||
def _stop_cpulimit(self):
|
||||
"""
|
||||
@@ -1070,14 +1039,8 @@ class QemuVM(BaseNode):
|
||||
return
|
||||
|
||||
try:
|
||||
if sys.platform.startswith("win") and hasattr(sys, "frozen"):
|
||||
cpulimit_exec = os.path.join(
|
||||
os.path.dirname(os.path.abspath(sys.executable)), "cpulimit", "cpulimit.exe"
|
||||
)
|
||||
else:
|
||||
cpulimit_exec = "cpulimit"
|
||||
subprocess.Popen(
|
||||
[cpulimit_exec, "--lazy", f"--pid={self._process.pid}", f"--limit={self._cpu_throttling}"],
|
||||
["cpulimit", "--lazy", f"--pid={self._process.pid}", f"--limit={self._cpu_throttling}"],
|
||||
cwd=self.working_dir,
|
||||
)
|
||||
log.info(f"CPU throttled to {self._cpu_throttling}%")
|
||||
@@ -1133,7 +1096,7 @@ class QemuVM(BaseNode):
|
||||
self.check_available_ram(self.ram)
|
||||
|
||||
command = await self._build_command()
|
||||
command_string = " ".join(shlex_quote(s) for s in command)
|
||||
command_string = " ".join(shlex.quote(s) for s in command)
|
||||
try:
|
||||
log.info(f"Starting QEMU with: {command_string}")
|
||||
self._stdout_file = os.path.join(self.working_dir, "qemu.log")
|
||||
@@ -1193,8 +1156,7 @@ class QemuVM(BaseNode):
|
||||
if self.started:
|
||||
log.info("QEMU process has stopped, return code: %d", returncode)
|
||||
await self.stop()
|
||||
# A return code of 1 seem fine on Windows
|
||||
if returncode != 0 and (not sys.platform.startswith("win") or returncode != 1):
|
||||
if returncode != 0:
|
||||
self.project.emit(
|
||||
"log.error",
|
||||
{"message": f"QEMU process has stopped, return code: {returncode}\n{self.read_stdout()}"},
|
||||
@@ -1822,7 +1784,7 @@ class QemuVM(BaseNode):
|
||||
|
||||
self._qemu_img_stdout_file = os.path.join(self.working_dir, "qemu-img.log")
|
||||
log.info(f"logging to {self._qemu_img_stdout_file}")
|
||||
command_string = " ".join(shlex_quote(s) for s in command)
|
||||
command_string = " ".join(shlex.quote(s) for s in command)
|
||||
log.info(f"Executing qemu-img with: {command_string}")
|
||||
with open(self._qemu_img_stdout_file, "w", encoding="utf-8") as fd:
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
@@ -2272,15 +2234,7 @@ class QemuVM(BaseNode):
|
||||
require_hardware_accel = self.manager.config.settings.Qemu.require_hardware_acceleration
|
||||
if enable_hardware_accel and "-machine accel=tcg" not in options:
|
||||
# Turn OFF hardware acceleration for non x86 architectures
|
||||
if sys.platform.startswith("win"):
|
||||
supported_binaries = [
|
||||
"qemu-system-x86_64.exe",
|
||||
"qemu-system-x86_64w.exe",
|
||||
"qemu-system-i386.exe",
|
||||
"qemu-system-i386w.exe",
|
||||
]
|
||||
else:
|
||||
supported_binaries = ["qemu-system-x86_64", "qemu-system-i386", "qemu-kvm"]
|
||||
supported_binaries = ["qemu-system-x86_64", "qemu-system-i386", "qemu-kvm"]
|
||||
if os.path.basename(qemu_path) not in supported_binaries:
|
||||
if require_hardware_accel:
|
||||
raise QemuError(
|
||||
@@ -2298,29 +2252,6 @@ class QemuVM(BaseNode):
|
||||
)
|
||||
else:
|
||||
return False
|
||||
elif sys.platform.startswith("win"):
|
||||
if require_hardware_accel:
|
||||
# HAXM is only available starting with Qemu version 2.9.0
|
||||
version = await self.manager.get_qemu_version(self.qemu_path)
|
||||
if version and parse_version(version) < parse_version("2.9.0"):
|
||||
raise QemuError(
|
||||
f"HAXM acceleration can only be enable for Qemu version 2.9.0 and above (current version: {version})"
|
||||
)
|
||||
|
||||
# check if HAXM is installed
|
||||
version = self.manager.get_haxm_windows_version()
|
||||
if version is None:
|
||||
raise QemuError("HAXM acceleration support is not installed on this host")
|
||||
log.info(f"HAXM support version {version} detected")
|
||||
|
||||
# check if the HAXM service is running
|
||||
from gns3server.utils.windows_service import check_windows_service_is_running
|
||||
|
||||
if not check_windows_service_is_running("intelhaxm"):
|
||||
raise QemuError("Intel HAXM service is not running on this host")
|
||||
|
||||
else:
|
||||
return False
|
||||
elif sys.platform.startswith("darwin"):
|
||||
process = await asyncio.create_subprocess_shell("kextstat | grep com.intel.kext.intelhaxm")
|
||||
await process.wait()
|
||||
@@ -2440,7 +2371,7 @@ class QemuVM(BaseNode):
|
||||
# https://github.com/GNS3/gns3-server/issues/685
|
||||
if version and parse_version(version) >= parse_version("2.4.0") and self.platform == "x86_64":
|
||||
command.extend(["-machine", "smm=off"])
|
||||
elif sys.platform.startswith("win") or sys.platform.startswith("darwin"):
|
||||
elif sys.platform.startswith("darwin"):
|
||||
command.extend(["-enable-hax"])
|
||||
command.extend(["-boot", f"order={self._boot_priority}"])
|
||||
command.extend(self._bios_option())
|
||||
|
||||
@@ -27,7 +27,6 @@ import re
|
||||
|
||||
from gns3server.utils import parse_version
|
||||
from gns3server.utils.asyncio import wait_for_process_termination
|
||||
from gns3server.utils.asyncio import monitor_process
|
||||
from gns3server.utils.asyncio import subprocess_check_output
|
||||
from .ubridge_hypervisor import UBridgeHypervisor
|
||||
from .ubridge_error import UbridgeError
|
||||
@@ -139,7 +138,7 @@ class Hypervisor(UBridgeHypervisor):
|
||||
match = re.search(r"ubridge version ([0-9a-z\.]+)", output)
|
||||
if match:
|
||||
self._version = match.group(1)
|
||||
if sys.platform.startswith("win") or sys.platform.startswith("darwin"):
|
||||
if sys.platform.startswith("darwin"):
|
||||
minimum_required_version = "0.9.12"
|
||||
else:
|
||||
# uBridge version 0.9.14 is required for packet filters
|
||||
@@ -158,11 +157,6 @@ class Hypervisor(UBridgeHypervisor):
|
||||
"""
|
||||
|
||||
env = os.environ.copy()
|
||||
if sys.platform.startswith("win"):
|
||||
# add the Npcap directory to $PATH to force uBridge to use npcap DLL instead of Winpcap (if installed)
|
||||
system_root = os.path.join(os.path.expandvars("%SystemRoot%"), "System32", "Npcap")
|
||||
if os.path.isdir(system_root):
|
||||
env["PATH"] = system_root + ";" + env["PATH"]
|
||||
await self._check_ubridge_version(env)
|
||||
try:
|
||||
command = self._build_command()
|
||||
|
||||
@@ -62,16 +62,7 @@ class VirtualBox(BaseManager):
|
||||
vboxmanage_path = shutil.which(vboxmanage_path)
|
||||
else:
|
||||
log.info("A path to VBoxManage has not been configured, trying to find it...")
|
||||
if sys.platform.startswith("win"):
|
||||
if "VBOX_INSTALL_PATH" in os.environ:
|
||||
vboxmanage_path_windows = os.path.join(os.environ["VBOX_INSTALL_PATH"], "VBoxManage.exe")
|
||||
if os.path.exists(vboxmanage_path_windows):
|
||||
vboxmanage_path = vboxmanage_path_windows
|
||||
elif "VBOX_MSI_INSTALL_PATH" in os.environ:
|
||||
vboxmanage_path_windows = os.path.join(os.environ["VBOX_MSI_INSTALL_PATH"], "VBoxManage.exe")
|
||||
if os.path.exists(vboxmanage_path_windows):
|
||||
vboxmanage_path = vboxmanage_path_windows
|
||||
elif sys.platform.startswith("darwin"):
|
||||
if sys.platform.startswith("darwin"):
|
||||
vboxmanage_path_osx = "/Applications/VirtualBox.app/Contents/MacOS/VBoxManage"
|
||||
if os.path.exists(vboxmanage_path_osx):
|
||||
vboxmanage_path = vboxmanage_path_osx
|
||||
|
||||
@@ -38,10 +38,6 @@ from gns3server.compute.nios.nio_udp import NIOUDP
|
||||
from gns3server.compute.adapters.ethernet_adapter import EthernetAdapter
|
||||
from gns3server.compute.base_node import BaseNode
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
import msvcrt
|
||||
import win32file
|
||||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -839,14 +835,11 @@ class VirtualBoxVM(BaseNode):
|
||||
:returns: pipe path (string)
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
pipe_name = fr"\\.\pipe\gns3_vbox\{self.id}"
|
||||
else:
|
||||
pipe_name = os.path.join(tempfile.gettempdir(), "gns3_vbox", f"{self.id}")
|
||||
try:
|
||||
os.makedirs(os.path.dirname(pipe_name), exist_ok=True)
|
||||
except OSError as e:
|
||||
raise VirtualBoxError(f"Could not create the VirtualBox pipe directory: {e}")
|
||||
pipe_name = os.path.join(tempfile.gettempdir(), "gns3_vbox", f"{self.id}")
|
||||
try:
|
||||
os.makedirs(os.path.dirname(pipe_name), exist_ok=True)
|
||||
except OSError as e:
|
||||
raise VirtualBoxError(f"Could not create the VirtualBox pipe directory: {e}")
|
||||
return pipe_name
|
||||
|
||||
async def _set_serial_console(self):
|
||||
|
||||
@@ -27,11 +27,12 @@ import subprocess
|
||||
import logging
|
||||
import codecs
|
||||
import ipaddress
|
||||
import shlex
|
||||
|
||||
from collections import OrderedDict
|
||||
from gns3server.utils.interfaces import interfaces
|
||||
from gns3server.utils.asyncio import subprocess_check_output
|
||||
from gns3server.utils import parse_version, shlex_quote
|
||||
from gns3server.utils import parse_version
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -53,10 +54,7 @@ class VMware(BaseManager):
|
||||
self._vmnets = []
|
||||
self._vmnets_info = {}
|
||||
self._vmnet_start_range = 2
|
||||
if sys.platform.startswith("win"):
|
||||
self._vmnet_end_range = 19
|
||||
else:
|
||||
self._vmnet_end_range = 255
|
||||
self._vmnet_end_range = 255
|
||||
|
||||
@property
|
||||
def vmrun_path(self):
|
||||
@@ -95,15 +93,7 @@ class VMware(BaseManager):
|
||||
# look for vmrun
|
||||
vmrun_path = self.config.settings.VMware.vmrun_path
|
||||
if not vmrun_path:
|
||||
if sys.platform.startswith("win"):
|
||||
vmrun_path = shutil.which("vmrun")
|
||||
if vmrun_path is None:
|
||||
# look for vmrun.exe using the VMware Workstation directory listed in the registry
|
||||
vmrun_path = self._find_vmrun_registry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware Workstation")
|
||||
if vmrun_path is None:
|
||||
# look for vmrun.exe using the VIX directory listed in the registry
|
||||
vmrun_path = self._find_vmrun_registry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware VIX")
|
||||
elif sys.platform.startswith("darwin"):
|
||||
if sys.platform.startswith("darwin"):
|
||||
vmrun_path = "/Applications/VMware Fusion.app/Contents/Library/vmrun"
|
||||
else:
|
||||
vmrun_path = "vmrun"
|
||||
@@ -197,84 +187,44 @@ class VMware(BaseManager):
|
||||
Check VMware version
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
# look for vmrun.exe using the directory listed in the registry
|
||||
ws_version = self._find_vmware_version_registry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware Workstation")
|
||||
if ws_version is None:
|
||||
player_version = self._find_vmware_version_registry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware Player")
|
||||
if player_version:
|
||||
log.debug(f"VMware Player version {player_version} detected")
|
||||
await self._check_vmware_player_requirements(player_version)
|
||||
else:
|
||||
log.warning("Could not find VMware version")
|
||||
self._host_type = "ws"
|
||||
else:
|
||||
log.debug(f"VMware Workstation version {ws_version} detected")
|
||||
await self._check_vmware_workstation_requirements(ws_version)
|
||||
else:
|
||||
if sys.platform.startswith("darwin"):
|
||||
if not os.path.isdir("/Applications/VMware Fusion.app"):
|
||||
raise VMwareError(
|
||||
"VMware Fusion is not installed in the standard location /Applications/VMware Fusion.app"
|
||||
)
|
||||
self._host_type = "fusion"
|
||||
return # FIXME: no version checking on Mac OS X but we support all versions of fusion
|
||||
if sys.platform.startswith("darwin"):
|
||||
if not os.path.isdir("/Applications/VMware Fusion.app"):
|
||||
raise VMwareError(
|
||||
"VMware Fusion is not installed in the standard location /Applications/VMware Fusion.app"
|
||||
)
|
||||
self._host_type = "fusion"
|
||||
return # FIXME: no version checking on Mac OS X but we support all versions of fusion
|
||||
|
||||
vmware_path = VMware._get_linux_vmware_binary()
|
||||
if vmware_path is None:
|
||||
raise VMwareError("VMware is not installed (vmware or vmplayer executable could not be found in $PATH)")
|
||||
vmware_path = VMware._get_linux_vmware_binary()
|
||||
if vmware_path is None:
|
||||
raise VMwareError("VMware is not installed (vmware or vmplayer executable could not be found in $PATH)")
|
||||
|
||||
try:
|
||||
output = await subprocess_check_output(vmware_path, "-v")
|
||||
match = re.search(r"VMware Workstation ([0-9]+)\.", output)
|
||||
version = None
|
||||
if match:
|
||||
# VMware Workstation has been detected
|
||||
version = match.group(1)
|
||||
log.debug(f"VMware Workstation version {version} detected")
|
||||
await self._check_vmware_workstation_requirements(version)
|
||||
match = re.search(r"VMware Player ([0-9]+)\.", output)
|
||||
if match:
|
||||
# VMware Player has been detected
|
||||
version = match.group(1)
|
||||
log.debug(f"VMware Player version {version} detected")
|
||||
await self._check_vmware_player_requirements(version)
|
||||
if version is None:
|
||||
log.warning(f"Could not find VMware version. Output of VMware: {output}")
|
||||
raise VMwareError(f"Could not find VMware version. Output of VMware: {output}")
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
log.error(f"Error while looking for the VMware version: {e}")
|
||||
raise VMwareError(f"Error while looking for the VMware version: {e}")
|
||||
|
||||
@staticmethod
|
||||
def _get_vmnet_interfaces_registry():
|
||||
|
||||
import winreg
|
||||
|
||||
vmnet_interfaces = []
|
||||
regkey = r"SOFTWARE\Wow6432Node\VMware, Inc.\VMnetLib\VMnetConfig"
|
||||
try:
|
||||
hkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, regkey)
|
||||
for index in range(winreg.QueryInfoKey(hkey)[0]):
|
||||
vmnet = winreg.EnumKey(hkey, index)
|
||||
hkeyvmnet = winreg.OpenKey(hkey, vmnet)
|
||||
if winreg.QueryInfoKey(hkeyvmnet)[1]:
|
||||
# the vmnet has not been configure if the key has no values
|
||||
vmnet = vmnet.replace("vm", "VM")
|
||||
if vmnet not in ("VMnet0", "VMnet1", "VMnet8"):
|
||||
vmnet_interfaces.append(vmnet)
|
||||
winreg.CloseKey(hkeyvmnet)
|
||||
winreg.CloseKey(hkey)
|
||||
except OSError as e:
|
||||
raise VMwareError(f"Could not read registry key {regkey}: {e}")
|
||||
return vmnet_interfaces
|
||||
output = await subprocess_check_output(vmware_path, "-v")
|
||||
match = re.search(r"VMware Workstation ([0-9]+)\.", output)
|
||||
version = None
|
||||
if match:
|
||||
# VMware Workstation has been detected
|
||||
version = match.group(1)
|
||||
log.debug(f"VMware Workstation version {version} detected")
|
||||
await self._check_vmware_workstation_requirements(version)
|
||||
match = re.search(r"VMware Player ([0-9]+)\.", output)
|
||||
if match:
|
||||
# VMware Player has been detected
|
||||
version = match.group(1)
|
||||
log.debug(f"VMware Player version {version} detected")
|
||||
await self._check_vmware_player_requirements(version)
|
||||
if version is None:
|
||||
log.warning(f"Could not find VMware version. Output of VMware: {output}")
|
||||
raise VMwareError(f"Could not find VMware version. Output of VMware: {output}")
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
log.error(f"Error while looking for the VMware version: {e}")
|
||||
raise VMwareError(f"Error while looking for the VMware version: {e}")
|
||||
|
||||
@staticmethod
|
||||
def _get_vmnet_interfaces():
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
return VMware._get_vmnet_interfaces_registry()
|
||||
elif sys.platform.startswith("darwin"):
|
||||
if sys.platform.startswith("darwin"):
|
||||
vmware_networking_file = "/Library/Preferences/VMware Fusion/networking"
|
||||
else:
|
||||
# location on Linux
|
||||
@@ -310,17 +260,7 @@ class VMware(BaseManager):
|
||||
|
||||
vmnet_interfaces = []
|
||||
for interface in interfaces():
|
||||
if sys.platform.startswith("win"):
|
||||
if "netcard" in interface:
|
||||
windows_name = interface["netcard"]
|
||||
else:
|
||||
windows_name = interface["name"]
|
||||
match = re.search(r"(VMnet[0-9]+)", windows_name)
|
||||
if match:
|
||||
vmnet = match.group(1)
|
||||
if vmnet not in ("VMnet0", "VMnet1", "VMnet8"):
|
||||
vmnet_interfaces.append(vmnet)
|
||||
elif interface["name"].startswith("vmnet"):
|
||||
if interface["name"].startswith("vmnet"):
|
||||
vmnet = interface["name"]
|
||||
if vmnet not in ("vmnet0", "vmnet1", "vmnet8"):
|
||||
vmnet_interfaces.append(interface["name"])
|
||||
@@ -428,7 +368,7 @@ class VMware(BaseManager):
|
||||
|
||||
command = [vmrun_path, "-T", self.host_type, subcommand]
|
||||
command.extend(args)
|
||||
command_string = " ".join([shlex_quote(c) for c in command])
|
||||
command_string = " ".join([shlex.quote(c) for c in command])
|
||||
log.log(log_level, f"Executing vmrun with command: {command_string}")
|
||||
try:
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
@@ -677,9 +617,7 @@ class VMware(BaseManager):
|
||||
:returns: path to the inventory file
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
return os.path.expandvars(r"%APPDATA%\Vmware\Inventory.vmls")
|
||||
elif sys.platform.startswith("darwin"):
|
||||
if sys.platform.startswith("darwin"):
|
||||
return os.path.expanduser("~/Library/Application Support/VMware Fusion/vmInventory")
|
||||
else:
|
||||
return os.path.expanduser("~/.vmware/inventory.vmls")
|
||||
@@ -692,9 +630,7 @@ class VMware(BaseManager):
|
||||
:returns: path to the preferences file
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
return os.path.expandvars(r"%APPDATA%\VMware\preferences.ini")
|
||||
elif sys.platform.startswith("darwin"):
|
||||
if sys.platform.startswith("darwin"):
|
||||
return os.path.expanduser("~/Library/Preferences/VMware Fusion/preferences")
|
||||
else:
|
||||
return os.path.expanduser("~/.vmware/preferences")
|
||||
@@ -707,15 +643,7 @@ class VMware(BaseManager):
|
||||
:returns: path to the default VM directory
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
import ctypes
|
||||
import ctypes.wintypes
|
||||
|
||||
path = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
|
||||
ctypes.windll.shell32.SHGetFolderPathW(None, 5, None, 0, path)
|
||||
documents_folder = path.value
|
||||
return [fr"{documents_folder}\My Virtual Machines", fr"{documents_folder}\Virtual Machines"]
|
||||
elif sys.platform.startswith("darwin"):
|
||||
if sys.platform.startswith("darwin"):
|
||||
return [os.path.expanduser("~/Documents/Virtual Machines.localized")]
|
||||
else:
|
||||
return [os.path.expanduser("~/vmware")]
|
||||
|
||||
@@ -882,14 +882,11 @@ class VMwareVM(BaseNode):
|
||||
:returns: pipe path (string)
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
pipe_name = fr"\\.\pipe\gns3_vmware\{self.id}"
|
||||
else:
|
||||
pipe_name = os.path.join(tempfile.gettempdir(), "gns3_vmware", f"{self.id}")
|
||||
try:
|
||||
os.makedirs(os.path.dirname(pipe_name), exist_ok=True)
|
||||
except OSError as e:
|
||||
raise VMwareError(f"Could not create the VMware pipe directory: {e}")
|
||||
pipe_name = os.path.join(tempfile.gettempdir(), "gns3_vmware", f"{self.id}")
|
||||
try:
|
||||
os.makedirs(os.path.dirname(pipe_name), exist_ok=True)
|
||||
except OSError as e:
|
||||
raise VMwareError(f"Could not create the VMware pipe directory: {e}")
|
||||
return pipe_name
|
||||
|
||||
def _set_serial_console(self):
|
||||
|
||||
Reference in new issue
Block a user