Compare commits

...
47 Commits
Author SHA1 Message Date
Julien Duponchelle 838680cb40 1.5.4 2017-04-13 17:30:25 +02:00
Julien Duponchelle 85136bc2e4 Fix VPCS tests for recent version 2017-04-13 15:56:12 +02:00
Julien Duponchelle 6d150bb62c Freeze server dependencies to the same version used for 1.5.3 2017-04-13 14:45:27 +02:00
Bernhard Ehlers 3afe85ba3c Fix 1.5: Error message, when stopping IOU router #769
Signed-off-by: Julien Duponchelle <julien@gns3.net>
2017-04-13 14:25:40 +02:00
Julien Duponchelle 57ba7ab801 Fix crash in some tests 2017-04-13 14:24:26 +02:00
Julien Duponchelle b755840a27 Add security issues section 2017-04-13 12:38:16 +02:00
Julien Duponchelle a8294c3de8 Backport requirements of 2.0 2017-04-13 10:22:20 +02:00
Julien Duponchelle 878aee6e90 Correct version number 2017-04-13 09:55:22 +02:00
Julien Duponchelle fea77398e7 Publish on PyPi when we tag 2017-03-10 20:33:17 +01:00
Julien Duponchelle b909ec978f Drop color logging for remote install, seem to fail in some conditions 2017-03-09 19:09:56 +01:00
Julien Duponchelle cb338d9583 Cleanup the remote install script 2017-03-08 18:15:43 +01:00
Julien Duponchelle bb45ff0d9a Support for Xenial in remote install
Fix #923
2017-03-08 15:58:28 +01:00
Julien Duponchelle e7a88a7d99 Force the dependency on typing because otherwise it's broke on 3.4 2017-01-19 10:27:32 +01:00
Julien Duponchelle e63171c2c2 1.5.3dev1 2017-01-12 09:07:06 +01:00
Julien Duponchelle 19c4ec1867 1.5.3 2017-01-12 08:18:46 +01:00
Bernhard Ehlers 8019374ed0 Fix sporadically systemd is unable to start gns3-server
Signed-off-by: Julien Duponchelle <julien@gns3.net>
2017-01-09 10:28:21 +01:00
Julien Duponchelle af530be346 1.5.3dev2 2016-12-20 11:48:55 +01:00
Julien Duponchelle 9c3cfc4f4e 1.5.3 rc1 2016-12-20 09:30:52 +01:00
Julien Duponchelle c7d878ed9e Fix TypeError: __init__() got multiple values for argument 'handler' with recent aiohttp
Fix #841
2016-12-20 09:21:02 +01:00
Julien Duponchelle 49f1ee2e32 Support aiohttp 1.2 (but not compatible with previous versions)
Fix #840
2016-12-20 09:17:45 +01:00
Julien Duponchelle bd4de862c8 Explain that segfault on IOU is a issue with the image
Fix #739
2016-10-28 11:25:14 +02:00
Julien Duponchelle f038735595 Fix an issue with finding vmrun and vboxmanage
Ref #1575
2016-10-19 17:44:55 +02:00
Julien Duponchelle a4f8675c93 Support named remote servers for VPCS
Fix #722
2016-10-19 16:55:33 +02:00
Jeremy Grossmann da71f29208 Merge pull request #726 from GNS3/port_check
When checking for a free port check if the host and 0.0.0.0 are available
2016-10-18 21:02:28 -06:00
Julien Duponchelle b53b34d485 When checking for a free port check if the host and 0.0.0.0 are available
Because some emulators will listen on 0.0.0.0 and not on the host.

Fix #721
2016-10-18 09:59:31 +02:00
Julien Duponchelle e63da227d0 Try pyup.io 2016-10-17 10:27:35 +02:00
Julien Duponchelle c7d9af121f smm=off is only for 64bits
Fix #714
2016-10-04 14:53:09 +02:00
Julien Duponchelle 15babb137d Fix set hostname on remote server
Fix #691
2016-09-27 10:40:58 +02:00
Julien Duponchelle eccee6b629 Support unstable ppa for remote install 2016-09-27 10:35:24 +02:00
Julien Duponchelle ef95ba1ed8 Fix sending smm option to qemu
Fix #689
2016-09-26 15:15:38 +02:00
Julien Duponchelle 2bbdbeaa82 Workaround a bug with KVM, Qemu >= 2.4 and Intel CPU
Fix #685
2016-09-21 19:25:15 +02:00
Julien Duponchelle de2dad20d5 Renable sleep at Vbox exit bug seem to be back
Fix https://github.com/GNS3/gns3-gui/issues/1444
2016-09-08 18:37:34 +02:00
Julien Duponchelle 84c0a17572 Support large project (> 2GB) during export
Fix #670
2016-09-08 11:41:12 +02:00
Julien Duponchelle f0edf799b7 Fix Deleting running telnet docker VM shows error in log
Fix #662
2016-09-07 14:24:56 +02:00
Julien Duponchelle a7be4681d5 Create gns3server/symbols directory
This directory is use only in 2.0 but to simplify packaging
we create it in 1.5.
2016-09-06 09:45:29 +02:00
Bernhard Ehlers 07b982d4db Fix when closing a container using VNC, root permission are not reset
Fix #659

