From 88cd8042741c75968551aea4f7994e6ec8523cfa Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 2 Jun 2017 11:40:39 +0200 Subject: [PATCH 01/13] Update readme --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 8d6fd28b..0f58de70 100644 --- a/README.rst +++ b/README.rst @@ -22,7 +22,7 @@ master 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 From e0b519eced6b97e4e15353a97421c9dfaac4d562 Mon Sep 17 00:00:00 2001 From: ziajka Date: Wed, 7 Jun 2017 10:50:40 +0200 Subject: [PATCH 02/13] Fix when config file doesn't have computes section (#1062) --- gns3server/controller/__init__.py | 4 ++-- tests/controller/test_controller.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/gns3server/controller/__init__.py b/gns3server/controller/__init__.py index 611755c4..59ed9712 100644 --- a/gns3server/controller/__init__.py +++ b/gns3server/controller/__init__.py @@ -82,7 +82,7 @@ class Controller: 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: @@ -176,7 +176,7 @@ class Controller: if "gns3vm" in data: self.gns3vm.settings = data["gns3vm"] - return data["computes"] + return data.get("computes", []) @asyncio.coroutine def load_projects(self): diff --git a/tests/controller/test_controller.py b/tests/controller/test_controller.py index f31fa999..e240c5b4 100644 --- a/tests/controller/test_controller.py +++ b/tests/controller/test_controller.py @@ -65,6 +65,16 @@ def test_load_controller_settings(controller, controller_config_path, async_run) 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 From eb6068c3d3371bd3c0c5324526d2fe6b2f1885ea Mon Sep 17 00:00:00 2001 From: ziajka Date: Wed, 7 Jun 2017 12:35:41 +0200 Subject: [PATCH 03/13] Fix Qemu disk creation with unicode characters not supported by local filesystem #1058 (#1063) --- gns3server/compute/qemu/__init__.py | 9 +++++++-- tests/compute/qemu/test_qemu_manager.py | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/gns3server/compute/qemu/__init__.py b/gns3server/compute/qemu/__init__.py index 2bf9f04b..fd06605c 100644 --- a/gns3server/compute/qemu/__init__.py +++ b/gns3server/compute/qemu/__init__.py @@ -247,8 +247,13 @@ class Qemu(BaseManager): 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 --git a/tests/compute/qemu/test_qemu_manager.py b/tests/compute/qemu/test_qemu_manager.py index cd71999a..6a0eb9e5 100644 --- a/tests/compute/qemu/test_qemu_manager.py +++ b/tests/compute/qemu/test_qemu_manager.py @@ -178,6 +178,26 @@ def test_create_image_exist(loop, tmpdir, fake_qemu_img_binary): 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): From 40cc5d76b33e457022f2fb2703ca9ba4e52bfa85 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Wed, 7 Jun 2017 15:55:50 +0200 Subject: [PATCH 04/13] Fix racecondition when listing interface Fix #1060 --- gns3server/utils/interfaces.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gns3server/utils/interfaces.py b/gns3server/utils/interfaces.py index af792cf2..c1000f55 100644 --- a/gns3server/utils/interfaces.py +++ b/gns3server/utils/interfaces.py @@ -198,12 +198,13 @@ def interfaces(): 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 From 7235a312abd1a7314f47463e0704da4f48dec166 Mon Sep 17 00:00:00 2001 From: ziajka Date: Thu, 8 Jun 2017 15:23:18 +0200 Subject: [PATCH 05/13] Escaping VPCS name in regex #1067 --- gns3server/compute/vpcs/vpcs_vm.py | 3 ++- tests/compute/vpcs/test_vpcs_vm.py | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/gns3server/compute/vpcs/vpcs_vm.py b/gns3server/compute/vpcs/vpcs_vm.py index 0c8c9ebc..6b6629bf 100644 --- a/gns3server/compute/vpcs/vpcs_vm.py +++ b/gns3server/compute/vpcs/vpcs_vm.py @@ -171,7 +171,8 @@ class VPCSVM(BaseNode): 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 --git a/tests/compute/vpcs/test_vpcs_vm.py b/tests/compute/vpcs/test_vpcs_vm.py index b36ac1c9..e08f537f 100644 --- a/tests/compute/vpcs/test_vpcs_vm.py +++ b/tests/compute/vpcs/test_vpcs_vm.py @@ -251,6 +251,12 @@ def test_update_startup_script_h(vm): 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 From 0dd35e1cbee2ce606ac369bca428f3a1481e8f23 Mon Sep 17 00:00:00 2001 From: ziajka Date: Thu, 8 Jun 2017 15:25:08 +0200 Subject: [PATCH 06/13] Ignoring virtualenv directory at gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 093b8deb..c1434d71 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ docs/_build vpcs.hist startup.vpcs .gns3_shell_history + +# Virtualenv +env \ No newline at end of file From c1c3a9ed80ac81628df182cf6088351884a72ced Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 9 Jun 2017 09:28:45 +0200 Subject: [PATCH 07/13] Drop debug --- tests/handlers/api/controller/test_gns3vm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/handlers/api/controller/test_gns3vm.py b/tests/handlers/api/controller/test_gns3vm.py index 21e156d2..5502caba 100644 --- a/tests/handlers/api/controller/test_gns3vm.py +++ b/tests/handlers/api/controller/test_gns3vm.py @@ -46,4 +46,3 @@ def test_put_gns3vm(http_controller): def test_get_gns3vm(http_controller): response = http_controller.get('/gns3vm', example=True) assert response.status == 200 - print(response.json) From 5c0d9551564770a417ec85e1687dcfa98acb6c8f Mon Sep 17 00:00:00 2001 From: ziajka Date: Fri, 9 Jun 2017 09:57:47 +0200 Subject: [PATCH 08/13] Fix: #1066 - Catching parsing errors at linked vbox file --- gns3server/compute/virtualbox/virtualbox_vm.py | 7 ++++++- tests/compute/virtualbox/test_virtualbox_vm.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/gns3server/compute/virtualbox/virtualbox_vm.py b/gns3server/compute/virtualbox/virtualbox_vm.py index ecd7ef2c..6f13b8d6 100644 --- a/gns3server/compute/virtualbox/virtualbox_vm.py +++ b/gns3server/compute/virtualbox/virtualbox_vm.py @@ -209,7 +209,12 @@ class VirtualBoxVM(BaseNode): 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 + "}": diff --git a/tests/compute/virtualbox/test_virtualbox_vm.py b/tests/compute/virtualbox/test_virtualbox_vm.py index ef617fe4..b2300280 100644 --- a/tests/compute/virtualbox/test_virtualbox_vm.py +++ b/tests/compute/virtualbox/test_virtualbox_vm.py @@ -113,3 +113,15 @@ def test_patch_vm_uuid(vm): 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 = """ + + """ + 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 From 64a852f38f6205719068a25539084bfb7db42133 Mon Sep 17 00:00:00 2001 From: ziajka Date: Fri, 9 Jun 2017 15:28:24 +0200 Subject: [PATCH 09/13] Fixes #1068 - handle zipfile encoding issues at project duplication --- gns3server/controller/project.py | 2 +- tests/controller/test_project.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index 3cf17af8..c185cccd 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -714,7 +714,7 @@ class Project: 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 --git a/tests/controller/test_project.py b/tests/controller/test_project.py index 4422c0d1..24d019f5 100644 --- a/tests/controller/test_project.py +++ b/tests/controller/test_project.py @@ -23,6 +23,7 @@ import json 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 @@ def test_duplicate(project, async_run, controller): 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 From 41af46cdc5ba5fa75805f10c8d97d93255aa3b30 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Tue, 13 Jun 2017 10:35:50 +0200 Subject: [PATCH 10/13] 2.0.3 release --- CHANGELOG | 11 +++++++++++ gns3server/crash_report.py | 2 +- gns3server/version.py | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8ea402eb..563812f0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,16 @@ # 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 diff --git a/gns3server/crash_report.py b/gns3server/crash_report.py index 77ae01f4..a2e44ec6 100644 --- a/gns3server/crash_report.py +++ b/gns3server/crash_report.py @@ -54,7 +54,7 @@ class CrashReport: Report crash to a third party service """ - DSN = "sync+https://67b93949a78d4ef5978388cc4b8906f9:271ee1dd01db4a39b919097f452cb6c5@sentry.io/38482" + DSN = "sync+https://9b15627f2ddf4e21a9880536354bfcb5:b31dee5d3abf4c74844895432193d0ac@sentry.io/38482" if hasattr(sys, "frozen"): cacert = get_resource("cacert.pem") if cacert is not None and os.path.isfile(cacert): diff --git a/gns3server/version.py b/gns3server/version.py index a5999586..fd5abfb4 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,7 +23,7 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.0.3dev1" +__version__ = "2.0.3" # If it's a git checkout try to add the commit if "dev" in __version__: @@ -36,4 +36,4 @@ if "dev" in __version__: except Exception as e: print(e) -__version_info__ = (2, 0, 3, -99) +__version_info__ = (2, 0, 3, 0) From b8a4785633382513cfb17f7bddd02c82da770846 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Tue, 13 Jun 2017 10:37:41 +0200 Subject: [PATCH 11/13] 2.0.4dev1 --- gns3server/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/version.py b/gns3server/version.py index fd5abfb4..85720a29 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,7 +23,7 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.0.3" +__version__ = "2.0.4dev1" # If it's a git checkout try to add the commit if "dev" in __version__: @@ -36,4 +36,4 @@ if "dev" in __version__: except Exception as e: print(e) -__version_info__ = (2, 0, 3, 0) +__version_info__ = (2, 0, 4, -99) From 734ca7d2f9aede701f96415d7895a93772f9e595 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Mon, 19 Jun 2017 10:49:23 +0200 Subject: [PATCH 12/13] Fix linked base & linked clone settings in appliance --- gns3server/controller/appliance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/controller/appliance.py b/gns3server/controller/appliance.py index 8960233b..9cfb00f0 100644 --- a/gns3server/controller/appliance.py +++ b/gns3server/controller/appliance.py @@ -42,8 +42,8 @@ class Appliance: # Version of the gui before 2.1 use linked_base # and the server linked_clone - if "linked_base" in data: - self._data["linked_clone"] = data.pop("linked_base") + if "linked_base" in self._data: + self._data["linked_clone"] = self._data.pop("linked_base") if data["node_type"] == "iou" and "image" in data: del self._data["image"] self._builtin = builtin From e1c20e6a22c4492a4576adaf6ae1279420d128a9 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Mon, 19 Jun 2017 10:50:45 +0200 Subject: [PATCH 13/13] Fix merge 2.0 error --- tests/controller/test_project.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/controller/test_project.py b/tests/controller/test_project.py index e921e003..0c9a929f 100644 --- a/tests/controller/test_project.py +++ b/tests/controller/test_project.py @@ -20,6 +20,7 @@ import os import sys import pytest import aiohttp +import zipstream from unittest.mock import MagicMock from tests.utils import AsyncioMagicMock, asyncio_patch from unittest.mock import patch