Hello community, here is the log from the commit of package gns3-server for openSUSE:Factory checked in at 2017-08-08 11:58:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gns3-server (Old) and /work/SRC/openSUSE:Factory/.gns3-server.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gns3-server" Tue Aug 8 11:58:55 2017 rev:10 rq:511359 version:2.0.3 Changes: -------- --- /work/SRC/openSUSE:Factory/gns3-server/gns3-server.changes 2017-05-17 17:19:00.911482097 +0200 +++ /work/SRC/openSUSE:Factory/.gns3-server.new/gns3-server.changes 2017-08-08 11:58:57.002470661 +0200 @@ -1,0 +2,8 @@ +Sat Jun 24 19:42:05 UTC 2017 - [email protected] + +- update to 2.0.3 + https://github.com/GNS3/gns3-server/releases/tag/v2.0.1 + https://github.com/GNS3/gns3-server/releases/tag/v2.0.2 + https://github.com/GNS3/gns3-server/releases/tag/v2.0.3 + +------------------------------------------------------------------- Old: ---- gns3-server-2.0.0.tar.gz New: ---- gns3-server-2.0.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gns3-server.spec ++++++ --- /var/tmp/diff_new_pack.dAF1Fo/_old 2017-08-08 11:58:59.118172678 +0200 +++ /var/tmp/diff_new_pack.dAF1Fo/_new 2017-08-08 11:58:59.146168735 +0200 @@ -27,28 +27,28 @@ Summary: GNS3 is a graphical network simulator License: GPL-3.0+ Group: Productivity/Networking/Other -Version: 2.0.0 +Version: 2.0.3 Release: 0 Url: http://www.gns3.net/ Source0: %{name}-%{version}.tar.gz Source1: %{name}-rpmlintrc +BuildRequires: busybox BuildRequires: python3-devel >= 3.3 BuildRequires: python3-pip BuildRequires: python3-setuptools -BuildRequires: busybox +Requires: busybox Requires: cpulimit -Requires: dynamips >= 0.2.11 Requires: docker +Requires: dynamips >= 0.2.11 Requires: iouyap Requires: python3-Jinja2 >= 2.7.3 Requires: python3-aiohttp >= 0.21.5 +Requires: python3-docker-py >= 1.4.0 Requires: python3-jsonschema >= 2.4.0 -Requires: python3-raven >= 5.2.0 Requires: python3-psutil >= 3.0.0 -Requires: python3-docker-py >= 1.4.0 +Requires: python3-raven >= 5.2.0 Requires: python3-zipstream >= 1.1.3 Requires: qemu -Requires: busybox Requires: vpcs >= 0.5b1 Requires: wireshark %if 0%{?suse_version} ++++++ gns3-server-2.0.0.tar.gz -> gns3-server-2.0.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/.gitignore new/gns3-server-2.0.3/.gitignore --- old/gns3-server-2.0.0/.gitignore 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/.gitignore 2017-06-13 10:35:50.000000000 +0200 @@ -53,3 +53,6 @@ vpcs.hist startup.vpcs .gns3_shell_history + +# Virtualenv +env \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/.travis.yml new/gns3-server-2.0.3/.travis.yml --- old/gns3-server-2.0.0/.travis.yml 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/.travis.yml 2017-06-13 10:35:50.000000000 +0200 @@ -9,7 +9,8 @@ - python setup.py install - pip install -rdev-requirements.txt script: -- py.test -v -s tests +- mkdir ‡ +- py.test -v -s tests --basetemp=‡ deploy: provider: pypi user: noplay diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/CHANGELOG new/gns3-server-2.0.3/CHANGELOG --- old/gns3-server-2.0.0/CHANGELOG 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/CHANGELOG 2017-06-13 10:35:50.000000000 +0200 @@ -1,5 +1,62 @@ # Change Log +## 2.0.3 13/06/2017 + +* Fixes #1068 - handle zipfile encoding issues at project duplication +* Fix: #1066 - Catching parsing errors at linked vbox file +* Ignoring virtualenv directory at gitignore +* Escaping VPCS name in regex #1067 +* Fix racecondition when listing interface +* Fix Qemu disk creation with unicode characters not supported by local filesystem #1058 (#1063) +* Fix when config file doesn't have computes section (#1062) +* Check aiohttp version + +## 2.0.2 30/05/2017 + +* Set correct permission on ubridge when doing a remote installation +* Remote install script should be totally non interactive +* Duplicate project on remote server use UUID +* Fix import of some old topologies from 1.3 +* Fix error in logging of error during starting GNS3 VM +* Fix an error when logging Docker container fail to start +* Use docker version in error message of outdated docker installation +* Support images created by "docker commit". Fixes #1039 +* Do not wait auto start to finish in order to complete project opening +* Improve logging for remote server connection lost + +## 2.0.1 16/05/2017 + +* Handle HTTP 504 errors from compute node +* When connecting to a compute node ask for qemu images list +* When importing portable project NAT node is loaded on GNS3 VM +* Fix port numbering for Wic slot 1 & 2 +* Fixes issue with connections when loading an ATM switch. +* Fixes ATM mapping. +* Fixes Frame-relay VC mapping. +* Fix export project is looking into the wrong directory +* Fix a race condition in logging when ubridge exit fast +* Fix conversion issue with old topology with C3640 +* Fix error when you have a directory in your symbols directory +* Catch VMWare errors when getting status after GNS3 VM start +* Make sure upstart LANG is utf8 +* Always install typing module (compat with python 3.4 on ubuntu) +* Fix KeyError: 'filename' +* Catch missing function listxattr on some Linux host. +* Sort image list +* Handle a race condition at project closing +* Fix unicode error when reading ios configuration +* Fix AttributeError: 'NoneType' object has no attribute 'send' +* Fix a conversion issue with some 1.3 topologies +* Fix an error with ethernetswitch when ethertype is null +* Raise an error if we can't create the dynamips configuration directory +* Catch timeout error when loading virtualbox VM +* Handle broken compute at server startup +* Catch error when we can't backup the topology +* Catch error when writting the topology file on read only device +* Catch a race condition in VirtualBox when editing and linking +* Fix a race condition when editing a qemu vm and connecting it +* Docker aux console is a VT100 terminal + ## 2.0.0 02/05/2017 * Fix connection to websocket with last docker release diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/README.rst new/gns3-server-2.0.3/README.rst --- old/gns3-server-2.0.0/README.rst 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/README.rst 2017-06-13 10:35:50.000000000 +0200 @@ -22,7 +22,7 @@ master is the next stable release, you can test it in your day to day activities. Bug fixes or small improvements pull requests go here. -1.x (1.4 for example) +2.x (2.1 for example) ******** Next major release diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/dev-requirements.txt new/gns3-server-2.0.3/dev-requirements.txt --- old/gns3-server-2.0.0/dev-requirements.txt 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/dev-requirements.txt 2017-06-13 10:35:50.000000000 +0200 @@ -1,7 +1,7 @@ -rrequirements.txt -sphinx==1.5.5 -pytest==3.0.7 +sphinx==1.6.2 +pytest==3.1.1 pep8==1.7.0 pytest-catchlog==1.2.2 pytest-timeout==1.2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/base_manager.py new/gns3-server-2.0.3/gns3server/compute/base_manager.py --- old/gns3-server-2.0.0/gns3server/compute/base_manager.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/base_manager.py 2017-06-13 10:35:50.000000000 +0200 @@ -344,7 +344,7 @@ # test the 2nd byte and check if the 13th bit (CAP_NET_RAW) is set if struct.unpack("<IIIII", caps)[1] & 1 << 13: return True - except OSError as e: + except (AttributeError, OSError) as e: log.error("could not determine if CAP_NET_RAW capability is set for {}: {}".format(executable, e)) return False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/base_node.py new/gns3-server-2.0.3/gns3server/compute/base_node.py --- old/gns3-server-2.0.0/gns3server/compute/base_node.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/base_node.py 2017-06-13 10:35:50.000000000 +0200 @@ -541,8 +541,9 @@ self._ubridge_hypervisor = Hypervisor(self._project, self.ubridge_path, self.working_dir, server_host) log.info("Starting new uBridge hypervisor {}:{}".format(self._ubridge_hypervisor.host, self._ubridge_hypervisor.port)) yield from self._ubridge_hypervisor.start() - log.info("Hypervisor {}:{} has successfully started".format(self._ubridge_hypervisor.host, self._ubridge_hypervisor.port)) - yield from self._ubridge_hypervisor.connect() + if self._ubridge_hypervisor: + log.info("Hypervisor {}:{} has successfully started".format(self._ubridge_hypervisor.host, self._ubridge_hypervisor.port)) + yield from self._ubridge_hypervisor.connect() @asyncio.coroutine def _stop_ubridge(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/docker/__init__.py new/gns3-server-2.0.3/gns3server/compute/docker/__init__.py --- old/gns3-server-2.0.0/gns3server/compute/docker/__init__.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/docker/__init__.py 2017-06-13 10:35:50.000000000 +0200 @@ -33,7 +33,9 @@ log = logging.getLogger(__name__) +# Be carefull to keep it consistent DOCKER_MINIMUM_API_VERSION = "1.25" +DOCKER_MINIMUM_VERSION = "1.13" class Docker(BaseManager): @@ -60,7 +62,7 @@ self._connected = False raise DockerError("Can't connect to docker daemon") if parse_version(version["ApiVersion"]) < parse_version(DOCKER_MINIMUM_API_VERSION): - raise DockerError("Docker API version is {}. GNS3 requires a minimum API version of {}".format(version["ApiVersion"], DOCKER_MINIMUM_API_VERSION)) + raise DockerError("Docker version is {}. GNS3 requires a minimum version of {}".format(version["Version"], DOCKER_MINIMUM_VERSION)) def connector(self): if self._connector is None or self._connector.closed: @@ -113,11 +115,13 @@ :returns: HTTP response """ data = json.dumps(data) - url = "http://docker/v" + DOCKER_MINIMUM_API_VERSION + "/" + path - if timeout is None: timeout = 60 * 60 * 24 * 31 # One month timeout + if path == 'version': + url = "http://docker/v1.12/" + path # API of docker v1.0 + else: + url = "http://docker/v" + DOCKER_MINIMUM_API_VERSION + "/" + path try: if path != "version": # version is use by check connection yield from self._check_connection() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/docker/docker_vm.py new/gns3-server-2.0.3/gns3server/compute/docker/docker_vm.py --- old/gns3-server-2.0.0/gns3server/compute/docker/docker_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/docker/docker_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -213,7 +213,7 @@ self._volumes = ["/etc/network"] - volumes = image_infos.get("ContainerConfig", {}).get("Volumes") + volumes = image_infos.get("Config", {}).get("Volumes") if volumes is None: return binds for volume in volumes.keys(): @@ -361,7 +361,7 @@ try: yield from self._add_ubridge_connection(nio, adapter_number) except UbridgeNamespaceError: - log.error("Container {} failed to start", self.name) + log.error("Container %s failed to start", self.name) yield from self.stop() # The container can crash soon after the start, this means we can not move the interface to the container namespace @@ -393,7 +393,7 @@ # We can not use the API because docker doesn't expose a websocket api for exec # https://github.com/GNS3/gns3-gui/issues/1039 process = yield from asyncio.subprocess.create_subprocess_exec( - "docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "script", "-qfc", "while true; do /gns3/bin/busybox sh; done", "/dev/null", + "docker", "exec", "-i", self._cid, "/gns3/bin/busybox", "script", "-qfc", "while true; do TERM=vt100 /gns3/bin/busybox sh; done", "/dev/null", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT, stdin=asyncio.subprocess.PIPE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/atm_switch.py new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/atm_switch.py --- old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/atm_switch.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/atm_switch.py 2017-06-13 10:35:50.000000000 +0200 @@ -188,22 +188,33 @@ raise DynamipsError("Port {} is not allocated".format(port_number)) # remove VCs mapped with the port - pvc_entry = re.compile(r"""^([0-9]*):([0-9]*):([0-9]*)$""") for source, destination in self._active_mappings.copy().items(): - match_source_pvc = pvc_entry.search(source) - match_destination_pvc = pvc_entry.search(destination) - if match_source_pvc and match_destination_pvc: + if len(source) == 3 and len(destination) == 3: # remove the virtual channels mapped with this port/nio - source_port, source_vpi, source_vci = map(int, match_source_pvc.group(1, 2, 3)) - destination_port, destination_vpi, destination_vci = map(int, match_destination_pvc.group(1, 2, 3)) + source_port, source_vpi, source_vci = source + destination_port, destination_vpi, destination_vci = destination if port_number == source_port: + log.info('ATM switch "{name}" [{id}]: unmapping VCC between port {source_port} VPI {source_vpi} VCI {source_vci} and port {destination_port} VPI {destination_vpi} VCI {destination_vci}'.format(name=self._name, + id=self._id, + source_port=source_port, + source_vpi=source_vpi, + source_vci=source_vci, + destination_port=destination_port, + destination_vpi=destination_vpi, + destination_vci=destination_vci)) yield from self.unmap_pvc(source_port, source_vpi, source_vci, destination_port, destination_vpi, destination_vci) yield from self.unmap_pvc(destination_port, destination_vpi, destination_vci, source_port, source_vpi, source_vci) else: # remove the virtual paths mapped with this port/nio - source_port, source_vpi = map(int, source.split(':')) - destination_port, destination_vpi = map(int, destination.split(':')) + source_port, source_vpi = source + destination_port, destination_vpi = destination if port_number == source_port: + log.info('ATM switch "{name}" [{id}]: unmapping VPC between port {source_port} VPI {source_vpi} and port {destination_port} VPI {destination_vpi}'.format(name=self._name, + id=self._id, + source_port=source_port, + source_vpi=source_vpi, + destination_port=destination_port, + destination_vpi=destination_vpi)) yield from self.unmap_vp(source_port, source_vpi, destination_port, destination_vpi) yield from self.unmap_vp(destination_port, destination_vpi, source_port, source_vpi) @@ -239,6 +250,14 @@ if self.has_port(destination_port): if (source_port, source_vpi, source_vci) not in self._active_mappings and \ (destination_port, destination_vpi, destination_vci) not in self._active_mappings: + log.info('ATM switch "{name}" [{id}]: mapping VCC between port {source_port} VPI {source_vpi} VCI {source_vci} and port {destination_port} VPI {destination_vpi} VCI {destination_vci}'.format(name=self._name, + id=self._id, + source_port=source_port, + source_vpi=source_vpi, + source_vci=source_vci, + destination_port=destination_port, + destination_vpi=destination_vpi, + destination_vci=destination_vci)) yield from self.map_pvc(source_port, source_vpi, source_vci, destination_port, destination_vpi, destination_vci) yield from self.map_pvc(destination_port, destination_vpi, destination_vci, source_port, source_vpi, source_vci) else: @@ -247,6 +266,12 @@ destination_port, destination_vpi = map(int, destination.split(':')) if self.has_port(destination_port): if (source_port, source_vpi) not in self._active_mappings and (destination_port, destination_vpi) not in self._active_mappings: + log.info('ATM switch "{name}" [{id}]: mapping VPC between port {source_port} VPI {source_vpi} and port {destination_port} VPI {destination_vpi}'.format(name=self._name, + id=self._id, + source_port=source_port, + source_vpi=source_vpi, + destination_port=destination_port, + destination_vpi=destination_vpi)) yield from self.map_vp(source_port, source_vpi, destination_port, destination_vpi) yield from self.map_vp(destination_port, destination_vpi, source_port, source_vpi) @@ -262,10 +287,10 @@ """ if port1 not in self._nios: - raise DynamipsError("Port {} is not allocated".format(port1)) + return if port2 not in self._nios: - raise DynamipsError("Port {} is not allocated".format(port2)) + return nio1 = self._nios[port1] nio2 = self._nios[port2] @@ -283,7 +308,7 @@ port2=port2, vpi2=vpi2)) - self._active_mappings["{}:{}".format(port1, vpi1)] = "{}:{}".format(port2, vpi2) + self._active_mappings[(port1, vpi1)] = (port2, vpi2) @asyncio.coroutine def unmap_vp(self, port1, vpi1, port2, vpi2): @@ -297,10 +322,10 @@ """ if port1 not in self._nios: - raise DynamipsError("Port {} is not allocated".format(port1)) + return if port2 not in self._nios: - raise DynamipsError("Port {} is not allocated".format(port2)) + return nio1 = self._nios[port1] nio2 = self._nios[port2] @@ -318,7 +343,7 @@ port2=port2, vpi2=vpi2)) - del self._active_mappings["{}:{}".format(port1, vpi1)] + del self._active_mappings[(port1, vpi1)] @asyncio.coroutine def map_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2): @@ -334,10 +359,10 @@ """ if port1 not in self._nios: - raise DynamipsError("Port {} is not allocated".format(port1)) + return if port2 not in self._nios: - raise DynamipsError("Port {} is not allocated".format(port2)) + return nio1 = self._nios[port1] nio2 = self._nios[port2] @@ -359,7 +384,7 @@ vpi2=vpi2, vci2=vci2)) - self._active_mappings["{}:{}:{}".format(port1, vpi1, vci1)] = "{}:{}:{}".format(port2, vpi2, vci2) + self._active_mappings[(port1, vpi1, vci1)] = (port2, vpi2, vci2) @asyncio.coroutine def unmap_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2): @@ -375,10 +400,10 @@ """ if port1 not in self._nios: - raise DynamipsError("Port {} is not allocated".format(port1)) + return if port2 not in self._nios: - raise DynamipsError("Port {} is not allocated".format(port2)) + return nio1 = self._nios[port1] nio2 = self._nios[port2] @@ -399,7 +424,7 @@ port2=port2, vpi2=vpi2, vci2=vci2)) - del self._active_mappings["{}:{}:{}".format(port1, vpi1, vci1)] + del self._active_mappings[(port1, vpi1, vci1)] @asyncio.coroutine def start_capture(self, port_number, output_file, data_link_type="DLT_ATM_RFC1483"): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/bridge.py new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/bridge.py --- old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/bridge.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/bridge.py 2017-06-13 10:35:50.000000000 +0200 @@ -103,8 +103,8 @@ :param nio: NIO instance to remove """ - - yield from self._hypervisor.send('nio_bridge remove_nio "{name}" {nio}'.format(name=self._name, nio=nio)) + if self._hypervisor: + yield from self._hypervisor.send('nio_bridge remove_nio "{name}" {nio}'.format(name=self._name, nio=nio)) self._nios.remove(nio) @property diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/ethernet_switch.py new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/ethernet_switch.py --- old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/ethernet_switch.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/ethernet_switch.py 2017-06-13 10:35:50.000000000 +0200 @@ -246,7 +246,7 @@ elif settings["type"] == "dot1q": yield from self.set_dot1q_port(port_number, settings["vlan"]) elif settings["type"] == "qinq": - yield from self.set_qinq_port(port_number, settings["vlan"], settings["ethertype"]) + yield from self.set_qinq_port(port_number, settings["vlan"], settings.get("ethertype")) @asyncio.coroutine def set_access_port(self, port_number, vlan_id): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/frame_relay_switch.py new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/frame_relay_switch.py --- old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/frame_relay_switch.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/frame_relay_switch.py 2017-06-13 10:35:50.000000000 +0200 @@ -191,9 +191,15 @@ # remove VCs mapped with the port for source, destination in self._active_mappings.copy().items(): - source_port, source_dlci = map(int, source.split(':')) - destination_port, destination_dlci = map(int, destination.split(':')) + source_port, source_dlci = source + destination_port, destination_dlci = destination if port_number == source_port: + log.info('Frame Relay switch "{name}" [{id}]: unmapping VC between port {source_port} DLCI {source_dlci} and port {destination_port} DLCI {destination_dlci}'.format(name=self._name, + id=self._id, + source_port=source_port, + source_dlci=source_dlci, + destination_port=destination_port, + destination_dlci=destination_dlci)) yield from self.unmap_vc(source_port, source_dlci, destination_port, destination_dlci) yield from self.unmap_vc(destination_port, destination_dlci, source_port, source_dlci) @@ -224,6 +230,13 @@ destination_port, destination_dlci = map(int, destination.split(':')) if self.has_port(destination_port): if (source_port, source_dlci) not in self._active_mappings and (destination_port, destination_dlci) not in self._active_mappings: + log.info('Frame Relay switch "{name}" [{id}]: mapping VC between port {source_port} DLCI {source_dlci} and port {destination_port} DLCI {destination_dlci}'.format(name=self._name, + id=self._id, + source_port=source_port, + source_dlci=source_dlci, + destination_port=destination_port, + destination_dlci=destination_dlci)) + yield from self.map_vc(source_port, source_dlci, destination_port, destination_dlci) yield from self.map_vc(destination_port, destination_dlci, source_port, source_dlci) @@ -260,7 +273,7 @@ port2=port2, dlci2=dlci2)) - self._active_mappings["{}:{}".format(port1, dlci1)] = "{}:{}".format(port2, dlci2) + self._active_mappings[(port1, dlci1)] = (port2, dlci2) @asyncio.coroutine def unmap_vc(self, port1, dlci1, port2, dlci2): @@ -294,7 +307,7 @@ dlci1=dlci1, port2=port2, dlci2=dlci2)) - del self._active_mappings["{}:{}".format(port1, dlci1)] + del self._active_mappings[(port1, dlci1)] @asyncio.coroutine def start_capture(self, port_number, output_file, data_link_type="DLT_FRELAY"): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/router.py new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/router.py --- old/gns3-server-2.0.0/gns3server/compute/dynamips/nodes/router.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/dynamips/nodes/router.py 2017-06-13 10:35:50.000000000 +0200 @@ -71,7 +71,10 @@ super().__init__(name, node_id, project, manager, console=console, aux=aux, allocate_aux=aux) self._working_directory = os.path.join(self.project.module_working_directory(self.manager.module_name.lower()), self.id) - os.makedirs(os.path.join(self._working_directory, "configs"), exist_ok=True) + try: + os.makedirs(os.path.join(self._working_directory, "configs"), exist_ok=True) + except OSError as e: + raise DynamipsError("Can't create the dynamips config directory: {}".format(str(e))) if dynamips_id: self._convert_before_2_0_0_b3(dynamips_id) @@ -1553,7 +1556,7 @@ try: startup_config_path = os.path.join(self._working_directory, startup_config) if os.path.exists(startup_config_path): - with open(startup_config_path) as f: + with open(startup_config_path, encoding="utf-8") as f: self._startup_config_content = f.read() else: self._startup_config_content = '' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/qemu/__init__.py new/gns3-server-2.0.3/gns3server/compute/qemu/__init__.py --- old/gns3-server-2.0.0/gns3server/compute/qemu/__init__.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/qemu/__init__.py 2017-06-13 10:35:50.000000000 +0200 @@ -247,8 +247,13 @@ directory = self.get_images_directory() os.makedirs(directory, exist_ok=True) path = os.path.join(directory, os.path.basename(path)) - if os.path.exists(path): - raise QemuError("Could not create disk image {} already exist".format(path)) + + try: + if os.path.exists(path): + raise QemuError("Could not create disk image {} already exist".format(path)) + except UnicodeEncodeError: + raise QemuError("Could not create disk image {}, " + "path contains characters not supported by filesystem".format(path)) command = [qemu_img, "create", "-f", img_format] for option in sorted(options.keys()): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/qemu/qemu_vm.py new/gns3-server-2.0.3/gns3server/compute/qemu/qemu_vm.py --- old/gns3-server-2.0.0/gns3server/compute/qemu/qemu_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/qemu/qemu_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -1131,9 +1131,13 @@ adapter_number=adapter_number)) if self.ubridge: - yield from self._add_ubridge_udp_connection("QEMU-{}-{}".format(self._id, adapter_number), - self._local_udp_tunnels[adapter_number][1], - nio) + try: + yield from self._add_ubridge_udp_connection("QEMU-{}-{}".format(self._id, adapter_number), + self._local_udp_tunnels[adapter_number][1], + nio) + except IndexError: + raise QemuError('Adapter {adapter_number} does not exist on QEMU VM "{name}"'.format(name=self._name, + adapter_number=adapter_number)) elif self.is_running(): raise QemuError("Sorry, adding a link to a started Qemu VM is not supported without using uBridge.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/virtualbox/__init__.py new/gns3-server-2.0.3/gns3server/compute/virtualbox/__init__.py --- old/gns3-server-2.0.0/gns3server/compute/virtualbox/__init__.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/virtualbox/__init__.py 2017-06-13 10:35:50.000000000 +0200 @@ -94,7 +94,7 @@ if not vboxmanage_path: vboxmanage_path = self.find_vboxmanage() if not vboxmanage_path: - raise VirtualBoxError("Could not found VBoxManage") + raise VirtualBoxError("Could not find VBoxManage") command = [vboxmanage_path, "--nologo", subcommand] command.extend(args) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/virtualbox/virtualbox_vm.py new/gns3-server-2.0.3/gns3server/compute/virtualbox/virtualbox_vm.py --- old/gns3-server-2.0.0/gns3server/compute/virtualbox/virtualbox_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/virtualbox/virtualbox_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -209,7 +209,12 @@ Fix the VM uuid in the case of linked clone """ if os.path.exists(self._linked_vbox_file()): - tree = ET.parse(self._linked_vbox_file()) + try: + tree = ET.parse(self._linked_vbox_file()) + except ET.ParseError: + raise VirtualBoxError("Cannot modify VirtualBox linked nodes file. " + "File {} is corrupted.".format(self._linked_vbox_file())) + machine = tree.getroot().find("{http://www.virtualbox.org/}Machine") if machine is not None and machine.get("uuid") != "{" + self.id + "}": @@ -968,9 +973,13 @@ adapter_number=adapter_number)) if self.ubridge: - yield from self._add_ubridge_udp_connection("VBOX-{}-{}".format(self._id, adapter_number), - self._local_udp_tunnels[adapter_number][1], - nio) + try: + yield from self._add_ubridge_udp_connection("VBOX-{}-{}".format(self._id, adapter_number), + self._local_udp_tunnels[adapter_number][1], + nio) + except KeyError: + raise VirtualBoxError("Adapter {adapter_number} doesn't exist on VirtualBox VM '{name}'".format(name=self.name, + adapter_number=adapter_number)) yield from self._control_vm("setlinkstate{} on".format(adapter_number + 1)) else: vm_state = yield from self._get_vm_state() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/compute/vpcs/vpcs_vm.py new/gns3-server-2.0.3/gns3server/compute/vpcs/vpcs_vm.py --- old/gns3-server-2.0.0/gns3server/compute/vpcs/vpcs_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/compute/vpcs/vpcs_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -171,7 +171,8 @@ if self.script_file: content = self.startup_script content = content.replace(self._name, new_name) - content = re.sub(r"^set pcname .+$", "set pcname " + new_name, content, flags=re.MULTILINE) + escaped_name = re.escape(new_name) + content = re.sub(r"^set pcname .+$", "set pcname " + escaped_name, content, flags=re.MULTILINE) self.startup_script = content super(VPCSVM, VPCSVM).name.__set__(self, new_name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/__init__.py new/gns3-server-2.0.3/gns3server/controller/__init__.py --- old/gns3-server-2.0.0/gns3server/controller/__init__.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/__init__.py 2017-06-13 10:35:50.000000000 +0200 @@ -82,12 +82,12 @@ password=server_config.get("password", ""), force=True) except aiohttp.web_exceptions.HTTPConflict as e: - log.fatal("Can't acces to the local server, make sure anything else is not running on the same port") + log.fatal("Can't access to the local server, make sure anything else is not running on the same port") sys.exit(1) for c in computes: try: yield from self.add_compute(**c) - except (aiohttp.web_exceptions.HTTPConflict): + except (aiohttp.web_exceptions.HTTPConflict, KeyError): pass # Skip not available servers at loading yield from self.load_projects() try: @@ -176,7 +176,7 @@ if "gns3vm" in data: self.gns3vm.settings = data["gns3vm"] - return data["computes"] + return data.get("computes", []) @asyncio.coroutine def load_projects(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/compute.py new/gns3-server-2.0.3/gns3server/controller/compute.py --- old/gns3-server-2.0.0/gns3server/controller/compute.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/compute.py 2017-06-13 10:35:50.000000000 +0200 @@ -23,6 +23,7 @@ import uuid import sys import io +from operator import itemgetter from ..utils import parse_version from ..utils.images import list_images @@ -528,7 +529,7 @@ raise aiohttp.web.HTTPForbidden(text=msg) elif response.status == 404: raise aiohttp.web.HTTPNotFound(text="{} {} not found".format(method, path)) - elif response.status == 408: + elif response.status == 408 or response.status == 504: raise aiohttp.web.HTTPRequestTimeout(text="{} {} request timeout".format(method, path)) elif response.status == 409: try: @@ -579,8 +580,10 @@ Forward a call to the emulator on compute """ try: - res = yield from self.http_query(method, "/{}/{}".format(type, path), data=data, timeout=None) + action = "/{}/{}".format(type, path) + res = yield from self.http_query(method, action, data=data, timeout=None) except aiohttp.errors.DisconnectedError: + log.error("Connection lost to %s during %s %s", self._id, method, action) raise aiohttp.web.HTTPGatewayTimeout() return res.json @@ -600,6 +603,9 @@ for local_image in list_images(type): if local_image['filename'] not in [i['filename'] for i in images]: images.append(local_image) + images = sorted(images, key=itemgetter('filename')) + else: + images = sorted(images, key=itemgetter('image')) except OSError as e: raise ComputeError("Can't list images: {}".format(str(e))) return images diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/export_project.py new/gns3-server-2.0.3/gns3server/controller/export_project.py --- old/gns3-server-2.0.0/gns3server/controller/export_project.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/export_project.py 2017-06-13 10:35:50.000000000 +0200 @@ -190,6 +190,5 @@ if os.path.exists(path): arcname = os.path.join("images", directory, os.path.basename(image)) z.write(path, arcname) - break - else: - raise aiohttp.web.HTTPConflict(text="Topology could not be exported because the image {} is not available. If you use multiple server, we need a copy of the image on the main server.".format(path)) + return + raise aiohttp.web.HTTPConflict(text="Topology could not be exported because the image {} is not available. If you use multiple server, we need a copy of the image on the main server.".format(image)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/gns3vm/__init__.py new/gns3-server-2.0.3/gns3server/controller/gns3vm/__init__.py --- old/gns3-server-2.0.0/gns3server/controller/gns3vm/__init__.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/gns3vm/__init__.py 2017-06-13 10:35:50.000000000 +0200 @@ -250,7 +250,7 @@ force=True) except aiohttp.web.HTTPConflict: pass - log.error("Can't start the GNS3 VM: {}", str(e)) + log.error("Can't start the GNS3 VM: %s", str(e)) @asyncio.coroutine def exit_vm(self): @@ -287,7 +287,7 @@ yield from engine.start() except Exception as e: yield from self._controller.delete_compute("vm") - log.error("Can't start the GNS3 VM: {}", str(e)) + log.error("Can't start the GNS3 VM: {}".format(str(e))) yield from compute.update(name="GNS3 VM ({})".format(engine.vmname)) raise e yield from compute.update(name="GNS3 VM ({})".format(engine.vmname), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/gns3vm/virtualbox_gns3_vm.py new/gns3-server-2.0.3/gns3server/controller/gns3vm/virtualbox_gns3_vm.py --- old/gns3-server-2.0.0/gns3server/controller/gns3vm/virtualbox_gns3_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/gns3vm/virtualbox_gns3_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -228,7 +228,7 @@ try: resp = None resp = yield from session.get('http://127.0.0.1:{}/v2/compute/network/interfaces'.format(api_port)) - except (OSError, aiohttp.errors.ClientHttpProcessingError, TimeoutError): + except (OSError, aiohttp.errors.ClientHttpProcessingError, TimeoutError, asyncio.TimeoutError): pass if resp: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/gns3vm/vmware_gns3_vm.py new/gns3-server-2.0.3/gns3server/controller/gns3vm/vmware_gns3_vm.py --- old/gns3-server-2.0.0/gns3server/controller/gns3vm/vmware_gns3_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/gns3vm/vmware_gns3_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -118,7 +118,10 @@ if vmware_tools_state not in ("installed", "running"): raise GNS3VMError("VMware tools are not installed in {}".format(self.vmname)) - running = yield from self._is_running() + try: + running = yield from self._is_running() + except VMwareError as e: + raise GNS3VMError("Could not list VMware VMs: {}".format(str(e))) if not running: log.info("Update GNS3 VM settings") # set the number of vCPUs and amount of RAM diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/import_project.py new/gns3-server-2.0.3/gns3server/controller/import_project.py --- old/gns3-server-2.0.0/gns3server/controller/import_project.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/import_project.py 2017-06-13 10:35:50.000000000 +0200 @@ -24,7 +24,6 @@ import zipfile import aiohttp -from ..config import Config from .topology import load_topology @@ -74,7 +73,7 @@ path = location else: projects_path = controller.projects_directory() - path = os.path.join(projects_path, project_name) + path = os.path.join(projects_path, project_id) try: os.makedirs(path, exist_ok=True) except UnicodeEncodeError as e: @@ -114,7 +113,7 @@ # unless it's a linux host without GNS3 VM if not sys.platform.startswith("linux") or controller.has_compute("vm"): for node in topology["topology"]["nodes"]: - if node["node_type"] in ("docker", "qemu", "iou"): + if node["node_type"] in ("docker", "qemu", "iou", "nat"): node["compute_id"] = "vm" else: for node in topology["topology"]["nodes"]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/ports/port.py new/gns3-server-2.0.3/gns3server/controller/ports/port.py --- old/gns3-server-2.0.0/gns3server/controller/ports/port.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/ports/port.py 2017-06-13 10:35:50.000000000 +0200 @@ -70,6 +70,10 @@ return self._name return self.short_name_type + "{}/{}".format(self._interface_number, self._port_number) + @short_name.setter + def short_name(self, val): + self._short_name = val + def __json__(self): return { "name": self._name, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/ports/port_factory.py new/gns3-server-2.0.3/gns3server/controller/ports/port_factory.py --- old/gns3-server-2.0.0/gns3server/controller/ports/port_factory.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/ports/port_factory.py 2017-06-13 10:35:50.000000000 +0200 @@ -181,7 +181,9 @@ ports = [] adapter_number = 0 - wic_port_number = 16 + wic_slot = 1 + wic_port_number = wic_slot * 16 + display_wic_port_number = 0 for name in sorted(properties.keys()): if name.startswith("slot") and properties[name]: port_class = cls.ADAPTER_MATRIX[properties[name]]["port"] @@ -194,7 +196,13 @@ port_class = cls.WIC_MATRIX[properties[name]]["port"] if port_class: for port_number in range(0, cls.WIC_MATRIX[properties[name]]["nb_ports"]): - name = "{}{}/{}".format(port_class.long_name_type(), 0, wic_port_number) - ports.append(port_class(name, 0, 0, wic_port_number)) + name = "{}{}/{}".format(port_class.long_name_type(), 0, display_wic_port_number) + port = port_class(name, 0, 0, wic_port_number) + port.short_name = "{}{}/{}".format(port.short_name_type, 0, display_wic_port_number) + ports.append(port) + display_wic_port_number += 1 wic_port_number += 1 + wic_slot += 1 + wic_port_number = wic_slot * 16 + return ports diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/project.py new/gns3-server-2.0.3/gns3server/controller/project.py --- old/gns3-server-2.0.0/gns3server/controller/project.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/project.py 2017-06-13 10:35:50.000000000 +0200 @@ -675,7 +675,10 @@ self._loading = False # Should we start the nodes when project is open if self._auto_start: - yield from self.start_all() + # Start all in the background without waiting for completion + # we ignore errors because we want to let the user open + # their project and fix it + asyncio.async(self.start_all()) @asyncio.coroutine def wait_loaded(self): @@ -711,7 +714,7 @@ f.write(data) with open(os.path.join(tmpdir, "project.gns3p"), "rb") as f: project = yield from import_project(self._controller, str(uuid.uuid4()), f, location=location, name=name, keep_compute_id=True) - except OSError as e: + except (OSError, UnicodeEncodeError) as e: raise aiohttp.web.HTTPConflict(text="Can not duplicate project: {}".format(str(e))) if previous_status == "closed": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/symbols.py new/gns3-server-2.0.3/gns3server/controller/symbols.py --- old/gns3-server-2.0.0/gns3server/controller/symbols.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/symbols.py 2017-06-13 10:35:50.000000000 +0200 @@ -55,6 +55,8 @@ for file in os.listdir(directory): if file.startswith('.'): continue + if not os.path.isfile(os.path.join(directory, file)): + continue symbol_id = file symbols.append({ 'symbol_id': symbol_id, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/controller/topology.py new/gns3-server-2.0.3/gns3server/controller/topology.py --- old/gns3-server-2.0.0/gns3server/controller/topology.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/controller/topology.py 2017-06-13 10:35:50.000000000 +0200 @@ -125,7 +125,10 @@ if "revision" not in topo or topo["revision"] < GNS3_FILE_FORMAT_REVISION: # If it's an old GNS3 file we need to convert it # first we backup the file - shutil.copy(path, path + ".backup{}".format(topo.get("revision", 0))) + try: + shutil.copy(path, path + ".backup{}".format(topo.get("revision", 0))) + except (OSError) as e: + raise aiohttp.web.HTTPConflict(text="Can't write backup of the topology {}: {}".format(path, str(e))) changed = True if "revision" not in topo or topo["revision"] < 5: @@ -146,8 +149,11 @@ raise e if changed: - with open(path, "w+", encoding="utf-8") as f: - json.dump(topo, f, indent=4, sort_keys=True) + try: + with open(path, "w+", encoding="utf-8") as f: + json.dump(topo, f, indent=4, sort_keys=True) + except (OSError) as e: + raise aiohttp.web.HTTPConflict(text="Can't write the topology {}: {}".format(path, str(e))) return topo @@ -283,6 +289,10 @@ node["properties"] = {} + # Some old dynamips node don't have type + if "type" not in old_node: + old_node["type"] = old_node["properties"]["platform"].upper() + if old_node["type"] == "VPCSDevice": node["node_type"] = "vpcs" elif old_node["type"] == "QemuVM": @@ -300,7 +310,7 @@ node["console_type"] = None node["symbol"] = ":/symbols/hub.svg" node["properties"]["ports_mapping"] = [] - for port in old_node["ports"]: + for port in old_node.get("ports", []): node["properties"]["ports_mapping"].append({ "name": "Ethernet{}".format(port["port_number"] - 1), "port_number": port["port_number"] - 1 @@ -310,7 +320,7 @@ node["symbol"] = ":/symbols/ethernet_switch.svg" node["console_type"] = None node["properties"]["ports_mapping"] = [] - for port in old_node["ports"]: + for port in old_node.get("ports", []): node["properties"]["ports_mapping"].append({ "name": "Ethernet{}".format(port["port_number"] - 1), "port_number": port["port_number"] - 1, @@ -321,13 +331,15 @@ node["node_type"] = "frame_relay_switch" node["symbol"] = ":/symbols/frame_relay_switch.svg" node["console_type"] = None - elif old_node["type"] in ["C1700", "C2600", "C2691", "C3600", "C3725", "C3745", "C7200", "EtherSwitchRouter"]: + elif old_node["type"].upper() in ["C1700", "C2600", "C2691", "C3600", "C3620", "C3640", "C3660", "C3725", "C3745", "C7200", "EtherSwitchRouter"]: if node["symbol"] is None: node["symbol"] = ":/symbols/router.svg" node["node_type"] = "dynamips" node["properties"]["dynamips_id"] = old_node.get("dynamips_id") - if "platform" not in node["properties"] and old_node["type"].startswith("C"): + if "platform" not in node["properties"] and old_node["type"].upper().startswith("C"): node["properties"]["platform"] = old_node["type"].lower() + if node["properties"]["platform"].startswith("c36"): + node["properties"]["platform"] = "c3600" if "ram" not in node["properties"] and old_node["type"].startswith("C"): node["properties"]["ram"] = PLATFORMS_DEFAULT_RAM[old_node["type"].lower()] elif old_node["type"] == "VMwareVM": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/crash_report.py new/gns3-server-2.0.3/gns3server/crash_report.py --- old/gns3-server-2.0.0/gns3server/crash_report.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/crash_report.py 2017-06-13 10:35:50.000000000 +0200 @@ -54,7 +54,7 @@ Report crash to a third party service """ - DSN = "sync+https://fd4397dee2e145da9227af29df24ded1:[email protected]/38482" + DSN = "sync+https://9b15627f2ddf4e21a9880536354bfcb5:[email protected]/38482" if hasattr(sys, "frozen"): cacert = get_resource("cacert.pem") if cacert is not None and os.path.isfile(cacert): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/handlers/api/compute/project_handler.py new/gns3-server-2.0.3/gns3server/handlers/api/compute/project_handler.py --- old/gns3-server-2.0.0/gns3server/handlers/api/compute/project_handler.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/handlers/api/compute/project_handler.py 2017-06-13 10:35:50.000000000 +0200 @@ -112,7 +112,10 @@ if ProjectHandler._notifications_listening.setdefault(project.id, 0) <= 1: yield from project.close() pm.remove_project(project.id) - del ProjectHandler._notifications_listening[project.id] + try: + del ProjectHandler._notifications_listening[project.id] + except KeyError: + pass else: log.warning("Skip project closing, another client is listening for project notifications") response.set_status(204) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/handlers/api/controller/project_handler.py new/gns3-server-2.0.3/gns3server/handlers/api/controller/project_handler.py --- old/gns3-server-2.0.0/gns3server/handlers/api/controller/project_handler.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/handlers/api/controller/project_handler.py 2017-06-13 10:35:50.000000000 +0200 @@ -23,7 +23,6 @@ from gns3server.web.route import Route from gns3server.controller import Controller -from gns3server.controller.project import Project from gns3server.controller.import_project import import_project from gns3server.controller.export_project import export_project from gns3server.config import Config diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/schemas/dynamips_vm.py new/gns3-server-2.0.3/gns3server/schemas/dynamips_vm.py --- old/gns3-server-2.0.0/gns3server/schemas/dynamips_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/schemas/dynamips_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -33,7 +33,7 @@ }, "dynamips_id": { "description": "Dynamips ID", - "type": "integer" + "type": ["integer", "null"] }, "name": { "description": "Dynamips VM instance name", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/utils/interfaces.py new/gns3-server-2.0.3/gns3server/utils/interfaces.py --- old/gns3-server-2.0.0/gns3server/utils/interfaces.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/utils/interfaces.py 2017-06-13 10:35:50.000000000 +0200 @@ -198,12 +198,13 @@ results = [] if not sys.platform.startswith("win"): - for interface in sorted(psutil.net_if_addrs().keys()): + net_if_addrs = psutil.net_if_addrs() + for interface in sorted(net_if_addrs.keys()): ip_address = "" mac_address = "" netmask = "" interface_type = "ethernet" - for addr in psutil.net_if_addrs()[interface]: + for addr in net_if_addrs[interface]: # get the first available IPv4 address only if addr.family == socket.AF_INET: ip_address = addr.address diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/version.py new/gns3-server-2.0.3/gns3server/version.py --- old/gns3-server-2.0.0/gns3server/version.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/version.py 2017-06-13 10:35:50.000000000 +0200 @@ -23,7 +23,7 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.0.0" +__version__ = "2.0.3" # If it's a git checkout try to add the commit if "dev" in __version__: @@ -36,4 +36,4 @@ except Exception as e: print(e) -__version_info__ = (2, 0, 0, 0) +__version_info__ = (2, 0, 3, 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/web/logger.py new/gns3-server-2.0.3/gns3server/web/logger.py --- old/gns3-server-2.0.0/gns3server/web/logger.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/web/logger.py 2017-06-13 10:35:50.000000000 +0200 @@ -98,6 +98,16 @@ self.handleError(record) +class LogFilter: + """ + This filter some noise from the logs + """ + def filter(record): + if record.name == "aiohttp.access" and "/settings" in record.msg and "200" in record.msg: + return 0 + return 1 + + def init_logger(level, logfile=None, quiet=False): if logfile and len(logfile) > 0: stream_handler = logging.FileHandler(logfile) @@ -111,5 +121,7 @@ if quiet: stream_handler.addFilter(logging.Filter(name="user_facing")) logging.getLogger('user_facing').propagate = False + if level > logging.DEBUG: + stream_handler.addFilter(LogFilter) logging.basicConfig(level=level, handlers=[stream_handler]) return logging.getLogger('user_facing') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/gns3server/web/web_server.py new/gns3-server-2.0.3/gns3server/web/web_server.py --- old/gns3-server-2.0.0/gns3server/web/web_server.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/gns3server/web/web_server.py 2017-06-13 10:35:50.000000000 +0200 @@ -33,6 +33,7 @@ from ..config import Config from ..compute import MODULES from ..compute.port_manager import PortManager +from ..compute.qemu import Qemu from ..controller import Controller @@ -42,6 +43,9 @@ import logging log = logging.getLogger(__name__) +if not aiohttp.__version__.startswith("1.3"): + raise RuntimeError("You need aiohttp 1.3 for running GNS3") + class WebServer: @@ -192,6 +196,10 @@ Called when the HTTP server start """ yield from Controller.instance().start() + # Because with a large image collection + # without md5sum already computed we start the + # computing with server start + asyncio.async(Qemu.instance().list_images()) def run(self): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/init/gns3.conf.upstart new/gns3-server-2.0.3/init/gns3.conf.upstart --- old/gns3-server-2.0.0/init/gns3.conf.upstart 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/init/gns3.conf.upstart 2017-06-13 10:35:50.000000000 +0200 @@ -1,5 +1,6 @@ description "GNS3 server" author "GNS3 Team" +env LANG=en_US.UTF-8 start on filesystem or runlevel [2345] stop on shutdown diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/requirements.txt new/gns3-server-2.0.3/requirements.txt --- old/gns3-server-2.0.0/requirements.txt 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/requirements.txt 2017-06-13 10:35:50.000000000 +0200 @@ -6,3 +6,4 @@ raven>=5.23.0 psutil>=3.0.0 zipstream>=1.1.4 +typing>=3.5.3.0 # Otherwise yarl fail with python 3.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/scripts/remote-install.sh new/gns3-server-2.0.3/scripts/remote-install.sh --- old/gns3-server-2.0.0/scripts/remote-install.sh 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/scripts/remote-install.sh 2017-06-13 10:35:50.000000000 +0200 @@ -152,7 +152,7 @@ apt-get update log "Upgrade packages" -apt-get upgrade -y +apt-get upgrade --yes --force-yes -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" log " Install GNS3 packages" apt-get install -y gns3-server @@ -163,6 +163,10 @@ useradd -d /opt/gns3/ -m gns3 fi + +log "Add GNS3 to the ubridge group" +usermod -aG ubridge gns3 + log "Install docker" if [ ! -f "/usr/bin/docker" ] then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/setup.py new/gns3-server-2.0.3/setup.py --- old/gns3-server-2.0.0/setup.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/setup.py 2017-06-13 10:35:50.000000000 +0200 @@ -40,9 +40,6 @@ dependencies = open("requirements.txt", "r").read().splitlines() -if sys.version_info <= (3, 4): - dependencies.append('typing>=3.5.3.0 # Otherwise yarl fail with python 3.4') - setup( name="gns3-server", version=__import__("gns3server").__version__, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/compute/docker/test_docker_vm.py new/gns3-server-2.0.3/tests/compute/docker/test_docker_vm.py --- old/gns3-server-2.0.0/tests/compute/docker/test_docker_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/compute/docker/test_docker_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -840,7 +840,7 @@ @pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows") def test_mount_binds(vm, tmpdir): image_infos = { - "ContainerConfig": { + "Config": { "Volumes": { "/test/experimental": {} } @@ -879,7 +879,7 @@ with asyncio_patch("asyncio.subprocess.create_subprocess_exec", return_value=MagicMock()) as mock_exec: loop.run_until_complete(asyncio.async(vm._start_aux())) - mock_exec.assert_called_with('docker', 'exec', '-i', 'e90e34656842', '/gns3/bin/busybox', 'script', '-qfc', 'while true; do /gns3/bin/busybox sh; done', '/dev/null', stderr=asyncio.subprocess.STDOUT, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE) + mock_exec.assert_called_with('docker', 'exec', '-i', 'e90e34656842', '/gns3/bin/busybox', 'script', '-qfc', 'while true; do TERM=vt100 /gns3/bin/busybox sh; done', '/dev/null', stderr=asyncio.subprocess.STDOUT, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE) def test_create_network_interfaces(vm): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/compute/qemu/test_qemu_manager.py new/gns3-server-2.0.3/tests/compute/qemu/test_qemu_manager.py --- old/gns3-server-2.0.0/tests/compute/qemu/test_qemu_manager.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/compute/qemu/test_qemu_manager.py 2017-06-13 10:35:50.000000000 +0200 @@ -178,6 +178,26 @@ assert not process.called +def test_create_image_with_not_supported_characters_by_filesystem(loop, tmpdir, fake_qemu_img_binary): + open(str(tmpdir / "hda.qcow2"), "w+").close() + + options = { + "format": "raw", + "size": 100 + } + + # patching os.makedirs is necessary as it depends on already mocked os.path.exists + with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process, \ + patch("gns3server.compute.qemu.Qemu.get_images_directory", return_value=str(tmpdir)), \ + patch("os.path.exists", side_effect=UnicodeEncodeError('error', u"", 1, 2, 'Emulated Unicode Err')),\ + patch("os.makedirs"): + + with pytest.raises(QemuError): + loop.run_until_complete(asyncio.async(Qemu.instance().create_disk( + fake_qemu_img_binary, "hda.qcow2", options))) + assert not process.called + + def test_get_kvm_archs_kvm_ok(loop): with patch("os.path.exists", return_value=True): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/compute/virtualbox/test_virtualbox_vm.py new/gns3-server-2.0.3/tests/compute/virtualbox/test_virtualbox_vm.py --- old/gns3-server-2.0.0/tests/compute/virtualbox/test_virtualbox_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/compute/virtualbox/test_virtualbox_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -113,3 +113,15 @@ with open(vm._linked_vbox_file()) as f: c = f.read() assert "{" + vm.id + "}" in c + + +def test_patch_vm_uuid_with_corrupted_file(vm): + xml = """<?xml version="1.0"?> + <VirtualBox> + """ + os.makedirs(os.path.join(vm.working_dir, vm._vmname), exist_ok=True) + with open(vm._linked_vbox_file(), "w+") as f: + f.write(xml) + vm._linked_clone = True + with pytest.raises(VirtualBoxError): + vm._patch_vm_uuid() \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/compute/vpcs/test_vpcs_vm.py new/gns3-server-2.0.3/tests/compute/vpcs/test_vpcs_vm.py --- old/gns3-server-2.0.0/tests/compute/vpcs/test_vpcs_vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/compute/vpcs/test_vpcs_vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -251,6 +251,12 @@ assert f.read() == "set pcname pc1\n" +def test_update_startup_script_with_escaping_characters_in_name(vm): + vm.startup_script = "set pcname initial-name\n" + vm.name = "test\\" + assert vm.startup_script == "set pcname test\\\n" + + def test_get_startup_script(vm): content = "echo GNS3 VPCS\nip 192.168.1.2" vm.startup_script = content diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/controller/test_compute.py new/gns3-server-2.0.3/tests/controller/test_compute.py --- old/gns3-server-2.0.0/tests/controller/test_compute.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/controller/test_compute.py 2017-06-13 10:35:50.000000000 +0200 @@ -360,8 +360,10 @@ images = async_run(compute.images("qemu")) mock.assert_called_with("GET", "https://example.com:84/v2/compute/qemu/images", auth=None, data=None, headers={'content-type': 'application/json'}, chunked=False, timeout=None) - assert images == [{"filename": "linux.qcow2", "path": "linux.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0}, - {"filename": "asa.qcow2", "path": "asa.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0}] + assert images == [ + {"filename": "asa.qcow2", "path": "asa.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0}, + {"filename": "linux.qcow2", "path": "linux.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0} + ] def test_list_files(project, async_run, compute): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/controller/test_controller.py new/gns3-server-2.0.3/tests/controller/test_controller.py --- old/gns3-server-2.0.0/tests/controller/test_controller.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/controller/test_controller.py 2017-06-13 10:35:50.000000000 +0200 @@ -65,6 +65,16 @@ assert controller.gns3vm.settings["vmname"] == "Test VM" +def test_load_controller_settings_with_no_computes_section(controller, controller_config_path, async_run): + controller.save() + with open(controller_config_path) as f: + data = json.load(f) + del data['computes'] + with open(controller_config_path, "w+") as f: + json.dump(data, f) + assert len(async_run(controller._load_controller_settings())) == 0 + + def test_import_computes_1_x(controller, controller_config_path, async_run): """ At first start the server should import the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/controller/test_import_project.py new/gns3-server-2.0.3/tests/controller/test_import_project.py --- old/gns3-server-2.0.0/tests/controller/test_import_project.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/controller/test_import_project.py 2017-06-13 10:35:50.000000000 +0200 @@ -35,6 +35,8 @@ topology = { "project_id": str(uuid.uuid4()), "name": "test", + "auto_open": True, + "auto_start": True, "topology": { }, "version": "2.0.0" @@ -67,6 +69,8 @@ # A new project name is generated when you import twice the same name with open(zip_path, "rb") as f: project = async_run(import_project(controller, str(uuid.uuid4()), f)) + assert project.auto_open is False + assert project.auto_start is False assert project.name != "test" @@ -228,6 +232,50 @@ "name": "test", "properties": {} } + ], + "links": [], + "computes": [], + "drawings": [] + }, + "revision": 5, + "version": "2.0.0" + } + + with open(str(tmpdir / "project.gns3"), 'w+') as f: + json.dump(topology, f) + + zip_path = str(tmpdir / "project.zip") + with zipfile.ZipFile(zip_path, 'w') as myzip: + myzip.write(str(tmpdir / "project.gns3"), "project.gns3") + + with open(zip_path, "rb") as f: + project = async_run(import_project(controller, project_id, f)) + + with open(os.path.join(project.path, "test.gns3")) as f: + topo = json.load(f) + assert topo["topology"]["nodes"][0]["compute_id"] == "vm" + + +def test_import_nat_non_linux(windows_platform, async_run, tmpdir, controller): + """ + On non linux host NAT should be moved to the GNS3 VM + """ + project_id = str(uuid.uuid4()) + controller._computes["vm"] = AsyncioMagicMock() + + topology = { + "project_id": str(uuid.uuid4()), + "name": "test", + "type": "topology", + "topology": { + "nodes": [ + { + "compute_id": "local", + "node_id": "0fd3dd4d-dc93-4a04-a9b9-7396a9e22e8b", + "node_type": "nat", + "name": "test", + "properties": {} + } ], "links": [], "computes": [], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/controller/test_node_port_name.py new/gns3-server-2.0.3/tests/controller/test_node_port_name.py --- old/gns3-server-2.0.0/tests/controller/test_node_port_name.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/controller/test_node_port_name.py 2017-06-13 10:35:50.000000000 +0200 @@ -548,8 +548,8 @@ "link_type": "ethernet" }, { - "name": "Serial0/16", - "short_name": "s0/16", + "name": "Serial0/0", + "short_name": "s0/0", "data_link_types": { "Cisco HDLC": "DLT_C_HDLC", "Cisco PPP": "DLT_PPP_SERIAL", @@ -559,8 +559,8 @@ "link_type": "serial" }, { - "name": "Serial0/17", - "short_name": "s0/17", + "name": "Serial0/1", + "short_name": "s0/1", "data_link_types": { "Cisco HDLC": "DLT_C_HDLC", "Cisco PPP": "DLT_PPP_SERIAL", @@ -570,24 +570,24 @@ "link_type": "serial" }, { - "name": "Serial0/18", - "short_name": "s0/18", + "name": "Serial0/2", + "short_name": "s0/2", "data_link_types": { "Cisco HDLC": "DLT_C_HDLC", "Cisco PPP": "DLT_PPP_SERIAL", "Frame Relay": "DLT_FRELAY"}, - "port_number": 18, + "port_number": 32, "adapter_number": 0, "link_type": "serial" }, { - "name": "Serial0/19", - "short_name": "s0/19", + "name": "Serial0/3", + "short_name": "s0/3", "data_link_types": { "Cisco HDLC": "DLT_C_HDLC", "Cisco PPP": "DLT_PPP_SERIAL", "Frame Relay": "DLT_FRELAY"}, - "port_number": 19, + "port_number": 33, "adapter_number": 0, "link_type": "serial" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/controller/test_project.py new/gns3-server-2.0.3/tests/controller/test_project.py --- old/gns3-server-2.0.0/tests/controller/test_project.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/controller/test_project.py 2017-06-13 10:35:50.000000000 +0200 @@ -23,6 +23,7 @@ import pytest import aiohttp import zipfile +import zipstream from unittest.mock import MagicMock from tests.utils import AsyncioMagicMock, asyncio_patch from unittest.mock import patch @@ -439,6 +440,15 @@ assert list(new_project.nodes.values())[1].compute.id == "remote" +def test_duplicate_with_zipfile_encoding_issues(project, async_run, controller): + zf = zipstream.ZipFile() + zf.writestr('test\udcc3', "data") + + with asyncio_patch('gns3server.controller.project.export_project', return_value=zf): + with pytest.raises(aiohttp.web.HTTPConflict): + async_run(project.duplicate(name="Hello")) + + def test_snapshots(project): """ List the snapshots diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/handlers/api/controller/test_gns3vm.py new/gns3-server-2.0.3/tests/handlers/api/controller/test_gns3vm.py --- old/gns3-server-2.0.0/tests/handlers/api/controller/test_gns3vm.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/handlers/api/controller/test_gns3vm.py 2017-06-13 10:35:50.000000000 +0200 @@ -46,4 +46,3 @@ def test_get_gns3vm(http_controller): response = http_controller.get('/gns3vm', example=True) assert response.status == 200 - print(response.json) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/topologies/1_3_dynamips_missing_type/after/1_3_dynamips.gns3 new/gns3-server-2.0.3/tests/topologies/1_3_dynamips_missing_type/after/1_3_dynamips.gns3 --- old/gns3-server-2.0.0/tests/topologies/1_3_dynamips_missing_type/after/1_3_dynamips.gns3 1970-01-01 01:00:00.000000000 +0100 +++ new/gns3-server-2.0.3/tests/topologies/1_3_dynamips_missing_type/after/1_3_dynamips.gns3 2017-06-13 10:35:50.000000000 +0200 @@ -0,0 +1,77 @@ +{ + "auto_start": false, + "name": "1_3_dynamips", + "project_id": "ba5790e1-2f51-443e-a3cc-1a2eee132888", + "revision": 6, + "topology": { + "computes": [ + { + "compute_id": "local", + "host": "127.0.0.1", + "name": "Local", + "port": 8000, + "protocol": "http" + } + ], + "drawings": [], + "links": [], + "nodes": [ + { + "symbol": ":/symbols/iosv_virl.svg", + "compute_id": "local", + "console": 2001, + "console_type": "telnet", + "label": { + "rotation": 0, + "style": "font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #000000;fill-opacity: 1.0;", + "text": "R1", + "x": 22, + "y": -25 + }, + "name": "R1", + "node_id": "0bce6ad5-c688-4d4d-a425-f21aaf3927e2", + "node_type": "dynamips", + "port_name_format": "Ethernet{0}", + "port_segment_size": 0, + "first_port_name": null, + "properties": { + "dynamips_id": 1, + "auto_delete_disks": true, + "clock_divisor": 4, + "disk0": 0, + "disk1": 0, + "exec_area": 64, + "idlemax": 500, + "idlesleep": 30, + "image": "c7200-adventerprisek9-mz.124-24.T8.image", + "mac_addr": "ca01.2f39.0000", + "midplane": "vxr", + "mmap": true, + "npe": "npe-400", + "nvram": 512, + "platform": "c7200", + "power_supplies": [ + 1, + 1 + ], + "ram": 512, + "sensors": [ + 22, + 22, + 22, + 22 + ], + "slot0": "C7200-IO-FE", + "sparsemem": true, + "startup_config": "configs/i1_startup-config.cfg", + "system_id": "FTX0945W0MY" + }, + "x": -112, + "y": -100, + "z": 1 + } + ] + }, + "type": "topology", + "version": "ANYSTR" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/topologies/1_3_dynamips_missing_type/before/1_3_dynamips.gns3 new/gns3-server-2.0.3/tests/topologies/1_3_dynamips_missing_type/before/1_3_dynamips.gns3 --- old/gns3-server-2.0.0/tests/topologies/1_3_dynamips_missing_type/before/1_3_dynamips.gns3 1970-01-01 01:00:00.000000000 +0100 +++ new/gns3-server-2.0.3/tests/topologies/1_3_dynamips_missing_type/before/1_3_dynamips.gns3 2017-06-13 10:35:50.000000000 +0200 @@ -0,0 +1,80 @@ +{ + "auto_start": false, + "name": "1_3_dynamips", + "project_id": "ba5790e1-2f51-443e-a3cc-1a2eee132888", + "revision": 3, + "topology": { + "nodes": [ + { + "default_symbol": ":/symbols/iosv_virl.normal.svg", + "description": "Router c7200", + "dynamips_id": 1, + "hover_symbol": ":/symbols/iosv_virl.selected.svg", + "id": 1, + "label": { + "color": "#000000", + "font": "TypeWriter,10,-1,5,75,0,0,0,0,0", + "text": "R1", + "x": 22.6171875, + "y": -25.0 + }, + "ports": [ + { + "adapter_number": 0, + "id": 1, + "name": "FastEthernet0/0", + "port_number": 0 + } + ], + "properties": { + "auto_delete_disks": true, + "clock_divisor": 4, + "console": 2001, + "disk0": 0, + "disk1": 0, + "exec_area": 64, + "idlemax": 500, + "idlesleep": 30, + "image": "c7200-adventerprisek9-mz.124-24.T8.image", + "mac_addr": "ca01.2f39.0000", + "midplane": "vxr", + "mmap": true, + "name": "R1", + "npe": "npe-400", + "nvram": 512, + "platform": "c7200", + "power_supplies": [ + 1, + 1 + ], + "ram": 512, + "sensors": [ + 22, + 22, + 22, + 22 + ], + "slot0": "C7200-IO-FE", + "sparsemem": true, + "startup_config": "configs/i1_startup-config.cfg", + "system_id": "FTX0945W0MY" + }, + "server_id": 1, + "vm_id": "0bce6ad5-c688-4d4d-a425-f21aaf3927e2", + "x": -112.0, + "y": -100.0 + } + ], + "servers": [ + { + "cloud": false, + "host": "127.0.0.1", + "id": 1, + "local": true, + "port": 8000 + } + ] + }, + "type": "topology", + "version": "1.3.13" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gns3-server-2.0.0/tests/utils.py new/gns3-server-2.0.3/tests/utils.py --- old/gns3-server-2.0.0/tests/utils.py 2017-05-02 10:16:11.000000000 +0200 +++ new/gns3-server-2.0.3/tests/utils.py 2017-06-13 10:35:50.000000000 +0200 @@ -16,6 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import io +import types import asyncio import unittest.mock @@ -69,6 +70,10 @@ """ Magic mock returning coroutine """ + try: + __class__ = types.CoroutineType + except AttributeError: # Not supported with Python 3.4 + __class__ = types.GeneratorType def __init__(self, return_value=None, return_values=None, **kwargs): """