Signed-off-by: Julien Duponchelle <julien@gns3.net>
2016-09-01 09:28:22 +02:00
Julien Duponchelle da1cd9a3e7 Use $PATH also for dynamips and cleanup some $PATH usages
Fix #655
2016-08-29 11:27:35 +02:00
Julien Duponchelle 0eafb6f06c Fix a lock issue with some virtualbox vm
Fix  https://github.com/GNS3/gns3-gui/issues/1444
2016-08-29 10:51:50 +02:00
Julien Duponchelle 042a69eecf Raise proper error when you try to load an empty qcow2 file
Fix #637
2016-08-29 10:18:18 +02:00
Julien Duponchelle 1885fe62a6 Fix upload form crash
Fix #647
2016-08-29 09:25:02 +02:00
Julien Duponchelle e481ffa94c Search bin from the $PATH for sample configuration file 2016-08-27 18:10:41 +02:00
Julien Duponchelle 937bbf0131 Merge pull request #653 from ehlers/master
Update 'Updated systemd unit file and added sample configuration file'
2016-08-27 18:09:35 +02:00
Bernhard Ehlers d58a6ccda9 Update 'Updated systemd unit file and added sample configuration file' 2016-08-27 02:00:26 +02:00
Bernhard Ehlers 84fb108abb Change CR/LF line ending to unix style 2016-08-26 18:45:22 +02:00
Julien Duponchelle 4455499e00 Merge pull request #648 from ianc1215/master
Updated systemd unit file and added sample configuration file
2016-08-26 09:28:40 +02:00
Ian Campbell 763f258465 Updated systemd unit file and added sample configuration file
Rewrote the systemd unit file to fix an issue where the system was not able to create a PID file inside /var/run.

