mirror of
https://github.com/GNS3/gns3-server.git
synced 2025-01-18 15:33:49 +02:00
Merge branch 'master' into dev
This commit is contained in:
commit
00f49e337d
@ -73,8 +73,8 @@ import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
ADAPTER_MATRIX = {"C7200_IO_2FE": C7200_IO_2FE,
|
||||
"C7200_IO_FE": C7200_IO_FE,
|
||||
ADAPTER_MATRIX = {"C7200-IO-2FE": C7200_IO_2FE,
|
||||
"C7200-IO-FE": C7200_IO_FE,
|
||||
"C7200-IO-GE-E": C7200_IO_GE_E,
|
||||
"NM-16ESW": NM_16ESW,
|
||||
"NM-1E": NM_1E,
|
||||
@ -468,7 +468,7 @@ class VM(object):
|
||||
except DynamipsError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
elif name.startswith("slot") and value == None:
|
||||
elif name.startswith("slot") and value is None:
|
||||
slot_id = int(name[-1])
|
||||
if router.slots[slot_id]:
|
||||
try:
|
||||
|
@ -212,7 +212,7 @@ class Hypervisor(DynamipsHypervisor):
|
||||
cwd=self._working_dir)
|
||||
log.info("Dynamips started PID={}".format(self._process.pid))
|
||||
self._started = True
|
||||
except OSError as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
log.error("could not start Dynamips: {}".format(e))
|
||||
raise DynamipsError("could not start Dynamips: {}".format(e))
|
||||
|
||||
|
@ -22,7 +22,7 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L294
|
||||
|
||||
from ..dynamips_error import DynamipsError
|
||||
from .router import Router
|
||||
from ..adapters.c7200_io_2fe import C7200_IO_2FE
|
||||
from ..adapters.c7200_io_fe import C7200_IO_FE
|
||||
from ..adapters.c7200_io_ge_e import C7200_IO_GE_E
|
||||
|
||||
import logging
|
||||
@ -70,7 +70,7 @@ class C7200(Router):
|
||||
if npe == "npe-g2":
|
||||
self.slot_add_binding(0, C7200_IO_GE_E())
|
||||
else:
|
||||
self.slot_add_binding(0, C7200_IO_2FE())
|
||||
self.slot_add_binding(0, C7200_IO_FE())
|
||||
|
||||
def defaults(self):
|
||||
"""
|
||||
|
@ -1324,7 +1324,7 @@ class Router(object):
|
||||
adapter=current_adapter))
|
||||
|
||||
# Only c7200, c3600 and c3745 (NM-4T only) support new adapter while running
|
||||
if self.is_running() and not (self._platform == 'c7200'
|
||||
if self.is_running() and not ((self._platform == 'c7200' and not str(adapter).startswith('C7200'))
|
||||
and not (self._platform == 'c3600' and self.chassis == '3660')
|
||||
and not (self._platform == 'c3745' and adapter == 'NM-4T')):
|
||||
raise DynamipsError("Adapter {adapter} cannot be added while router {name} is running".format(adapter=adapter,
|
||||
@ -1369,7 +1369,7 @@ class Router(object):
|
||||
slot_id=slot_id))
|
||||
|
||||
# Only c7200, c3600 and c3745 (NM-4T only) support to remove adapter while running
|
||||
if self.is_running() and not (self._platform == 'c7200'
|
||||
if self.is_running() and not ((self._platform == 'c7200' and not str(adapter).startswith('C7200'))
|
||||
and not (self._platform == 'c3600' and self.chassis == '3660')
|
||||
and not (self._platform == 'c3745' and adapter == 'NM-4T')):
|
||||
raise DynamipsError("Adapter {adapter} cannot be removed while router {name} is running".format(adapter=adapter,
|
||||
|
@ -509,7 +509,7 @@ class IOUDevice(object):
|
||||
cwd=self._working_dir)
|
||||
|
||||
log.info("iouyap started PID={}".format(self._iouyap_process.pid))
|
||||
except OSError as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
iouyap_stdout = self.read_iouyap_stdout()
|
||||
log.error("could not start iouyap: {}\n{}".format(e, iouyap_stdout))
|
||||
raise IOUError("Could not start iouyap: {}\n{}".format(e, iouyap_stdout))
|
||||
@ -521,7 +521,7 @@ class IOUDevice(object):
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(["ldd", self._path])
|
||||
except (FileNotFoundError, subprocess.CalledProcessError) as e:
|
||||
except (FileNotFoundError, subprocess.SubprocessError) as e:
|
||||
log.warn("could not determine the shared library dependencies for {}: {}".format(self._path, e))
|
||||
return
|
||||
|
||||
@ -583,7 +583,7 @@ class IOUDevice(object):
|
||||
self._started = True
|
||||
except FileNotFoundError as e:
|
||||
raise IOUError("could not start IOU: {}: 32-bit binary support is probably not installed".format(e))
|
||||
except OSError as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
iou_stdout = self.read_iou_stdout()
|
||||
log.error("could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))
|
||||
raise IOUError("could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))
|
||||
@ -761,7 +761,7 @@ class IOUDevice(object):
|
||||
command.extend(["-l"])
|
||||
else:
|
||||
raise IOUError("layer 1 keepalive messages are not supported by {}".format(os.path.basename(self._path)))
|
||||
except (OSError, subprocess.CalledProcessError) as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
log.warn("could not determine if layer 1 keepalive messages are supported by {}: {}".format(os.path.basename(self._path), e))
|
||||
|
||||
def _build_command(self):
|
||||
|
@ -601,14 +601,14 @@ class Qemu(IModule):
|
||||
if sys.platform.startswith("win"):
|
||||
return ""
|
||||
try:
|
||||
output = subprocess.check_output([qemu_path, "--version"])
|
||||
match = re.search("QEMU emulator version ([0-9a-z\-\.]+)", output.decode("utf-8"))
|
||||
output = subprocess.check_output([qemu_path, "-version"])
|
||||
match = re.search("version\s+([0-9a-z\-\.]+)", output.decode("utf-8"))
|
||||
if match:
|
||||
version = match.group(1)
|
||||
return version
|
||||
else:
|
||||
raise QemuError("Could not determine the Qemu version for {}".format(qemu_path))
|
||||
except (OSError, subprocess.CalledProcessError) as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
raise QemuError("Error while looking for the Qemu version: {}".format(e))
|
||||
|
||||
@IModule.route("qemu.qemu_list")
|
||||
@ -625,7 +625,13 @@ class Qemu(IModule):
|
||||
# look for Qemu binaries in the current working directory and $PATH
|
||||
if sys.platform.startswith("win"):
|
||||
# add specific Windows paths
|
||||
paths.append(os.path.join(os.getcwd(), "qemu"))
|
||||
if hasattr(sys, "frozen"):
|
||||
# add any qemu dir in the same location as gns3server.exe to the list of paths
|
||||
exec_dir = os.path.dirname(os.path.abspath(sys.executable))
|
||||
for f in os.listdir(exec_dir):
|
||||
if f.lower().startswith("qemu"):
|
||||
paths.append(os.path.join(exec_dir, f))
|
||||
|
||||
if "PROGRAMFILES(X86)" in os.environ and os.path.exists(os.environ["PROGRAMFILES(X86)"]):
|
||||
paths.append(os.path.join(os.environ["PROGRAMFILES(X86)"], "qemu"))
|
||||
if "PROGRAMFILES" in os.environ and os.path.exists(os.environ["PROGRAMFILES"]):
|
||||
@ -633,15 +639,18 @@ class Qemu(IModule):
|
||||
elif sys.platform.startswith("darwin"):
|
||||
# add specific locations on Mac OS X regardless of what's in $PATH
|
||||
paths.extend(["/usr/local/bin", "/opt/local/bin"])
|
||||
if hasattr(sys, "frozen"):
|
||||
paths.append(os.path.abspath(os.path.join(os.getcwd(), "../../../qemu/bin/")))
|
||||
for path in paths:
|
||||
try:
|
||||
for f in os.listdir(path):
|
||||
if (f.startswith("qemu-system") or f == "qemu" or f == "qemu.exe") and os.access(os.path.join(path, f), os.X_OK):
|
||||
if (f.startswith("qemu-system") 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)):
|
||||
qemu_path = os.path.join(path, f)
|
||||
version = self._get_qemu_version(qemu_path)
|
||||
qemus.append({"path": qemu_path, "version": version})
|
||||
except (OSError, QemuError) as e:
|
||||
log.warn("Could not find QEMU version for {}: {}".format(path, e))
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
response = {"qemus": qemus}
|
||||
|
@ -19,6 +19,7 @@
|
||||
QEMU VM instance.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import random
|
||||
@ -89,6 +90,7 @@ class QemuVM(object):
|
||||
self._command = []
|
||||
self._started = False
|
||||
self._process = None
|
||||
self._cpulimit_process = None
|
||||
self._stdout_file = ""
|
||||
self._console_host = console_host
|
||||
self._console_start_port_range = console_start_port_range
|
||||
@ -107,6 +109,9 @@ class QemuVM(object):
|
||||
self._initrd = ""
|
||||
self._kernel_image = ""
|
||||
self._kernel_command_line = ""
|
||||
self._legacy_networking = False
|
||||
self._cpu_throttling = 0 # means no CPU throttling
|
||||
self._process_priority = "low"
|
||||
|
||||
working_dir_path = os.path.join(working_dir, "qemu", "vm-{}".format(self._id))
|
||||
|
||||
@ -152,7 +157,11 @@ class QemuVM(object):
|
||||
"console": self._console,
|
||||
"initrd": self._initrd,
|
||||
"kernel_image": self._kernel_image,
|
||||
"kernel_command_line": self._kernel_command_line}
|
||||
"kernel_command_line": self._kernel_command_line,
|
||||
"legacy_networking": self._legacy_networking,
|
||||
"cpu_throttling": self._cpu_throttling,
|
||||
"process_priority": self._process_priority
|
||||
}
|
||||
|
||||
return qemu_defaults
|
||||
|
||||
@ -437,6 +446,80 @@ class QemuVM(object):
|
||||
id=self._id,
|
||||
adapter_type=adapter_type))
|
||||
|
||||
@property
|
||||
def legacy_networking(self):
|
||||
"""
|
||||
Returns either QEMU legacy networking commands are used.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
return self._legacy_networking
|
||||
|
||||
@legacy_networking.setter
|
||||
def legacy_networking(self, legacy_networking):
|
||||
"""
|
||||
Sets either QEMU legacy networking commands are used.
|
||||
|
||||
:param legacy_networking: boolean
|
||||
"""
|
||||
|
||||
if legacy_networking:
|
||||
log.info("QEMU VM {name} [id={id}] has enabled legacy networking".format(name=self._name, id=self._id))
|
||||
else:
|
||||
log.info("QEMU VM {name} [id={id}] has disabled legacy networking".format(name=self._name, id=self._id))
|
||||
self._legacy_networking = legacy_networking
|
||||
|
||||
@property
|
||||
def cpu_throttling(self):
|
||||
"""
|
||||
Returns the percentage of CPU allowed.
|
||||
|
||||
:returns: integer
|
||||
"""
|
||||
|
||||
return self._cpu_throttling
|
||||
|
||||
@cpu_throttling.setter
|
||||
def cpu_throttling(self, cpu_throttling):
|
||||
"""
|
||||
Sets the percentage of CPU allowed.
|
||||
|
||||
:param cpu_throttling: integer
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the percentage of CPU allowed to {cpu}".format(name=self._name,
|
||||
id=self._id,
|
||||
cpu=cpu_throttling))
|
||||
self._cpu_throttling = cpu_throttling
|
||||
self._stop_cpulimit()
|
||||
if cpu_throttling:
|
||||
self._set_cpu_throttling()
|
||||
|
||||
@property
|
||||
def process_priority(self):
|
||||
"""
|
||||
Returns the process priority.
|
||||
|
||||
:returns: string
|
||||
"""
|
||||
|
||||
return self._process_priority
|
||||
|
||||
@process_priority.setter
|
||||
def process_priority(self, process_priority):
|
||||
"""
|
||||
Sets the process priority.
|
||||
|
||||
:param process_priority: string
|
||||
"""
|
||||
|
||||
log.info("QEMU VM {name} [id={id}] has set the process priority to {priority}".format(name=self._name,
|
||||
id=self._id,
|
||||
priority=process_priority))
|
||||
self._process_priority = process_priority
|
||||
|
||||
|
||||
@property
|
||||
def ram(self):
|
||||
"""
|
||||
@ -552,6 +635,84 @@ class QemuVM(object):
|
||||
kernel_command_line=kernel_command_line))
|
||||
self._kernel_command_line = kernel_command_line
|
||||
|
||||
def _set_process_priority(self):
|
||||
"""
|
||||
Changes the process priority
|
||||
"""
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
try:
|
||||
import win32api
|
||||
import win32con
|
||||
import win32process
|
||||
except ImportError:
|
||||
log.error("pywin32 must be installed to change the priority class for QEMU VM {}".format(self._name))
|
||||
else:
|
||||
log.info("setting QEMU VM {} priority class to BELOW_NORMAL".format(self._name))
|
||||
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
|
||||
win32process.SetPriorityClass(handle, priority)
|
||||
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:
|
||||
subprocess.call(['renice', '-n', str(priority), '-p', str(self._process.pid)])
|
||||
except subprocess.SubprocessError as e:
|
||||
log.error("could not change process priority for QEMU VM {}: {}".format(self._name, e))
|
||||
|
||||
def _stop_cpulimit(self):
|
||||
"""
|
||||
Stops the cpulimit process.
|
||||
"""
|
||||
|
||||
if self._cpulimit_process and self._cpulimit_process.poll() is None:
|
||||
self._cpulimit_process.kill()
|
||||
try:
|
||||
self._process.wait(3)
|
||||
except subprocess.TimeoutExpired:
|
||||
log.error("could not kill cpulimit process {}".format(self._cpulimit_process.pid))
|
||||
|
||||
def _set_cpu_throttling(self):
|
||||
"""
|
||||
Limits the CPU usage for current QEMU process.
|
||||
"""
|
||||
|
||||
if not self.is_running():
|
||||
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", "--pid={}".format(self._process.pid), "--limit={}".format(self._cpu_throttling)], cwd=self._working_dir)
|
||||
log.info("CPU throttled to {}%".format(self._cpu_throttling))
|
||||
except FileNotFoundError:
|
||||
raise QemuError("cpulimit could not be found, please install it or deactivate CPU throttling")
|
||||
except subprocess.SubprocessError as e:
|
||||
raise QemuError("Could not throttle CPU: {}".format(e))
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starts this QEMU VM.
|
||||
@ -612,11 +773,15 @@ class QemuVM(object):
|
||||
cwd=self._working_dir)
|
||||
log.info("QEMU VM instance {} started PID={}".format(self._id, self._process.pid))
|
||||
self._started = True
|
||||
except OSError as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
stdout = self.read_stdout()
|
||||
log.error("could not start QEMU {}: {}\n{}".format(self._qemu_path, e, stdout))
|
||||
raise QemuError("could not start QEMU {}: {}\n{}".format(self._qemu_path, e, stdout))
|
||||
|
||||
self._set_process_priority()
|
||||
if self._cpu_throttling:
|
||||
self._set_cpu_throttling()
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops this QEMU VM.
|
||||
@ -635,6 +800,7 @@ class QemuVM(object):
|
||||
self._process.pid))
|
||||
self._process = None
|
||||
self._started = False
|
||||
self._stop_cpulimit()
|
||||
|
||||
def suspend(self):
|
||||
"""
|
||||
@ -782,7 +948,7 @@ class QemuVM(object):
|
||||
retcode = subprocess.call([qemu_img_path, "create", "-f", "qcow2", hda_disk, "128M"])
|
||||
log.info("{} returned with {}".format(qemu_img_path, retcode))
|
||||
|
||||
except OSError as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
raise QemuError("Could not create disk image {}".format(e))
|
||||
|
||||
options.extend(["-hda", hda_disk])
|
||||
@ -794,7 +960,7 @@ class QemuVM(object):
|
||||
"backing_file={}".format(self._hdb_disk_image),
|
||||
"-f", "qcow2", hdb_disk])
|
||||
log.info("{} returned with {}".format(qemu_img_path, retcode))
|
||||
except OSError as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
raise QemuError("Could not create disk image {}".format(e))
|
||||
options.extend(["-hdb", hdb_disk])
|
||||
|
||||
@ -819,14 +985,27 @@ class QemuVM(object):
|
||||
for adapter in self._ethernet_adapters:
|
||||
#TODO: let users specify a base mac address
|
||||
mac = "00:00:ab:%02x:%02x:%02d" % (random.randint(0x00, 0xff), random.randint(0x00, 0xff), adapter_id)
|
||||
if self._legacy_networking:
|
||||
network_options.extend(["-net", "nic,vlan={},macaddr={},model={}".format(adapter_id, mac, self._adapter_type)])
|
||||
else:
|
||||
network_options.extend(["-device", "{},mac={},netdev=gns3-{}".format(self._adapter_type, mac, adapter_id)])
|
||||
nio = adapter.get_nio(0)
|
||||
if nio and isinstance(nio, NIO_UDP):
|
||||
if self._legacy_networking:
|
||||
network_options.extend(["-net", "udp,vlan={},sport={},dport={},daddr={}".format(adapter_id,
|
||||
nio.lport,
|
||||
nio.rport,
|
||||
nio.rhost)])
|
||||
|
||||
else:
|
||||
network_options.extend(["-netdev", "socket,id=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_id,
|
||||
nio.rhost,
|
||||
nio.rport,
|
||||
self._host,
|
||||
nio.lport)])
|
||||
else:
|
||||
if self._legacy_networking:
|
||||
network_options.extend(["-net", "user,vlan={}".format(adapter_id)])
|
||||
else:
|
||||
network_options.extend(["-netdev", "user,id=gns3-{}".format(adapter_id)])
|
||||
adapter_id += 1
|
||||
|
@ -124,8 +124,27 @@ QEMU_UPDATE_SCHEMA = {
|
||||
"description": "Path to the image in the cloud object store",
|
||||
"type": "string",
|
||||
},
|
||||
"legacy_networking": {
|
||||
"description": "Use QEMU legagy networking commands (-net syntax)",
|
||||
"type": "boolean",
|
||||
},
|
||||
"cpu_throttling": {
|
||||
"description": "Percentage of CPU allowed for QEMU",
|
||||
"minimum": 0,
|
||||
"maximum": 800,
|
||||
"type": "integer",
|
||||
},
|
||||
"process_priority": {
|
||||
"description": "Process priority for QEMU",
|
||||
"enum": ["realtime",
|
||||
"very high",
|
||||
"high",
|
||||
"normal",
|
||||
"low",
|
||||
"very low"]
|
||||
},
|
||||
"options": {
|
||||
"description": "additional QEMU options",
|
||||
"description": "Additional QEMU options",
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
|
@ -62,8 +62,13 @@ class VirtualBox(IModule):
|
||||
|
||||
# get the vboxmanage location
|
||||
self._vboxmanage_path = None
|
||||
if sys.platform.startswith("win") and "VBOX_INSTALL_PATH" in os.environ:
|
||||
if sys.platform.startswith("win"):
|
||||
if "VBOX_INSTALL_PATH" in os.environ:
|
||||
self._vboxmanage_path = os.path.join(os.environ["VBOX_INSTALL_PATH"], "VBoxManage.exe")
|
||||
elif "VBOX_MSI_INSTALL_PATH" in os.environ:
|
||||
self._vboxmanage_path = os.path.join(os.environ["VBOX_MSI_INSTALL_PATH"], "VBoxManage.exe")
|
||||
elif sys.platform.startswith("darwin"):
|
||||
self._vboxmanage_path = "/Applications/VirtualBox.app/Contents/MacOS/VBoxManage"
|
||||
else:
|
||||
config = Config.instance()
|
||||
vbox_config = config.get_section_config(name.upper())
|
||||
@ -716,12 +721,10 @@ class VirtualBox(IModule):
|
||||
"""
|
||||
|
||||
try:
|
||||
result = subprocess.check_output(command, stderr=subprocess.STDOUT, universal_newlines=True, timeout=30)
|
||||
except subprocess.CalledProcessError as e:
|
||||
result = subprocess.check_output(command, stderr=subprocess.STDOUT, timeout=30)
|
||||
except subprocess.SubprocessError as e:
|
||||
raise VirtualBoxError("Could not execute VBoxManage {}".format(e))
|
||||
except subprocess.TimeoutExpired:
|
||||
raise VirtualBoxError("VBoxManage has timed out")
|
||||
return result
|
||||
return result.decode("utf-8")
|
||||
|
||||
@IModule.route("virtualbox.vm_list")
|
||||
def vm_list(self, request):
|
||||
@ -753,7 +756,13 @@ class VirtualBox(IModule):
|
||||
for line in result.splitlines():
|
||||
vmname, uuid = line.rsplit(' ', 1)
|
||||
vmname = vmname.strip('"')
|
||||
if vmname == "<inaccessible>":
|
||||
continue # ignore inaccessible VMs
|
||||
try:
|
||||
extra_data = self._execute_vboxmanage([vboxmanage_path, "getextradata", vmname, "GNS3/Clone"]).strip()
|
||||
except VirtualBoxError as e:
|
||||
self.send_custom_error(str(e))
|
||||
return
|
||||
if not extra_data == "Value: yes":
|
||||
vms.append(vmname)
|
||||
|
||||
|
@ -322,8 +322,8 @@ class VirtualBoxVM(object):
|
||||
self._allocated_console_ports.remove(self.console)
|
||||
|
||||
if self._linked_clone:
|
||||
if os.path.exists(self._working_dir):
|
||||
hdd_table = []
|
||||
if os.path.exists(self._working_dir):
|
||||
hdd_files = self._get_all_hdd_files()
|
||||
vm_info = self._get_vm_info()
|
||||
for entry, value in vm_info.items():
|
||||
@ -550,17 +550,17 @@ class VirtualBoxVM(object):
|
||||
command.extend(args)
|
||||
log.debug("Execute vboxmanage command: {}".format(command))
|
||||
try:
|
||||
result = subprocess.check_output(command, stderr=subprocess.STDOUT, universal_newlines=True, timeout=timeout)
|
||||
result = subprocess.check_output(command, stderr=subprocess.STDOUT, timeout=timeout)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if e.output:
|
||||
# only the first line of the output is useful
|
||||
virtualbox_error = e.output.splitlines()[0]
|
||||
virtualbox_error = e.output.decode("utf-8").splitlines()[0]
|
||||
raise VirtualBoxError("{}".format(virtualbox_error))
|
||||
else:
|
||||
raise VirtualBoxError("{}".format(e))
|
||||
except subprocess.TimeoutExpired:
|
||||
raise VirtualBoxError("VBoxManage has timed out")
|
||||
return result.splitlines()
|
||||
except subprocess.SubprocessError as e:
|
||||
raise VirtualBoxError("Could not execute VBoxManage: {}".format(e))
|
||||
return result.decode("utf-8").splitlines()
|
||||
|
||||
def _get_vm_info(self):
|
||||
"""
|
||||
|
@ -346,7 +346,7 @@ class VPCSDevice(object):
|
||||
raise VPCSError("VPCS executable version must be >= 0.5b1")
|
||||
else:
|
||||
raise VPCSError("Could not determine the VPCS version for {}".format(self._path))
|
||||
except (OSError, subprocess.CalledProcessError) as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
raise VPCSError("Error while looking for the VPCS version: {}".format(e))
|
||||
|
||||
def start(self):
|
||||
@ -386,7 +386,7 @@ class VPCSDevice(object):
|
||||
creationflags=flags)
|
||||
log.info("VPCS instance {} started PID={}".format(self._id, self._process.pid))
|
||||
self._started = True
|
||||
except OSError as e:
|
||||
except subprocess.SubprocessError as e:
|
||||
vpcs_stdout = self.read_vpcs_stdout()
|
||||
log.error("could not start VPCS {}: {}\n{}".format(self._path, e, vpcs_stdout))
|
||||
raise VPCSError("could not start VPCS {}: {}\n{}".format(self._path, e, vpcs_stdout))
|
||||
|
@ -184,7 +184,6 @@ class Server(object):
|
||||
except KeyError:
|
||||
log.info("Missing cloud.conf - disabling HTTP auth and SSL")
|
||||
|
||||
|
||||
router = self._create_zmq_router()
|
||||
# Add our JSON-RPC Websocket handler to Tornado
|
||||
self.handlers.extend([(r"/", JSONRPCWebSocket, dict(zmq_router=router))])
|
||||
@ -208,6 +207,7 @@ class Server(object):
|
||||
|
||||
if parse_version(tornado.version) >= parse_version("3.1"):
|
||||
kwargs["max_buffer_size"] = 524288000 # 500 MB file upload limit
|
||||
|
||||
tornado_app.listen(self._port, **kwargs)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EADDRINUSE: # socket already in use
|
||||
|
@ -23,5 +23,5 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "1.2.dev3"
|
||||
__version_info__ = (1, 2, 0, 99)
|
||||
__version__ = "1.2.2.dev1"
|
||||
__version_info__ = (1, 2, 2, 0)
|
||||
|
46
scripts/ws_client.py
Normal file
46
scripts/ws_client.py
Normal file
@ -0,0 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ws4py.client.threadedclient import WebSocketClient
|
||||
|
||||
|
||||
class WSClient(WebSocketClient):
|
||||
|
||||
def opened(self):
|
||||
|
||||
print("Connection successful with {}:{}".format(self.host, self.port))
|
||||
|
||||
self.send('{"jsonrpc": 2.0, "method": "dynamips.settings", "params": {"path": "/usr/local/bin/dynamips", "allocate_hypervisor_per_device": true, "working_dir": "/tmp/gns3-1b4grwm3-files", "udp_end_port_range": 20000, "sparse_memory_support": true, "allocate_hypervisor_per_ios_image": true, "aux_start_port_range": 2501, "use_local_server": true, "hypervisor_end_port_range": 7700, "aux_end_port_range": 3000, "mmap_support": true, "console_start_port_range": 2001, "console_end_port_range": 2500, "hypervisor_start_port_range": 7200, "ghost_ios_support": true, "memory_usage_limit_per_hypervisor": 1024, "jit_sharing_support": false, "udp_start_port_range": 10001}}')
|
||||
self.send('{"jsonrpc": 2.0, "method": "dynamips.vm.create", "id": "e8caf5be-de3d-40dd-80b9-ab6df8029570", "params": {"image": "/home/grossmj/GNS3/images/IOS/c3725-advipservicesk9-mz.124-15.T14.image", "name": "R1", "platform": "c3725", "ram": 256}}')
|
||||
|
||||
def closed(self, code, reason=None):
|
||||
|
||||
print("Closed down. Code: {} Reason: {}".format(code, reason))
|
||||
|
||||
def received_message(self, m):
|
||||
|
||||
print(m)
|
||||
if len(m) == 175:
|
||||
self.close(reason='Bye bye')
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
ws = WSClient('ws://localhost:8000/', protocols=['http-only', 'chat'])
|
||||
ws.connect()
|
||||
ws.run_forever()
|
||||
except KeyboardInterrupt:
|
||||
ws.close()
|
Loading…
Reference in New Issue
Block a user