Merge remote-tracking branch 'origin/master' into 2.1

pull/1081/head
Julien Duponchelle 7 years ago
commit bb8097a052
No known key found for this signature in database
GPG Key ID: CE8B29639E07F5E8

3
.gitignore vendored

@ -53,3 +53,6 @@ docs/_build
vpcs.hist
startup.vpcs
.gns3_shell_history
# Virtualenv
env

@ -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

@ -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

@ -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()):

@ -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 + "}":

@ -169,7 +169,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)

@ -154,7 +154,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:
@ -249,7 +249,7 @@ class Controller:
self.gns3vm.settings = data["gns3vm"]
self.load_appliances()
return data["computes"]
return data.get("computes", [])
@asyncio.coroutine
def load_projects(self):

@ -738,7 +738,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":

@ -57,7 +57,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):

@ -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

@ -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):
@ -185,7 +205,7 @@ def test_get_kvm_archs_kvm_ok(loop):
if platform.machine() == 'x86_64':
assert archs == ['x86_64', 'i386']
else:
assert archs == [ platform.machine() ]
assert archs == [platform.machine()]
with patch("os.path.exists", return_value=False):
archs = loop.run_until_complete(asyncio.async(Qemu.get_kvm_archs()))

@ -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 = """<?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()

@ -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

@ -62,6 +62,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

@ -473,6 +473,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

@ -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)

Loading…
Cancel
Save