I fixed this by having systemd create a new directory called /var/run/gns3. Then I had systemd change ownership of the directory to gns3:gns3 so the gns3server executable could read and write the PID file. I have tested these changes against Ubuntu 16.04.1 LTS.
2016-08-25 19:24:09 -04:00
Julien Duponchelle d447a04c6a 1.5.3dev1 2016-08-18 22:16:01 +02:00
33 changed files with 423 additions and 126 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
branch:
2.0
+11 -3
View File
@@ -1,6 +1,8 @@
language: python
python:
- '3.4'
- '3.5'
- '3.6'
sudo: false
cache: pip
install:
@@ -8,6 +10,12 @@ install:
- pip install -rdev-requirements.txt
- pip install coveralls
script:
- py.test -v -s tests --cov gns3server --cov-report term-missing
after_success:
- coveralls
- py.test -v -s tests
deploy:
provider: pypi
user: noplay
password:
secure: Fa66zp8ML4oSGwzkUMZi07MIYfO3tbS5gHFUaLN2mk2MBknhCjDYexmFJqT//sC/+xqv6sSJE6rz1EPoy/THbxj8R96ZgIyiUZIbDCbzgdy92d7J/eusrDoNdpApBLke8NqQqtFETb3addMZZNofQ3IDANFD2m2jY+KECU8z8NI=
on:
tags: true
repo: GNS3/gns3-server
+35
View File
@@ -1,5 +1,40 @@
# Change Log
## 1.5.4 13/04/2017
* Fix VPCS tests for recent version
* Freeze server dependencies to the same version used for 1.5.3
* Fix 1.5: Error message, when stopping IOU router #769
* Drop color logging for remote install, seem to fail in some conditions
* Cleanup the remote install script
* Support for Xenial in remote install
## 1.5.3 12/01/2016
* Fix sporadically systemd is unable to start gns3-server
## 1.5.3 rc1 20/12/2016
* Support aiohttp 1.2 (but not compatible with previous versions)
* Explain that segfault on IOU is a issue with the image
* Fix an issue with finding vmrun and vboxmanage
* Support named remote servers for VPCS
* When checking for a free port check if the host and 0.0.0.0 are available
* smm=off is only for 64bits
* Fix set hostname on remote server
* Fix sending smm option to qemu
* Workaround a bug with KVM, Qemu >= 2.4 and Intel CPU
* Renable sleep at Vbox exit bug seem to be back
* Support large project (> 2GB) during export
* Fix Deleting running telnet docker VM shows error in log
* Fix when closing a container using VNC, root permission are not reset
* Use $PATH also for dynamips and cleanup some $PATH usages
* Fix a lock issue with some virtualbox vm
* Raise proper error when you try to load an empty qcow2 file
* Fix upload form crash
* Search bin from the $PATH for sample configuration file
* Updated systemd unit file and added sample configuration file
## 1.5.2 18/08/2016
* Move utils.vmnet to gns3 namespace
+5
View File
@@ -206,3 +206,8 @@ If you want test coverage:
.. code:: bash
py.test --cov-report term-missing --cov=gns3server
Security issues
----------------
Please contact us using contact informations available here:
http://docs.gns3.com/1ON9JBXSeR7Nt2-Qum2o3ZX0GU86BZwlmNSUgvmqNWGY/index.html
+61
View File
@@ -0,0 +1,61 @@
[Server]
; IP where the server listen for connections
host = 0.0.0.0
; HTTP port for controlling the servers
port = 3080
; Option to enable SSL encryption
ssl = False
certfile=/home/gns3/.config/GNS3/ssl/server.cert
certkey=/home/gns3/.config/GNS3/ssl/server.key
; Path where devices images are stored
images_path = /home/gns3/GNS3/images
; Path where user projects are stored
projects_path = /home/gns3/GNS3/projects
; Option to automatically send crash reports to the GNS3 team
report_errors = True
; First console port of the range allocated to devices
console_start_port_range = 5000
; Last console port of the range allocated to devices
console_end_port_range = 10000
; First port of the range allocated for inter-device communication. Two ports are allocated per link.
udp_start_port_range = 10000
; Last port of the range allocated for inter-device communication. Two ports are allocated per link
udp_start_end_range = 20000
; uBridge executable location, default: search in PATH
;ubridge_path = ubridge
; Option to enable HTTP authentication.
auth = False
; Username for HTTP authentication.
user = gns3
; Password for HTTP authentication.
password = gns3
[VPCS]
; VPCS executable location, default: search in PATH
;vpcs_path = vpcs
[Dynamips]
; Enable auxiliary console ports on IOS routers
allocate_aux_console_ports = False
mmap_support = True
; Dynamips executable path, default: search in PATH
;dynamips_path = dynamips
sparse_memory_support = True
ghost_ios_support = True
[IOU]
; iouyap executable path, default: search in PATH
;iouyap_path = iouyap
; Path of your .iourc file. If not provided, the file is searched in $HOME/.iourc
iourc_path = /home/gns3/.iourc
; Validate if the iourc license file is correct. If you turn this off and your licence is invalid IOU will not start and no errors will be shown.
license_check = True
[Qemu]
; !! Remember to add the gns3 user to the KVM group, otherwise you will not have read / write permssions to /dev/kvm !!
enable_kvm = True
+1 -1
View File
@@ -52,7 +52,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "sync+https://76659dafd45f4e3f8ca0ae7597eac70b:dc0094ac9ae44fe1beacc1e37b2f6041@app.getsentry.com/38482"
DSN = "sync+https://a50622052018408097c33bb425dcb9bc:55f46ecbe2d04d6e9c3bd8d182bf2990@sentry.io/38482"
if hasattr(sys, "frozen"):
cacert = get_resource("cacert.pem")
if cacert is not None and os.path.isfile(cacert):
+1 -1
View File
@@ -202,7 +202,7 @@ class VPCSHandler:
nio_type = request.json["type"]
if nio_type not in ("nio_udp", "nio_tap"):
raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type))
nio = vpcs_manager.create_nio(vm.vpcs_path, request.json)
nio = vpcs_manager.create_nio(vm.vpcs_path(), request.json)
vm.port_add_nio_binding(int(request.match_info["port_number"]), nio)
response.set_status(201)
response.json(nio)
+2 -1
View File
@@ -54,7 +54,8 @@ class UploadHandler:
@Route.post(
r"/upload",
description="Manage upload of GNS3 images",
api_version=None
api_version=None,
raw=True
)
def upload(request, response):
data = yield from request.post()
+2 -3
View File
@@ -403,11 +403,10 @@ class BaseVM:
"""
path = self._manager.config.get_section_config("Server").get("ubridge_path", "ubridge")
if path == "ubridge":
path = shutil.which("ubridge")
path = shutil.which(path)
if path is None or len(path) == 0:
raise VMError("uBridge is not installed")
raise VMError("uBridge is not installed or uBridge path is invalid")
return path
@asyncio.coroutine
+9 -5
View File
@@ -530,7 +530,11 @@ class DockerVM(BaseVM):
if self._ubridge_hypervisor and self._ubridge_hypervisor.is_running():
yield from self._ubridge_hypervisor.stop()
state = yield from self._get_container_state()
try:
state = yield from self._get_container_state()
except DockerHttp404Error:
state = "stopped"
if state == "paused":
yield from self.unpause()
@@ -577,6 +581,9 @@ class DockerVM(BaseVM):
@asyncio.coroutine
def reset(self):
try:
state = yield from self._get_container_state()
if state == "paused" or state == "running":
yield from self.stop()
if self.console_type == "vnc":
if self._x11vnc_process:
try:
@@ -589,9 +596,6 @@ class DockerVM(BaseVM):
yield from self._xvfb_process.wait()
except ProcessLookupError:
pass
state = yield from self._get_container_state()
if state == "paused" or state == "running":
yield from self.stop()
# v – 1/True/true or 0/False/false, Remove the volumes associated to the container. Default false.
# force - 1/True/true or 0/False/false, Kill then remove the container. Default false.
yield from self.manager.query("DELETE", "containers/{}".format(self._cid), params={"force": 1, "v": 1})
@@ -658,7 +662,7 @@ class DockerVM(BaseVM):
if nio.capturing:
yield from self._ubridge_hypervisor.send('bridge start_capture bridge{adapter} "{pcap_file}"'.format(adapter=adapter_number,
pcap_file=nio.pcap_output_file))
pcap_file=nio.pcap_output_file))
yield from self._ubridge_hypervisor.send('bridge start bridge{adapter}'.format(adapter=adapter_number))
+4 -4
View File
@@ -336,16 +336,16 @@ class Dynamips(BaseManager):
def find_dynamips(self):
# look for Dynamips
dynamips_path = self.config.get_section_config("Dynamips").get("dynamips_path")
if not dynamips_path:
dynamips_path = shutil.which("dynamips")
dynamips_path = self.config.get_section_config("Dynamips").get("dynamips_path", "dynamips")
if not os.path.isabs(dynamips_path):
dynamips_path = shutil.which(dynamips_path)
if not dynamips_path:
raise DynamipsError("Could not find Dynamips")
if not os.path.isfile(dynamips_path):
raise DynamipsError("Dynamips {} is not accessible".format(dynamips_path))
if not os.access(dynamips_path, os.X_OK):
raise DynamipsError("Dynamips is not executable")
raise DynamipsError("Dynamips {} is not executable".format(dynamips_path))
self._dynamips_path = dynamips_path
return dynamips_path
+12 -7
View File
@@ -230,9 +230,11 @@ class IOUVM(BaseVM):
:returns: path to IOUYAP
"""
path = self._manager.config.get_section_config("IOU").get("iouyap_path", "iouyap")
if path == "iouyap":
path = shutil.which("iouyap")
search_path = self._manager.config.get_section_config("IOU").get("iouyap_path", "iouyap")
path = shutil.which(search_path)
# shutil.which return None if the path doesn't exists
if not path:
return search_path
return path
@property
@@ -534,14 +536,17 @@ class IOUVM(BaseVM):
:param returncode: Process returncode
"""
log.info("{} process has stopped, return code: {}".format(process_name, returncode))
self._terminate_process_iou()
self._terminate_process_iouyap()
self._ioucon_thread_stop_event.set()
if returncode != 0:
self.project.emit("log.error", {"message": "{} process has stopped, return code: {}\n{}".format(process_name,
returncode,
self.read_iou_stdout())})
if returncode == 11:
message = "{} process has stopped, return code: {}. This could be an issue with the image using a different image can fix the issue.\n{}".format(process_name, returncode, self.read_iou_stdout())
else:
message = "{} process has stopped, return code: {}\n{}".format(process_name, returncode, self.read_iou_stdout())
log.warn(message)
self.project.emit("log.error", {"message": message})
def _rename_nvram_file(self):
"""
+2
View File
@@ -153,6 +153,8 @@ class PortManager:
try:
PortManager._check_port(host, port, socket_type)
if host != "0.0.0.0":
PortManager._check_port("0.0.0.0", port, socket_type)
return port
except OSError as e:
last_exception = e
+1 -1
View File
@@ -528,7 +528,7 @@ class Project:
:returns: ZipStream object
"""
z = zipstream.ZipFile()
z = zipstream.ZipFile(allowZip64=True)
# topdown allo to modify the list of directory in order to ignore
# directory
for root, dirs, files in os.walk(self._path, topdown=True):
+4 -1
View File
@@ -62,7 +62,10 @@ class Qcow2:
with open(self.path, 'rb') as f:
content = f.read(struct.calcsize(struct_format))
self.magic, self.version, self.backing_file_offset, self.backing_file_size = struct.unpack_from(struct_format, content)
try:
self.magic, self.version, self.backing_file_offset, self.backing_file_size = struct.unpack_from(struct_format, content)
except struct.error:
raise Qcow2Error("Invalid file header for {}".format(self.path))
if self.magic != 1363560955: # The first 4 bytes contain the characters 'Q', 'F', 'I' followed by 0xfb.
raise Qcow2Error("Invalid magic for {}".format(self.path))
+5
View File
@@ -1424,6 +1424,11 @@ class QemuVM(BaseVM):
command.extend(["-smp", "cpus={}".format(self._cpus)])
if self._run_with_kvm(self.qemu_path, self._options):
command.extend(["-enable-kvm"])
version = yield from self.manager.get_qemu_version(self.qemu_path)
# Issue on some combo Intel CPU + KVM + Qemu 2.4.0
# 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"])
command.extend(["-boot", "order={}".format(self._boot_priority)])
cdrom_option = self._cdrom_option()
command.extend(cdrom_option)
+4 -1
View File
@@ -66,7 +66,10 @@ class VirtualBox(BaseManager):
elif sys.platform.startswith("darwin"):
vboxmanage_path = "/Applications/VirtualBox.app/Contents/MacOS/VBoxManage"
else:
vboxmanage_path = shutil.which("vboxmanage")
vboxmanage_path = "vboxmanage"
if not os.path.isabs(vboxmanage_path):
vboxmanage_path = shutil.which(vboxmanage_path)
if not vboxmanage_path:
raise VirtualBoxError("Could not find VBoxManage")
@@ -30,7 +30,7 @@ import asyncio
from gns3server.utils import parse_version
from gns3server.utils.telnet_server import TelnetServer
from gns3server.utils.asyncio import wait_for_file_creation, wait_for_named_pipe_creation
from gns3server.utils.asyncio import wait_for_file_creation, wait_for_named_pipe_creation, locked_coroutine
from .virtualbox_error import VirtualBoxError
from ..nios.nio_udp import NIOUDP
from ..nios.nio_nat import NIONAT
@@ -230,7 +230,7 @@ class VirtualBoxVM(BaseVM):
if (yield from self.check_hw_virtualization()):
self._hw_virtualization = True
@asyncio.coroutine
@locked_coroutine
def stop(self):
"""
Stops this VirtualBox VM.
@@ -250,7 +250,7 @@ class VirtualBoxVM(BaseVM):
log.debug("Stop result: {}".format(result))
log.info("VirtualBox VM '{name}' [{id}] stopped".format(name=self.name, id=self.id))
# yield from asyncio.sleep(0.5) # give some time for VirtualBox to unlock the VM
yield from asyncio.sleep(0.5) # give some time for VirtualBox to unlock the VM
try:
# deactivate the first serial port
yield from self._modify_vm("--uart1 off")
+4 -1
View File
@@ -105,7 +105,10 @@ class VMware(BaseManager):
elif sys.platform.startswith("darwin"):
vmrun_path = "/Applications/VMware Fusion.app/Contents/Library/vmrun"
else:
vmrun_path = shutil.which("vmrun")
vmrun_path = "vmrun"
if not os.path.isabs(vmrun_path):
vmrun_path = shutil.which(vmrun_path)
if not vmrun_path:
raise VMwareError("Could not find VMware vmrun, please make sure it is installed")
+16 -11
View File
@@ -22,6 +22,7 @@ order to run a VPCS VM.
import os
import sys
import socket
import subprocess
import signal
import re
@@ -93,7 +94,7 @@ class VPCSVM(BaseVM):
Check if VPCS is available with the correct version.
"""
path = self.vpcs_path
path = self.vpcs_path()
if not path:
raise VPCSError("No path to a VPCS executable has been set")
@@ -131,7 +132,6 @@ class VPCSVM(BaseVM):
else:
return None
@property
def vpcs_path(self):
"""
Returns the VPCS executable path.
@@ -139,9 +139,11 @@ class VPCSVM(BaseVM):
:returns: path to VPCS
"""
path = self._manager.config.get_section_config("VPCS").get("vpcs_path", "vpcs")
if path == "vpcs":
path = shutil.which("vpcs")
search_path = self._manager.config.get_section_config("VPCS").get("vpcs_path", "vpcs")
path = shutil.which(search_path)
# shutil.which return None if the path doesn't exists
if not path:
return search_path
return path
@BaseVM.name.setter
@@ -200,7 +202,7 @@ class VPCSVM(BaseVM):
Checks if the VPCS executable version is >= 0.8b or == 0.6.1.
"""
try:
output = yield from subprocess_check_output(self.vpcs_path, "-v", cwd=self.working_dir)
output = yield from subprocess_check_output(self.vpcs_path(), "-v", cwd=self.working_dir)
match = re.search("Welcome to Virtual PC Simulator, version ([0-9a-z\.]+)", output)
if match:
version = match.group(1)
@@ -208,7 +210,7 @@ class VPCSVM(BaseVM):
if self._vpcs_version < parse_version("0.8b") and self._vpcs_version != parse_version("0.6.1"):
raise VPCSError("VPCS executable version must be >= 0.8b or 0.6.1")
else:
raise VPCSError("Could not determine the VPCS version for {}".format(self.vpcs_path))
raise VPCSError("Could not determine the VPCS version for {}".format(self.vpcs_path()))
except (OSError, subprocess.SubprocessError) as e:
raise VPCSError("Error while looking for the VPCS version: {}".format(e))
@@ -244,8 +246,8 @@ class VPCSVM(BaseVM):
self.status = "started"
except (OSError, subprocess.SubprocessError) as e:
vpcs_stdout = self.read_vpcs_stdout()
log.error("Could not start VPCS {}: {}\n{}".format(self.vpcs_path, e, vpcs_stdout))
raise VPCSError("Could not start VPCS {}: {}\n{}".format(self.vpcs_path, e, vpcs_stdout))
log.error("Could not start VPCS {}: {}\n{}".format(self.vpcs_path(), e, vpcs_stdout))
raise VPCSError("Could not start VPCS {}: {}\n{}".format(self.vpcs_path(), e, vpcs_stdout))
def _termination_callback(self, returncode):
"""
@@ -414,7 +416,7 @@ class VPCSVM(BaseVM):
"""
command = [self.vpcs_path]
command = [self.vpcs_path()]
command.extend(["-p", str(self._console)]) # listen to console port
command.extend(["-m", str(self._manager.get_mac_id(self.id))]) # the unique ID is used to set the MAC address offset
command.extend(["-i", "1"]) # option to start only one VPC instance
@@ -430,7 +432,10 @@ class VPCSVM(BaseVM):
# UDP tunnel
command.extend(["-s", str(nio.lport)]) # source UDP port
command.extend(["-c", str(nio.rport)]) # destination UDP port
command.extend(["-t", nio.rhost]) # destination host
try:
command.extend(["-t", socket.gethostbyname(nio.rhost)]) # destination host, we need to resolve the hostname because VPCS doesn't support it
except socket.gaierror as e:
raise VPCSError("Can't resolve hostname {}".format(nio.rhost))
elif isinstance(nio, NIOTAP):
# TAP interface
+6 -2
View File
@@ -30,7 +30,6 @@ import time
import atexit
from .web.route import Route
from .web.request_handler import RequestHandler
from .config import Config
from .modules import MODULES
from .modules.port_manager import PortManager
@@ -199,6 +198,11 @@ class Server:
Starts the server.
"""
server_logger = logging.getLogger('aiohttp.server')
# In debug mode we don't use the standard request log but a more complete in response.py
if log.getEffectiveLevel() == logging.DEBUG:
server_logger.setLevel(logging.CRITICAL)
logger = logging.getLogger("asyncio")
logger.setLevel(logging.ERROR)
@@ -239,7 +243,7 @@ class Server:
m.port_manager = self._port_manager
log.info("Starting server on {}:{}".format(self._host, self._port))
self._handler = app.make_handler(handler=RequestHandler)
self._handler = app.make_handler()
server = self._run_application(self._handler, ssl_context)
self._loop.run_until_complete(server)
self._signal_handling()
View File
Whitespace-only changes.
+21
View File
@@ -127,3 +127,24 @@ def wait_for_named_pipe_creation(pipe_path, timeout=60):
else:
return
raise asyncio.TimeoutError()
def locked_coroutine(f):
"""
Method decorator that replace asyncio.coroutine that warranty
that this specific method of this class instance will not we
executed twice at the same time
"""
@asyncio.coroutine
def new_function(*args, **kwargs):
# In the instance of the class we will store
# a lock has an attribute.
lock_var_name = "__" + f.__name__ + "_lock"
if not hasattr(args[0], lock_var_name):
setattr(args[0], lock_var_name, asyncio.Lock())
with (yield from getattr(args[0], lock_var_name)):
return (yield from f(*args, **kwargs))
return new_function
+2 -2
View File
@@ -23,5 +23,5 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "1.5.2"
__version_info__ = (1, 5, 2, 0)
__version__ = "1.5.4"
__version_info__ = (1, 5, 4, 0)
-28
View File
@@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 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/>.
import aiohttp.web
import logging
class RequestHandler(aiohttp.web.RequestHandler):
def log_access(self, message, environ, response, time):
# In debug mode we don't use the standard request log but a more complete in response.py
if self.logger.getEffectiveLevel() != logging.DEBUG:
super().log_access(message, environ, response, time)
+10 -5
View File
@@ -1,14 +1,19 @@
[Unit]
Description=GNS3 server
Wants=network-online.target
After=network.target network-online.target
[Service]
Type=forking
Environment=statedir=/var/cache/gns3
PIDFile=/var/run/gns3.pid
ExecStart=/usr/local/bin/gns3server --log /var/log/gns3.log \
--pid /var/run/gns3.pid --daemon
Restart=on-abort
User=gns3
Group=gns3
PermissionsStartOnly=true
ExecStartPre=/bin/mkdir -p /var/log/gns3 /var/run/gns3
ExecStartPre=/bin/chown -R gns3:gns3 /var/log/gns3 /var/run/gns3
ExecStart=/usr/local/bin/gns3server --log /var/log/gns3/gns3.log \
--pid /var/run/gns3/gns3.pid --daemon
Restart=on-abort
PIDFile=/var/run/gns3/gns3.pid
[Install]
WantedBy=multi-user.target
+6 -3
View File
@@ -1,6 +1,9 @@
jsonschema>=2.4.0
aiohttp>=0.21.5
aiohttp==1.2.0 # pyup: ignore
aiohttp-cors==0.4.0 # pyup: ignore
yarl==0.8.1 # pyup: ignore
typing>=3.5.3.0 # Otherwise yarl fail with python 3.4
Jinja2>=2.7.3
raven>=5.2.0
raven>=5.23.0
psutil>=3.0.0
zipstream>=1.1.3
zipstream>=1.1.4
+88 -18
View File
@@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Install GNS3 on a remote Ubuntu 14.04 LTS server
# Install GNS3 on a remote Ubuntu LTS server
# This create a dedicated user and setup all the package
# and optionnaly a VPN
#
@@ -26,19 +26,18 @@ function help {
echo "--with-openvpn: Install Open VPN" >&2
echo "--with-iou: Install IOU" >&2
echo "--with-i386-repository: Add i386 repositories require by IOU if they are not available on the system. Warning this will replace your source.list in order to use official ubuntu mirror" >&2
echo "--unstable: Use the GNS3 unstable repository"
echo "--help: This help" >&2
}
function log {
tput setaf 2
echo "=> $1" >&2
tput sgr0
}
lsb_release -d | grep "Ubuntu 14.04" > /dev/null
lsb_release -d | grep "LTS" > /dev/null
if [ $? != 0 ]
then
echo "You can use this script on Ubuntu 14.04 LTS only"
echo "You can use this script on Ubuntu LTS only"
exit 1
fi
@@ -46,8 +45,9 @@ fi
USE_VPN=0
USE_IOU=0
I386_REPO=0
UNSTABLE=0
TEMP=`getopt -o h --long with-openvpn,with-iou,with-i386-repository,help -n 'gns3-remote-install.sh' -- "$@"`
TEMP=`getopt -o h --long with-openvpn,with-iou,with-i386-repository,unstable,help -n 'gns3-remote-install.sh' -- "$@"`
if [ $? != 0 ]
then
help
@@ -70,6 +70,10 @@ while true ; do
I386_REPO=1
shift
;;
--unstable)
UNSTABLE=1
shift
;;
-h|--help)
help
exit 1
@@ -84,26 +88,61 @@ set -e
export DEBIAN_FRONTEND="noninteractive"
UBUNTU_VERSION=`lsb_release -r -s`
if [ "$UBUNTU_VERSION" == "14.04" ]
then
UBUNTU_CODENAME="trusty"
else
UBUNTU_CODENAME="xenial"
fi
log "Add GNS3 repository"
cat <<EOFLIST > /etc/apt/sources.list.d/gns3.list
deb http://ppa.launchpad.net/gns3/ppa/ubuntu trusty main
deb-src http://ppa.launchpad.net/gns3/ppa/ubuntu trusty main
deb http://ppa.launchpad.net/gns3/qemu/ubuntu trusty main
deb-src http://ppa.launchpad.net/gns3/qemu/ubuntu trusty main
if [ "$UBUNTU_CODENAME" == "trusty" ]
then
if [ $UNSTABLE == 1 ]
then
cat <<EOFLIST > /etc/apt/sources.list.d/gns3.list
deb http://ppa.launchpad.net/gns3/unstable/ubuntu $UBUNTU_CODENAME main
deb-src http://ppa.launchpad.net/gns3/unstable/ubuntu $UBUNTU_CODENAME main
deb http://ppa.launchpad.net/gns3/qemu/ubuntu $UBUNTU_CODENAME main
deb-src http://ppa.launchpad.net/gns3/qemu/ubuntu $UBUNTU_CODENAME main
EOFLIST
else
cat <<EOFLIST > /etc/apt/sources.list.d/gns3.list
deb http://ppa.launchpad.net/gns3/ppa/ubuntu $UBUNTU_CODENAME main
deb-src http://ppa.launchpad.net/gns3/ppa/ubuntu $UBUNTU_CODENAME main
deb http://ppa.launchpad.net/gns3/qemu/ubuntu $UBUNTU_CODENAME main
deb-src http://ppa.launchpad.net/gns3/qemu/ubuntu $UBUNTU_CODENAME main
EOFLIST
fi
else
if [ $UNSTABLE == 1 ]
then
cat <<EOFLIST > /etc/apt/sources.list.d/gns3.list
deb http://ppa.launchpad.net/gns3/unstable/ubuntu $UBUNTU_CODENAME main
deb-src http://ppa.launchpad.net/gns3/unstable/ubuntu $UBUNTU_CODENAME main
EOFLIST
else
cat <<EOFLIST > /etc/apt/sources.list.d/gns3.list
deb http://ppa.launchpad.net/gns3/ppa/ubuntu $UBUNTU_CODENAME main
deb-src http://ppa.launchpad.net/gns3/ppa/ubuntu $UBUNTU_CODENAME main
EOFLIST
fi
fi
if [ $I386_REPO == 1 ]
then
cat <<EOFLIST2 >> /etc/apt/sources.list
###### Ubuntu Main Repos
deb http://archive.ubuntu.com/ubuntu/ trusty main universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ trusty main universe multiverse
deb http://archive.ubuntu.com/ubuntu/ $UBUNTU_CODENAME main universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ $UBUNTU_CODENAME main universe multiverse
###### Ubuntu Update Repos
deb http://archive.ubuntu.com/ubuntu/ trusty-security main universe multiverse
deb http://archive.ubuntu.com/ubuntu/ trusty-updates main universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ trusty-security main universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ trusty-updates main universe multiverse
deb http://archive.ubuntu.com/ubuntu/ ${UBUNTU_CODENAME}-security main universe multiverse
deb http://archive.ubuntu.com/ubuntu/ ${UBUNTU_CODENAME}-updates main universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ ${UBUNTU_CODENAME}-security main universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ ${UBUNTU_CODENAME}-updates main universe multiverse
EOFLIST2
fi
@@ -142,7 +181,7 @@ then
apt-get install -y gns3-iou
# Force the host name to gns3vm
hostnamectl set-hostname gns3vm
echo gns3vm > /etc/hostname
# Force hostid for IOU
dd if=/dev/zero bs=4 count=1 of=/etc/hostid
@@ -172,6 +211,8 @@ EOFC
chown -R gns3:gns3 /etc/gns3
chmod -R 700 /etc/gns3
if [ "$UBUNTU_CODENAME" == "trusty" ]
then
cat <<EOFI > /etc/init/gns3.conf
description "GNS3 server"
author "GNS3 Team"
@@ -206,6 +247,35 @@ service gns3 stop
set -e
service gns3 start
else
# Install systemd service
cat <<EOFI > /lib/systemd/system/gns3.service
[Unit]
Description=GNS3 server
[Service]
Type=forking
User=gns3
Group=gns3
PermissionsStartOnly=true
ExecStartPre=/bin/mkdir -p /var/log/gns3 /var/run/gns3
ExecStartPre=/bin/chown -R gns3:gns3 /var/log/gns3 /var/run/gns3
ExecStart=/usr/bin/gns3server --log /var/log/gns3/gns3.log \
--pid /var/run/gns3/gns3.pid --daemon
Restart=on-abort
PIDFile=/var/run/gns3/gns3.pid
[Install]
WantedBy=multi-user.target
EOFI
chmod 755 /lib/systemd/system/gns3.service
chown root:root /lib/systemd/system/gns3.service
log "Start GNS3 service"
systemctl enable gns3
systemctl start gns3
fi
log "GNS3 installed with success"
if [ $USE_VPN == 1 ]
+6
View File
@@ -56,6 +56,12 @@ def test_invalid_file():
Qcow2("tests/resources/nvram_iou")
def test_invalid_empty_file(tmpdir):
open(str(tmpdir / 'a'), 'w+').close()
with pytest.raises(Qcow2Error):
Qcow2(str(tmpdir / 'a'))
@pytest.mark.skipif(qemu_img() is None, reason="qemu-img is not available")
def test_rebase(tmpdir, loop):
shutil.copy("tests/resources/empty8G.qcow2", str(tmpdir / "empty16G.qcow2"))
+61 -1
View File
@@ -22,7 +22,7 @@ import os
import sys
import stat
import re
from tests.utils import asyncio_patch
from tests.utils import asyncio_patch, AsyncioMagicMock
from unittest import mock
@@ -434,6 +434,66 @@ def test_build_command(vm, loop, fake_qemu_binary, port_manager):
]
def test_build_command_kvm(linux_platform, vm, loop, fake_qemu_binary, port_manager):
"""
Qemu 2.4 introduce an issue with KVM
"""
vm._run_with_kvm = MagicMock(return_value=True)
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.3.2")
os.environ["DISPLAY"] = "0:0"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.async(vm._build_command()))
assert cmd == [
fake_qemu_binary,
"-name",
"test",
"-m",
"256M",
"-smp",
"cpus=1",
"-enable-kvm",
"-boot",
"order=c",
"-serial",
"telnet:127.0.0.1:{},server,nowait".format(vm.console),
"-net",
"none",
"-device",
"e1000,mac={}".format(vm._mac_address)
]
def test_build_command_kvm_2_4(linux_platform, vm, loop, fake_qemu_binary, port_manager):
"""
Qemu 2.4 introduce an issue with KVM
"""
vm._run_with_kvm = MagicMock(return_value=True)
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.4.2")
os.environ["DISPLAY"] = "0:0"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.async(vm._build_command()))
assert cmd == [
fake_qemu_binary,
"-name",
"test",
"-m",
"256M",
"-smp",
"cpus=1",
"-enable-kvm",
"-machine",
"smm=off",
"-boot",
"order=c",
"-serial",
"telnet:127.0.0.1:{},server,nowait".format(vm.console),
"-net",
"none",
"-device",
"e1000,mac={}".format(vm._mac_address)
]
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_build_command_without_display(vm, loop, fake_qemu_binary):
+3 -3
View File
@@ -216,15 +216,15 @@ def test_get_default_project_directory(monkeypatch):
def test_clean_project_directory(tmpdir):
# A non anonymous project with uuid.
project1 = tmpdir / uuid4()
project1 = tmpdir / str(uuid4())
project1.mkdir()
# A non anonymous project.
oldproject = tmpdir / uuid4()
oldproject = tmpdir / str(uuid4())
oldproject.mkdir()
# an anonymous project
project2 = tmpdir / uuid4()
project2 = tmpdir / str(uuid4())
project2.mkdir()
tmp = (project2 / ".gns3_temporary")
with open(str(tmp), 'w+') as f:
+12 -20
View File
@@ -65,7 +65,7 @@ def test_vm_check_vpcs_version_0_6_1(loop, vm, manager):
def test_vm_invalid_vpcs_version(loop, manager, vm):
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.1"):
with pytest.raises(VPCSError):
nio = manager.create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
nio = manager.create_nio(vm.vpcs_path(), {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio)
loop.run_until_complete(asyncio.async(vm._check_vpcs_version()))
assert vm.name == "test"
@@ -73,9 +73,9 @@ def test_vm_invalid_vpcs_version(loop, manager, vm):
def test_vm_invalid_vpcs_path(vm, manager, loop):
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM.vpcs_path", return_value="/tmp/fake/path/vpcs"):
with patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM.vpcs_path", return_value="/tmp/fake/path/vpcs"):
with pytest.raises(VPCSError):
nio = manager.create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
nio = manager.create_nio(vm.vpcs_path(), {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio)
loop.run_until_complete(asyncio.async(vm.start()))
assert vm.name == "test"
@@ -89,10 +89,10 @@ def test_start(loop, vm):
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
nio = VPCS.instance().create_nio(vm.vpcs_path(), {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio)
loop.run_until_complete(asyncio.async(vm.start()))
assert mock_exec.call_args[0] == (vm.vpcs_path,
assert mock_exec.call_args[0] == (vm.vpcs_path(),
'-p',
str(vm.console),
'-m', '1',
@@ -125,10 +125,10 @@ def test_start_0_6_1(loop, vm):
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
nio = VPCS.instance().create_nio(vm.vpcs_path(), {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio)
loop.run_until_complete(asyncio.async(vm.start()))
assert mock_exec.call_args[0] == (vm.vpcs_path,
assert mock_exec.call_args[0] == (vm.vpcs_path(),
'-p',
str(vm.console),
'-m', '1',
@@ -158,7 +158,7 @@ def test_stop(loop, vm):
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
nio = VPCS.instance().create_nio(vm.vpcs_path(), {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio)
loop.run_until_complete(asyncio.async(vm.start()))
@@ -191,7 +191,7 @@ def test_reload(loop, vm):
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
nio = VPCS.instance().create_nio(vm.vpcs_path(), {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio)
loop.run_until_complete(asyncio.async(vm.start()))
assert vm.is_running()
@@ -207,7 +207,7 @@ def test_reload(loop, vm):
def test_add_nio_binding_udp(vm):
nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
nio = VPCS.instance().create_nio(vm.vpcs_path(), {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio)
assert nio.lport == 4242
@@ -215,21 +215,13 @@ def test_add_nio_binding_udp(vm):
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_add_nio_binding_tap(vm, ethernet_device):
with patch("gns3server.modules.base_manager.BaseManager.has_privileged_access", return_value=True):
nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_tap", "tap_device": ethernet_device})
nio = VPCS.instance().create_nio(vm.vpcs_path(), {"type": "nio_tap", "tap_device": ethernet_device})
vm.port_add_nio_binding(0, nio)
assert nio.tap_device == ethernet_device
# def test_add_nio_binding_tap_no_privileged_access(vm):
# with patch("gns3server.modules.base_manager.BaseManager.has_privileged_access", return_value=False):
# with pytest.raises(aiohttp.web.HTTPForbidden):
# nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_tap", "tap_device": "test"})
# vm.port_add_nio_binding(0, nio)
# assert vm._ethernet_adapter.ports[0] is None
#
def test_port_remove_nio_binding(vm):
nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
nio = VPCS.instance().create_nio(vm.vpcs_path(), {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio)
vm.port_remove_nio_binding(0)
assert vm._ethernet_adapter.ports[0] is None
+24 -1
View File
@@ -21,7 +21,7 @@ import pytest
import sys
from unittest.mock import MagicMock
from gns3server.utils.asyncio import wait_run_in_executor, subprocess_check_output, wait_for_process_termination
from gns3server.utils.asyncio import wait_run_in_executor, subprocess_check_output, wait_for_process_termination, locked_coroutine
def test_wait_run_in_executor(loop):
@@ -67,3 +67,26 @@ def test_wait_for_process_termination(loop):
exec = wait_for_process_termination(process, timeout=0.5)
with pytest.raises(asyncio.TimeoutError):
loop.run_until_complete(asyncio.async(exec))
def test_lock_decorator(loop):
"""
The test check if the the second call to method_to_lock wait for the
first call to finish
"""
class TestLock:
def __init__(self):
self._test_val = 0
@locked_coroutine
def method_to_lock(self):
res = self._test_val
yield from asyncio.sleep(0.1)
self._test_val += 1
return res
i = TestLock()
res = set(loop.run_until_complete(asyncio.gather(i.method_to_lock(), i.method_to_lock())))
assert res == set((0, 1,)) # We use a set to test this to avoid order issue