mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-15 12:59:06 +00:00
Merge branch 'master' into 1.5
This commit is contained in:
commit
f6fb0623be
16
CHANGELOG
16
CHANGELOG
@ -1,5 +1,21 @@
|
||||
# Change Log
|
||||
|
||||
## 1.4.1 01/02/2016
|
||||
* VMware raise error if version is not found
|
||||
* For topologies before 1.4 manage qemu missing
|
||||
* Fixes issue with packet capture on VMware VMs. Fixes #396.
|
||||
* Fixes concurrency issue when closing multiple VMware linked clone VMs. Fixes #410.
|
||||
* Fixes "can only use tap interfaces that both already exist and are up". Fixes #399.
|
||||
* Send machine stats via the notification stream
|
||||
* Check for /dev/kvm instead of kvm-ok
|
||||
* Show a warning when starting ASA8
|
||||
* Fix error when setting Qemu VM boot to 'cd' (HDD or CD/DVD-ROM)
|
||||
* Fixed the VMware default VM location on Windows, so that it doesn't assume the "Documents" folder is within the %USERPROFILE% folder, and also support Windows Server's folder (which is "My Virtual Machines" instead of "Virtual Machines").
|
||||
* Improve dynamips startup_config dump
|
||||
* Dump environnement to server debug log
|
||||
* Fix usage of qemu 0.10 on Windows
|
||||
* Show hostname when the hostname is missing in the iourc.txt
|
||||
|
||||
## 1.4.0 12/01/2016
|
||||
* Release 1.4.0
|
||||
|
||||
|
@ -148,11 +148,12 @@ class IOUHandler:
|
||||
"vm_id": "UUID for the instance"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance started",
|
||||
200: "Instance started",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
input=IOU_START_SCHEMA,
|
||||
output=IOU_OBJECT_SCHEMA,
|
||||
description="Start a IOU instance")
|
||||
def start(request, response):
|
||||
|
||||
@ -166,7 +167,7 @@ class IOUHandler:
|
||||
print(vm.iourc_path)
|
||||
|
||||
yield from vm.start()
|
||||
response.set_status(204)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
|
@ -146,11 +146,12 @@ class QEMUHandler:
|
||||
"vm_id": "UUID for the instance"
|
||||
},
|
||||
status_codes={
|
||||
204: "Instance started",
|
||||
200: "Instance started",
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Start a Qemu VM instance")
|
||||
description="Start a Qemu VM instance",
|
||||
output=QEMU_OBJECT_SCHEMA)
|
||||
def start(request, response):
|
||||
|
||||
qemu_manager = Qemu.instance()
|
||||
@ -161,7 +162,7 @@ class QEMUHandler:
|
||||
if pm.check_hardware_virtualization(vm) is False:
|
||||
raise HTTPConflict(text="Cannot start VM with KVM enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
|
||||
yield from vm.start()
|
||||
response.set_status(204)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
|
@ -130,13 +130,14 @@ class VPCSHandler:
|
||||
400: "Invalid request",
|
||||
404: "Instance doesn't exist"
|
||||
},
|
||||
description="Start a VPCS instance")
|
||||
description="Start a VPCS instance",
|
||||
output=VPCS_OBJECT_SCHEMA)
|
||||
def start(request, response):
|
||||
|
||||
vpcs_manager = VPCS.instance()
|
||||
vm = vpcs_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
|
||||
yield from vm.start()
|
||||
response.set_status(204)
|
||||
response.json(vm)
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
|
@ -58,6 +58,7 @@ class BaseVM:
|
||||
self._hw_virtualization = False
|
||||
self._ubridge_hypervisor = None
|
||||
self._vm_status = "stopped"
|
||||
self._command_line = ""
|
||||
|
||||
if self._console is not None:
|
||||
if console_type == "vnc":
|
||||
@ -94,6 +95,17 @@ class BaseVM:
|
||||
self._vm_status = status
|
||||
self._project.emit("vm.{}".format(status), self)
|
||||
|
||||
@property
|
||||
def command_line(self):
|
||||
"""Return command used to start the VM"""
|
||||
|
||||
return self._command_line
|
||||
|
||||
@command_line.setter
|
||||
def command_line(self, command_line):
|
||||
|
||||
self._command_line = command_line
|
||||
|
||||
@property
|
||||
def project(self):
|
||||
"""
|
||||
|
@ -710,10 +710,12 @@ class Dynamips(BaseManager):
|
||||
"""
|
||||
|
||||
image_dir = self.get_images_directory()
|
||||
if not os.path.exists(image_dir):
|
||||
return []
|
||||
try:
|
||||
files = os.listdir(image_dir)
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
except OSError as e:
|
||||
raise DynamipsError("Can not list {}: {}".format(image_dir, str(e)))
|
||||
files.sort()
|
||||
images = []
|
||||
for filename in files:
|
||||
@ -724,7 +726,6 @@ class Dynamips(BaseManager):
|
||||
# read the first 7 bytes of the file.
|
||||
elf_header_start = f.read(7)
|
||||
except OSError as e:
|
||||
print(e)
|
||||
continue
|
||||
# valid IOS images must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1
|
||||
if elf_header_start == b'\x7fELF\x01\x02\x01':
|
||||
|
@ -48,9 +48,9 @@ class NIOVDE(NIO):
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
self._hypervisor.send("nio create_vde {name} {control} {local}".format(name=self._name,
|
||||
control=self._control_file,
|
||||
local=self._local_file))
|
||||
yield from self._hypervisor.send("nio create_vde {name} {control} {local}".format(name=self._name,
|
||||
control=self._control_file,
|
||||
local=self._local_file))
|
||||
|
||||
log.info("NIO VDE {name} created with control={control}, local={local}".format(name=self._name,
|
||||
control=self._control_file,
|
||||
|
@ -367,7 +367,7 @@ class Router(BaseVM):
|
||||
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_flash[0-1]".format(self.platform, self.dynamips_id)))
|
||||
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_rom".format(self.platform, self.dynamips_id)))
|
||||
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_bootflash".format(self.platform, self.dynamips_id)))
|
||||
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_ssa").format(self.platform, self.dynamips_id))
|
||||
files += glob.glob(os.path.join(glob.escape(project_dir), "{}_i{}_ssa".format(self.platform, self.dynamips_id)))
|
||||
for file in files:
|
||||
try:
|
||||
log.debug("Deleting file {}".format(file))
|
||||
|
@ -72,7 +72,6 @@ class IOUVM(BaseVM):
|
||||
|
||||
super().__init__(name, vm_id, project, manager, console=console)
|
||||
|
||||
self._command = []
|
||||
self._iouyap_process = None
|
||||
self._iou_process = None
|
||||
self._iou_stdout_file = ""
|
||||
@ -220,7 +219,8 @@ class IOUVM(BaseVM):
|
||||
"startup_config": self.relative_startup_config_file,
|
||||
"private_config": self.relative_private_config_file,
|
||||
"iourc_path": self.iourc_path,
|
||||
"use_default_iou_values": self._use_default_iou_values}
|
||||
"use_default_iou_values": self._use_default_iou_values,
|
||||
"command_line": self.command_line}
|
||||
|
||||
# return the relative path if the IOU image is in the images_path directory
|
||||
iou_vm_info["path"] = self.manager.get_relative_image_path(self.path)
|
||||
@ -403,9 +403,9 @@ class IOUVM(BaseVM):
|
||||
raise IOUError("Hostname \"{}\" not found in iourc file {}".format(hostname, self.iourc_path))
|
||||
user_ioukey = config["license"][hostname]
|
||||
if user_ioukey[-1:] != ';':
|
||||
raise IOUError("IOU key not ending with ; in iourc file".format(self.iourc_path))
|
||||
raise IOUError("IOU key not ending with ; in iourc file {}".format(self.iourc_path))
|
||||
if len(user_ioukey) != 17:
|
||||
raise IOUError("IOU key length is not 16 characters in iourc file".format(self.iourc_path))
|
||||
raise IOUError("IOU key length is not 16 characters in iourc file {}".format(self.iourc_path))
|
||||
user_ioukey = user_ioukey[:16]
|
||||
|
||||
# We can't test this because it's mean distributing a valid licence key
|
||||
@ -502,13 +502,14 @@ class IOUVM(BaseVM):
|
||||
|
||||
if "IOURC" not in os.environ:
|
||||
env["IOURC"] = iourc_path
|
||||
self._command = yield from self._build_command()
|
||||
command = yield from self._build_command()
|
||||
try:
|
||||
log.info("Starting IOU: {}".format(self._command))
|
||||
log.info("Starting IOU: {}".format(command))
|
||||
self._iou_stdout_file = os.path.join(self.working_dir, "iou.log")
|
||||
log.info("Logging to {}".format(self._iou_stdout_file))
|
||||
with open(self._iou_stdout_file, "w", encoding="utf-8") as fd:
|
||||
self._iou_process = yield from asyncio.create_subprocess_exec(*self._command,
|
||||
self.command_line = ' '.join(command)
|
||||
self._iou_process = yield from asyncio.create_subprocess_exec(*command,
|
||||
stdout=fd,
|
||||
stderr=subprocess.STDOUT,
|
||||
cwd=self.working_dir,
|
||||
|
@ -142,16 +142,14 @@ class PortManager:
|
||||
if end_port < start_port:
|
||||
raise HTTPConflict(text="Invalid port range {}-{}".format(start_port, end_port))
|
||||
|
||||
|
||||
last_exception = None
|
||||
for port in range(start_port, end_port + 1):
|
||||
if port in ignore_ports:
|
||||
continue
|
||||
|
||||
last_exception
|
||||
try:
|
||||
PortManager._check_port(host, port, socket_type)
|
||||
return port
|
||||
PortManager._check_port(host, port, socket_type)
|
||||
return port
|
||||
except OSError as e:
|
||||
last_exception = e
|
||||
if port + 1 == end_port:
|
||||
@ -163,6 +161,7 @@ class PortManager:
|
||||
end_port,
|
||||
host,
|
||||
last_exception))
|
||||
|
||||
@staticmethod
|
||||
def _check_port(host, port, socket_type):
|
||||
"""
|
||||
@ -182,7 +181,6 @@ class PortManager:
|
||||
s.bind(sa) # the port is available if bind is a success
|
||||
return True
|
||||
|
||||
|
||||
def get_free_tcp_port(self, project, port_range_start=None, port_range_end=None):
|
||||
"""
|
||||
Get an available TCP port and reserve it
|
||||
@ -291,7 +289,7 @@ class PortManager:
|
||||
"""
|
||||
|
||||
if port in self._used_udp_ports:
|
||||
raise HTTPConflict(text="UDP port {} already in use on host".format(port, self._console_host))
|
||||
raise HTTPConflict(text="UDP port {} already in use on host {}".format(port, self._console_host))
|
||||
if port < self._udp_port_range[0] or port > self._udp_port_range[1]:
|
||||
raise HTTPConflict(text="UDP port {} is outside the range {}-{}".format(port, self._udp_port_range[0], self._udp_port_range[1]))
|
||||
self._used_udp_ports.add(port)
|
||||
|
@ -141,7 +141,10 @@ class Project:
|
||||
|
||||
if hasattr(self, "_path"):
|
||||
if path != self._path and self.is_local() is False:
|
||||
raise aiohttp.web.HTTPForbidden(text="You are not allowed to modify the project directory location")
|
||||
raise aiohttp.web.HTTPForbidden(text="You are not allowed to modify the project directory path")
|
||||
|
||||
if '"' in path:
|
||||
raise aiohttp.web.HTTPForbidden(text="You are not allowed to use \" in the project directory path. It's not supported by Dynamips.")
|
||||
|
||||
self._path = path
|
||||
self._update_temporary_file()
|
||||
|
@ -117,6 +117,8 @@ class Qemu(BaseManager):
|
||||
for path in Qemu.paths_list():
|
||||
try:
|
||||
for f in os.listdir(path):
|
||||
if f.endswith("-spice"):
|
||||
continue
|
||||
if (f.startswith("qemu-system") or f.startswith("qemu-kvm") or f == "qemu" or f == "qemu.exe") and \
|
||||
os.access(os.path.join(path, f), os.X_OK) and \
|
||||
os.path.isfile(os.path.join(path, f)):
|
||||
|
@ -68,7 +68,6 @@ class QemuVM(BaseVM):
|
||||
self._host = server_config.get("host", "127.0.0.1")
|
||||
self._monitor_host = server_config.get("monitor_host", "127.0.0.1")
|
||||
self._linked_clone = linked_clone
|
||||
self._command = []
|
||||
self._process = None
|
||||
self._cpulimit_process = None
|
||||
self._monitor = None
|
||||
@ -867,15 +866,16 @@ class QemuVM(BaseVM):
|
||||
# check if there is enough RAM to run
|
||||
self.check_available_ram(self.ram)
|
||||
|
||||
self._command = yield from self._build_command()
|
||||
command_string = " ".join(shlex.quote(s) for s in self._command)
|
||||
command = yield from self._build_command()
|
||||
command_string = " ".join(shlex.quote(s) for s in command)
|
||||
try:
|
||||
log.info("Starting QEMU with: {}".format(command_string))
|
||||
self._stdout_file = os.path.join(self.working_dir, "qemu.log")
|
||||
log.info("logging to {}".format(self._stdout_file))
|
||||
with open(self._stdout_file, "w", encoding="utf-8") as fd:
|
||||
fd.write("Start QEMU with {}\n\nExecution log:\n".format(command_string))
|
||||
self._process = yield from asyncio.create_subprocess_exec(*self._command,
|
||||
self.command_line = ' '.join(command)
|
||||
self._process = yield from asyncio.create_subprocess_exec(*command,
|
||||
stdout=fd,
|
||||
stderr=subprocess.STDOUT,
|
||||
cwd=self.working_dir)
|
||||
@ -1084,24 +1084,24 @@ class QemuVM(BaseVM):
|
||||
raise QemuError("Sorry, adding a link to a started Qemu VM is not supported.")
|
||||
# FIXME: does the code below work? very undocumented feature...
|
||||
# dynamically configure an UDP tunnel on the QEMU VM adapter
|
||||
if nio and isinstance(nio, NIOUDP):
|
||||
if self._legacy_networking:
|
||||
yield from self._control_vm("host_net_remove {} gns3-{}".format(adapter_number, adapter_number))
|
||||
yield from self._control_vm("host_net_add udp vlan={},name=gns3-{},sport={},dport={},daddr={}".format(adapter_number,
|
||||
adapter_number,
|
||||
nio.lport,
|
||||
nio.rport,
|
||||
nio.rhost))
|
||||
else:
|
||||
# Apparently there is a bug in Qemu...
|
||||
# netdev_add [user|tap|socket|hubport|netmap],id=str[,prop=value][,...] -- add host network device
|
||||
# netdev_del id -- remove host network device
|
||||
yield from self._control_vm("netdev_del gns3-{}".format(adapter_number))
|
||||
yield from self._control_vm("netdev_add socket,id=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_number,
|
||||
nio.rhost,
|
||||
nio.rport,
|
||||
self._host,
|
||||
nio.lport))
|
||||
# if nio and isinstance(nio, NIOUDP):
|
||||
# if self._legacy_networking:
|
||||
# yield from self._control_vm("host_net_remove {} gns3-{}".format(adapter_number, adapter_number))
|
||||
# yield from self._control_vm("host_net_add udp vlan={},name=gns3-{},sport={},dport={},daddr={}".format(adapter_number,
|
||||
# adapter_number,
|
||||
# nio.lport,
|
||||
# nio.rport,
|
||||
# nio.rhost))
|
||||
# else:
|
||||
# # Apparently there is a bug in Qemu...
|
||||
# # netdev_add [user|tap|socket|hubport|netmap],id=str[,prop=value][,...] -- add host network device
|
||||
# # netdev_del id -- remove host network device
|
||||
# yield from self._control_vm("netdev_del gns3-{}".format(adapter_number))
|
||||
# yield from self._control_vm("netdev_add socket,id=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_number,
|
||||
# nio.rhost,
|
||||
# nio.rport,
|
||||
# self._host,
|
||||
# nio.lport))
|
||||
|
||||
adapter.add_nio(0, nio)
|
||||
log.info('QEMU VM "{name}" [{id}]: {nio} added to adapter {adapter_number}'.format(name=self._name,
|
||||
|
@ -31,6 +31,7 @@ import codecs
|
||||
from collections import OrderedDict
|
||||
from gns3server.utils.interfaces import interfaces
|
||||
from gns3server.utils.asyncio import subprocess_check_output
|
||||
from pkg_resources import parse_version
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -96,21 +97,11 @@ class VMware(BaseManager):
|
||||
if sys.platform.startswith("win"):
|
||||
vmrun_path = shutil.which("vmrun")
|
||||
if vmrun_path is None:
|
||||
# look for vmrun.exe in default VMware Workstation directory
|
||||
vmrun_ws = os.path.expandvars(r"%PROGRAMFILES(X86)%\VMware\VMware Workstation\vmrun.exe")
|
||||
if os.path.exists(vmrun_ws):
|
||||
vmrun_path = vmrun_ws
|
||||
else:
|
||||
# look for vmrun.exe using the directory listed in the registry
|
||||
vmrun_path = self._find_vmrun_registry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware Workstation")
|
||||
# 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 in default VMware VIX directory
|
||||
vmrun_vix = os.path.expandvars(r"%PROGRAMFILES(X86)%\VMware\VMware VIX\vmrun.exe")
|
||||
if os.path.exists(vmrun_vix):
|
||||
vmrun_path = vmrun_vix
|
||||
else:
|
||||
# look for vmrun.exe using the directory listed in the registry
|
||||
vmrun_path = self._find_vmrun_registry(r"SOFTWARE\Wow6432Node\VMware, Inc.\VMware VIX")
|
||||
# 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"):
|
||||
vmrun_path = "/Applications/VMware Fusion.app/Contents/Library/vmrun"
|
||||
else:
|
||||
@ -358,6 +349,31 @@ class VMware(BaseManager):
|
||||
|
||||
return stdout_data.decode("utf-8", errors="ignore").splitlines()
|
||||
|
||||
@asyncio.coroutine
|
||||
def check_vmrun_version(self):
|
||||
|
||||
with (yield from self._execute_lock):
|
||||
vmrun_path = self.vmrun_path
|
||||
if not vmrun_path:
|
||||
vmrun_path = self.find_vmrun()
|
||||
|
||||
try:
|
||||
output = yield from subprocess_check_output(vmrun_path)
|
||||
match = re.search("vmrun version ([0-9\.]+)", output)
|
||||
version = None
|
||||
if match:
|
||||
version = match.group(1)
|
||||
log.debug("VMware vmrun version {} detected".format(version))
|
||||
if parse_version(version) < parse_version("1.13"):
|
||||
# VMware VIX library version must be at least >= 1.13
|
||||
raise VMwareError("VMware vmrun executable version must be >= version 1.13")
|
||||
if version is None:
|
||||
log.warning("Could not find VMware vmrun version. Output: {}".format(output))
|
||||
raise VMwareError("Could not find VMware vmrun version. Output: {}".format(output))
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
log.error("Error while looking for the VMware vmrun version: {}".format(e))
|
||||
raise VMwareError("Error while looking for the VMware vmrun version: {}".format(e))
|
||||
|
||||
@asyncio.coroutine
|
||||
def remove_from_vmware_inventory(self, vmx_path):
|
||||
"""
|
||||
|
@ -142,6 +142,7 @@ class VMwareVM(BaseVM):
|
||||
Creates this VM and handle linked clones.
|
||||
"""
|
||||
|
||||
yield from self.manager.check_vmrun_version()
|
||||
if self._linked_clone and not os.path.exists(os.path.join(self.working_dir, os.path.basename(self._vmx_path))):
|
||||
# create the base snapshot for linked clones
|
||||
base_snapshot_name = "GNS3 Linked Base for clones"
|
||||
|
@ -59,7 +59,6 @@ class VPCSVM(BaseVM):
|
||||
def __init__(self, name, vm_id, project, manager, console=None, startup_script=None):
|
||||
|
||||
super().__init__(name, vm_id, project, manager, console=console)
|
||||
self._command = []
|
||||
self._process = None
|
||||
self._vpcs_stdout_file = ""
|
||||
self._vpcs_version = None
|
||||
@ -115,7 +114,8 @@ class VPCSVM(BaseVM):
|
||||
"console": self._console,
|
||||
"project_id": self.project.id,
|
||||
"startup_script": self.startup_script,
|
||||
"startup_script_path": self.relative_startup_script}
|
||||
"startup_script_path": self.relative_startup_script,
|
||||
"command_line": self.command_line}
|
||||
|
||||
@property
|
||||
def relative_startup_script(self):
|
||||
@ -223,16 +223,17 @@ class VPCSVM(BaseVM):
|
||||
if not self._ethernet_adapter.get_nio(0):
|
||||
raise VPCSError("This VPCS instance must be connected in order to start")
|
||||
|
||||
self._command = self._build_command()
|
||||
command = self._build_command()
|
||||
try:
|
||||
log.info("Starting VPCS: {}".format(self._command))
|
||||
log.info("Starting VPCS: {}".format(command))
|
||||
self._vpcs_stdout_file = os.path.join(self.working_dir, "vpcs.log")
|
||||
log.info("Logging to {}".format(self._vpcs_stdout_file))
|
||||
flags = 0
|
||||
if sys.platform.startswith("win32"):
|
||||
flags = subprocess.CREATE_NEW_PROCESS_GROUP
|
||||
with open(self._vpcs_stdout_file, "w", encoding="utf-8") as fd:
|
||||
self._process = yield from asyncio.create_subprocess_exec(*self._command,
|
||||
self.command_line = ' '.join(command)
|
||||
self._process = yield from asyncio.create_subprocess_exec(*command,
|
||||
stdout=fd,
|
||||
stderr=subprocess.STDOUT,
|
||||
cwd=self.working_dir,
|
||||
|
@ -254,11 +254,16 @@ IOU_OBJECT_SCHEMA = {
|
||||
"iourc_path": {
|
||||
"description": "Path of the iourc file used by remote servers",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"command_line": {
|
||||
"description": "Last command line used by GNS3 to start QEMU",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name", "vm_id", "console", "project_id", "path", "md5sum", "serial_adapters", "ethernet_adapters",
|
||||
"ram", "nvram", "l1_keepalives", "startup_config", "private_config", "use_default_iou_values"]
|
||||
"ram", "nvram", "l1_keepalives", "startup_config", "private_config", "use_default_iou_values",
|
||||
"command_line"]
|
||||
}
|
||||
|
||||
IOU_CAPTURE_SCHEMA = {
|
||||
|
@ -558,6 +558,10 @@ QEMU_OBJECT_SCHEMA = {
|
||||
"description": "Additional QEMU options",
|
||||
"type": "string",
|
||||
},
|
||||
"command_line": {
|
||||
"description": "Last command line used by GNS3 to start QEMU",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["vm_id",
|
||||
@ -598,7 +602,8 @@ QEMU_OBJECT_SCHEMA = {
|
||||
"cpu_throttling",
|
||||
"process_priority",
|
||||
"options",
|
||||
"vm_directory"]
|
||||
"vm_directory",
|
||||
"command_line"]
|
||||
}
|
||||
|
||||
QEMU_BINARY_FILTER_SCHEMA = {
|
||||
|
@ -121,7 +121,11 @@ VPCS_OBJECT_SCHEMA = {
|
||||
"description": "Path of the VPCS startup script relative to project directory",
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"command_line": {
|
||||
"description": "Last command line used by GNS3 to start QEMU",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name", "vm_id", "status", "console", "project_id", "startup_script_path"]
|
||||
"required": ["name", "vm_id", "status", "console", "project_id", "startup_script_path", "command_line"]
|
||||
}
|
||||
|
@ -61,20 +61,20 @@ class Query:
|
||||
body = json.dumps(body)
|
||||
|
||||
@asyncio.coroutine
|
||||
def go(future):
|
||||
def go_request(future):
|
||||
response = yield from aiohttp.request(method, self.get_url(path, api_version), data=body)
|
||||
future.set_result(response)
|
||||
future = asyncio.Future()
|
||||
asyncio.async(go(future))
|
||||
asyncio.async(go_request(future))
|
||||
self._loop.run_until_complete(future)
|
||||
response = future.result()
|
||||
|
||||
@asyncio.coroutine
|
||||
def go(future, response):
|
||||
def go_read(future, response):
|
||||
response = yield from response.read()
|
||||
future.set_result(response)
|
||||
future = asyncio.Future()
|
||||
asyncio.async(go(future, response))
|
||||
asyncio.async(go_read(future, response))
|
||||
self._loop.run_until_complete(future)
|
||||
response.body = future.result()
|
||||
x_route = response.headers.get('X-Route', None)
|
||||
|
@ -139,7 +139,8 @@ def test_iou_start(server, vm):
|
||||
with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM.start", return_value=True) as mock:
|
||||
response = server.post("/projects/{project_id}/iou/vms/{vm_id}/start".format(project_id=vm["project_id"], vm_id=vm["vm_id"]))
|
||||
assert mock.called
|
||||
assert response.status == 204
|
||||
assert response.status == 200
|
||||
assert response.json["name"] == "PC TEST 1"
|
||||
|
||||
|
||||
def test_iou_start_with_iourc(server, vm, tmpdir):
|
||||
@ -148,7 +149,7 @@ def test_iou_start_with_iourc(server, vm, tmpdir):
|
||||
with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM.start", return_value=True) as mock:
|
||||
response = server.post("/projects/{project_id}/iou/vms/{vm_id}/start".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), body=body, example=True)
|
||||
assert mock.called
|
||||
assert response.status == 204
|
||||
assert response.status == 200
|
||||
|
||||
response = server.get("/projects/{project_id}/iou/vms/{vm_id}".format(project_id=vm["project_id"], vm_id=vm["vm_id"]))
|
||||
assert response.status == 200
|
||||
|
@ -114,7 +114,8 @@ def test_qemu_start(server, vm):
|
||||
with asyncio_patch("gns3server.modules.qemu.qemu_vm.QemuVM.start", return_value=True) as mock:
|
||||
response = server.post("/projects/{project_id}/qemu/vms/{vm_id}/start".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), example=True)
|
||||
assert mock.called
|
||||
assert response.status == 204
|
||||
assert response.status == 200
|
||||
assert response.json["name"] == "PC TEST 1"
|
||||
|
||||
|
||||
def test_qemu_stop(server, vm):
|
||||
|
@ -102,7 +102,8 @@ def test_vpcs_start(server, vm):
|
||||
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM.start", return_value=True) as mock:
|
||||
response = server.post("/projects/{project_id}/vpcs/vms/{vm_id}/start".format(project_id=vm["project_id"], vm_id=vm["vm_id"]), example=True)
|
||||
assert mock.called
|
||||
assert response.status == 204
|
||||
assert response.status == 200
|
||||
assert response.json["name"] == "PC TEST 1"
|
||||
|
||||
|
||||
def test_vpcs_stop(server, vm):
|
||||
|
@ -112,11 +112,11 @@ def test_start(loop, vm, monkeypatch):
|
||||
with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._check_iou_licence", return_value=True):
|
||||
with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_ioucon", return_value=True):
|
||||
with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_iouyap", return_value=True):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process) as mock_exec:
|
||||
mock_process.returncode = None
|
||||
loop.run_until_complete(asyncio.async(vm.start()))
|
||||
assert vm.is_running()
|
||||
|
||||
assert vm.command_line == ' '.join(mock_exec.call_args[0])
|
||||
|
||||
def test_start_with_iourc(loop, vm, monkeypatch, tmpdir):
|
||||
|
||||
|
@ -50,7 +50,7 @@ def test_get_qemu_version(loop):
|
||||
|
||||
def test_binary_list(loop):
|
||||
|
||||
files_to_create = ["qemu-system-x86", "qemu-system-x42", "qemu-kvm", "hello"]
|
||||
files_to_create = ["qemu-system-x86", "qemu-system-x42", "qemu-kvm", "hello", "qemu-system-x86_64-spice"]
|
||||
|
||||
for file_to_create in files_to_create:
|
||||
path = os.path.join(os.environ["PATH"], file_to_create)
|
||||
@ -70,6 +70,7 @@ def test_binary_list(loop):
|
||||
assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} in qemus
|
||||
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x42"), "version": version} in qemus
|
||||
assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus
|
||||
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86_64-spice"), "version": version} not in qemus
|
||||
|
||||
qemus = loop.run_until_complete(asyncio.async(Qemu.binary_list(["x86"])))
|
||||
|
||||
|
@ -112,9 +112,10 @@ def test_is_running(vm, running_subprocess_mock):
|
||||
|
||||
|
||||
def test_start(loop, vm, running_subprocess_mock):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=running_subprocess_mock):
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=running_subprocess_mock) as mock:
|
||||
loop.run_until_complete(asyncio.async(vm.start()))
|
||||
assert vm.is_running()
|
||||
assert vm.command_line == ' '.join(mock.call_args[0])
|
||||
|
||||
|
||||
def test_stop(loop, vm, running_subprocess_mock):
|
||||
|
@ -42,7 +42,7 @@ def test_reserve_tcp_port_outside_range():
|
||||
assert mock_emit.call_args[0][0] == "log.warning"
|
||||
|
||||
|
||||
def test_reserve_tcp_port_already_used():
|
||||
def test_reserve_tcp_port_already_used_by_another_program():
|
||||
"""
|
||||
This test simulate a scenario where the port is already taken
|
||||
by another programm on the server
|
||||
@ -65,6 +65,7 @@ def test_reserve_tcp_port_already_used():
|
||||
assert port != 2001
|
||||
assert mock_emit.call_args[0][0] == "log.warning"
|
||||
|
||||
|
||||
def test_reserve_tcp_port_already_used():
|
||||
"""
|
||||
This test simulate a scenario where the port is already taken
|
||||
|
@ -102,6 +102,13 @@ def test_changing_path_not_allowed(tmpdir):
|
||||
p.path = str(tmpdir)
|
||||
|
||||
|
||||
def test_changing_path_with_quote_not_allowed(tmpdir):
|
||||
with patch("gns3server.modules.project.Project.is_local", return_value=True):
|
||||
with pytest.raises(aiohttp.web.HTTPForbidden):
|
||||
p = Project()
|
||||
p.path = str(tmpdir / "project\"53")
|
||||
|
||||
|
||||
def test_json(tmpdir):
|
||||
p = Project()
|
||||
assert p.__json__() == {"name": p.name, "location": p.location, "path": p.path, "project_id": p.id, "temporary": False}
|
||||
|
@ -107,6 +107,7 @@ def test_start(loop, vm):
|
||||
'-t',
|
||||
'127.0.0.1')
|
||||
assert vm.is_running()
|
||||
assert vm.command_line == ' '.join(mock_exec.call_args[0])
|
||||
(action, event) = queue.get_nowait()
|
||||
assert action == "vm.started"
|
||||
assert event == vm
|
||||
|
Loading…
Reference in New Issue
Block a user