mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-06-07 11:06:28 +03:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ff2b5f546 | ||
|
|
f5e2309563 | ||
|
|
75aa6d50b3 | ||
|
|
021ad2a5c2 | ||
|
|
ffe486e284 | ||
|
|
6132aa7864 | ||
|
|
56e55d9cd6 | ||
|
|
2f0e91d96e | ||
|
|
32a45ad0d3 | ||
|
|
f0d0d6b73a | ||
|
|
03c470846b | ||
|
|
66f347c973 | ||
|
|
1cf8cae166 | ||
|
|
f2585438bd | ||
|
|
f1e2c5b0d1 | ||
|
|
466ba18ec8 | ||
|
|
844fb2e6ec | ||
|
|
41d8e2a0ae | ||
|
|
49ea016980 | ||
|
|
34a8972ce4 | ||
|
|
a980e1910c | ||
|
|
10758879db | ||
|
|
1e0986b1f6 | ||
|
|
57e16f46ce | ||
|
|
cc076cc803 | ||
|
|
254262c5c4 | ||
|
|
dc8279c3ea | ||
|
|
d34d9316f3 | ||
|
|
7496b1de21 |
35
CHANGELOG
35
CHANGELOG
@@ -1,5 +1,40 @@
|
||||
# Change Log
|
||||
|
||||
## 1.3.1 11/04/2015
|
||||
|
||||
* Release
|
||||
|
||||
## 1.3.1rc4 09/04/2015
|
||||
|
||||
* Fix crash when save as can't create a directory
|
||||
* Allow less strict dependencies
|
||||
|
||||
## 1.3.1rc3 07/04/2015
|
||||
|
||||
* Send HTTP errors 400 to the crash report system
|
||||
|
||||
## 1.3.1rc2 06/04/2015
|
||||
|
||||
* Fix race condition during old project import
|
||||
|
||||
## 1.3.1rc1 05/04/2015
|
||||
|
||||
* Fix rare occasion when user manage to put text in port field
|
||||
* Fix a crash when exporting vpcs startup script
|
||||
* Fix an issue with sending iourc when a topologies is reloaded
|
||||
* Solve issue when iourc contains non ascii characters
|
||||
* Handle corrupted zip file with IOS image
|
||||
* Don't crash if we try to contact a non GNS3 remote server returning JSON
|
||||
* Skip tests in package
|
||||
* Check port range
|
||||
* Add a warning about too much ram for IOS
|
||||
* Fix crash if project is already closed
|
||||
* Check if wait for connection thread still running before emitting a signal.
|
||||
* Check if process files thread still running before emitting a signal.
|
||||
* Raven is an optionnal dependencies for Debian
|
||||
* Fix crash if a dumped topology as no node during save as
|
||||
* Fix: remove old ID references for ATM and Frame-Relay switches.
|
||||
|
||||
## 1.3.0 30/03/2015
|
||||
|
||||
* Fix etherswitch router
|
||||
|
||||
@@ -5,7 +5,6 @@ include LICENSE
|
||||
include MANIFEST.in
|
||||
include tox.ini
|
||||
recursive-exclude tests *
|
||||
recursive-include docs *
|
||||
recursive-include gns3 *
|
||||
recursive-exclude * __pycache__
|
||||
recursive-exclude * *.py[co]
|
||||
|
||||
@@ -17,9 +17,16 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import raven
|
||||
import struct
|
||||
import platform
|
||||
import struct
|
||||
|
||||
try:
|
||||
import raven
|
||||
RAVEN_AVAILABLE = True
|
||||
except ImportError:
|
||||
# raven is not installed with deb package in order to simplify packaging
|
||||
RAVEN_AVAILABLE = False
|
||||
|
||||
|
||||
from .version import __version__
|
||||
from .servers import Servers
|
||||
@@ -34,7 +41,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "sync+https://2e90f3a4dc094b39a94864ae1ced969c:fc65363ea35245f28ae2b7205de744c9@app.getsentry.com/38506"
|
||||
DSN = "sync+https://93967ffc7e08401fa0b7578ecf08256b:8c0a5bcbc99e42f1819c6870d6362122@app.getsentry.com/38506"
|
||||
if hasattr(sys, "frozen"):
|
||||
cacert = os.path.join(os.getcwd(), "cacert.pem")
|
||||
if os.path.isfile(cacert):
|
||||
@@ -47,6 +54,8 @@ class CrashReport:
|
||||
self._client = None
|
||||
|
||||
def captureException(self, exception, value, tb):
|
||||
if not RAVEN_AVAILABLE:
|
||||
return
|
||||
local_server = Servers.instance().localServerSettings()
|
||||
if local_server["report_errors"]:
|
||||
if self._client is None:
|
||||
|
||||
@@ -30,6 +30,10 @@ import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HttpBadRequest(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class HTTPClient(QtCore.QObject):
|
||||
|
||||
"""
|
||||
@@ -258,6 +262,14 @@ class HTTPClient(QtCore.QObject):
|
||||
if callback is not None:
|
||||
callback({"message": msg}, error=True, server=self)
|
||||
return
|
||||
|
||||
if "version" not in params or "local" not in params:
|
||||
msg = "The remote server {}://{}:{} is not a GNS 3 server".format(self.scheme, self.host, self.port)
|
||||
log.error(msg)
|
||||
if callback is not None:
|
||||
callback({"message": msg}, error=True, server=self)
|
||||
return
|
||||
|
||||
if params["version"] != __version__:
|
||||
msg = "Client version {} differs with server version {}".format(__version__, params["version"])
|
||||
log.error(msg)
|
||||
@@ -325,12 +337,17 @@ class HTTPClient(QtCore.QObject):
|
||||
|
||||
def _processResponse(self, response, callback, context):
|
||||
|
||||
status = None
|
||||
body = None
|
||||
|
||||
if "query_id" in context:
|
||||
self.notify_progress_end_query(context["query_id"])
|
||||
if response.error() != QtNetwork.QNetworkReply.NoError:
|
||||
error_code = response.error()
|
||||
if error_code < 200:
|
||||
self._connected = False
|
||||
else:
|
||||
status = response.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute)
|
||||
error_message = response.errorString()
|
||||
log.info("Response error: {}".format(error_message))
|
||||
body = bytes(response.readAll()).decode()
|
||||
@@ -357,6 +374,8 @@ class HTTPClient(QtCore.QObject):
|
||||
else:
|
||||
callback(params, server=self, context=context)
|
||||
response.deleteLater()
|
||||
if status == 400:
|
||||
raise HttpBadRequest(body)
|
||||
|
||||
def dump(self):
|
||||
"""
|
||||
|
||||
@@ -1293,7 +1293,7 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError as e:
|
||||
QtGui.QMessageBox.critical(self, "Save project", "Could not create project directory {}: {}".format(project_dir), e)
|
||||
QtGui.QMessageBox.critical(self, "Save project", "Could not create project directory {}: {}".format(project_dir, e))
|
||||
return
|
||||
|
||||
if self._project.temporary():
|
||||
|
||||
@@ -128,8 +128,7 @@ class ATMSwitch(Device):
|
||||
if self.hasAllocatedName(new_settings["name"]):
|
||||
self.error_signal.emit(self.id(), 'Name "{}" is already used by another node'.format(new_settings["name"]))
|
||||
return
|
||||
params = {"id": self._atmsw_id,
|
||||
"name": new_settings["name"]}
|
||||
params["name"] = new_settings["name"]
|
||||
updated = True
|
||||
|
||||
if updated:
|
||||
|
||||
@@ -129,8 +129,7 @@ class FrameRelaySwitch(Device):
|
||||
if self.hasAllocatedName(new_settings["name"]):
|
||||
self.error_signal.emit(self.id(), 'Name "{}" is already used by another node'.format(new_settings["name"]))
|
||||
return
|
||||
params = {"id": self._frsw_id,
|
||||
"name": new_settings["name"]}
|
||||
params["name"] = new_settings["name"]
|
||||
updated = True
|
||||
|
||||
if updated:
|
||||
|
||||
@@ -308,7 +308,7 @@ class IOSRouterPreferencesPage(QtGui.QWidget, Ui_IOSRouterPreferencesPageWidget)
|
||||
decompressed_size += zip_info.file_size
|
||||
else:
|
||||
decompressed_size = os.path.getsize(path)
|
||||
except OSError:
|
||||
except (zipfile.BadZipFile, OSError):
|
||||
return 0
|
||||
|
||||
# get the size in MB
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>517</width>
|
||||
<width>585</width>
|
||||
<height>398</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -197,7 +197,7 @@
|
||||
<string>Memory</string>
|
||||
</property>
|
||||
<property name="subTitle">
|
||||
<string>Please check the amount of memory (RAM) that you allocate to IOS. Not enough RAM could prevent IOS to start.</string>
|
||||
<string>Please check the amount of memory (RAM) that you allocate to IOS. Too much or not enough RAM could prevent IOS to start.</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
@@ -239,10 +239,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><a href="http://tools.cisco.com/ITDIT/CFN/jsp/SearchBySoftware.jsp"><span style=" text-decoration: underline; color:#0000ff;">Check for minimum RAM requirement</span></a></p></body></html></string>
|
||||
<string><html><head/><body><p><a href="http://tools.cisco.com/ITDIT/CFN/jsp/SearchBySoftware.jsp"><span style=" text-decoration: underline; color:#0000ff;">Check for minimum and maximum RAM requirement</span></a></p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/modules/dynamips/ui/ios_router_wizard.ui'
|
||||
# Form implementation generated from reading ui file '/Users/noplay/code/gns3/gns3-gui/gns3/modules/dynamips/ui/ios_router_wizard.ui'
|
||||
#
|
||||
# Created: Fri Mar 13 11:09:58 2015
|
||||
# by: PyQt4 UI code generator 4.10.4
|
||||
# Created: Wed Apr 1 15:15:16 2015
|
||||
# by: PyQt4 UI code generator 4.11.3
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
@@ -26,7 +26,7 @@ except AttributeError:
|
||||
class Ui_IOSRouterWizard(object):
|
||||
def setupUi(self, IOSRouterWizard):
|
||||
IOSRouterWizard.setObjectName(_fromUtf8("IOSRouterWizard"))
|
||||
IOSRouterWizard.resize(517, 398)
|
||||
IOSRouterWizard.resize(585, 398)
|
||||
IOSRouterWizard.setModal(True)
|
||||
self.uiServerWizardPage = QtGui.QWizardPage()
|
||||
self.uiServerWizardPage.setObjectName(_fromUtf8("uiServerWizardPage"))
|
||||
@@ -141,7 +141,7 @@ class Ui_IOSRouterWizard(object):
|
||||
self.label.setWordWrap(False)
|
||||
self.label.setOpenExternalLinks(True)
|
||||
self.label.setObjectName(_fromUtf8("label"))
|
||||
self.gridLayout_2.addWidget(self.label, 1, 0, 1, 2)
|
||||
self.gridLayout_2.addWidget(self.label, 1, 0, 1, 3)
|
||||
IOSRouterWizard.addPage(self.uiMemoryWizardPage)
|
||||
self.uiNetworkAdaptersWizardPage = QtGui.QWizardPage()
|
||||
self.uiNetworkAdaptersWizardPage.setObjectName(_fromUtf8("uiNetworkAdaptersWizardPage"))
|
||||
@@ -304,11 +304,11 @@ class Ui_IOSRouterWizard(object):
|
||||
self.uiChassisLabel.setText(_translate("IOSRouterWizard", "Chassis:", None))
|
||||
self.uiEtherSwitchCheckBox.setText(_translate("IOSRouterWizard", "This is an EtherSwitch router", None))
|
||||
self.uiMemoryWizardPage.setTitle(_translate("IOSRouterWizard", "Memory", None))
|
||||
self.uiMemoryWizardPage.setSubTitle(_translate("IOSRouterWizard", "Please check the amount of memory (RAM) that you allocate to IOS. Not enough RAM could prevent IOS to start.", None))
|
||||
self.uiMemoryWizardPage.setSubTitle(_translate("IOSRouterWizard", "Please check the amount of memory (RAM) that you allocate to IOS. Too much or not enough RAM could prevent IOS to start.", None))
|
||||
self.uiRamLabel.setText(_translate("IOSRouterWizard", "Default RAM:", None))
|
||||
self.uiRamSpinBox.setSuffix(_translate("IOSRouterWizard", " MiB", None))
|
||||
self.uiTestIOSImagePushButton.setText(_translate("IOSRouterWizard", "&Test IOS image", None))
|
||||
self.label.setText(_translate("IOSRouterWizard", "<html><head/><body><p><a href=\"http://tools.cisco.com/ITDIT/CFN/jsp/SearchBySoftware.jsp\"><span style=\" text-decoration: underline; color:#0000ff;\">Check for minimum RAM requirement</span></a></p></body></html>", None))
|
||||
self.label.setText(_translate("IOSRouterWizard", "<html><head/><body><p><a href=\"http://tools.cisco.com/ITDIT/CFN/jsp/SearchBySoftware.jsp\"><span style=\" text-decoration: underline; color:#0000ff;\">Check for minimum and maximum RAM requirement</span></a></p></body></html>", None))
|
||||
self.uiNetworkAdaptersWizardPage.setTitle(_translate("IOSRouterWizard", "Network adapters", None))
|
||||
self.uiNetworkAdaptersWizardPage.setSubTitle(_translate("IOSRouterWizard", "Please choose the default network adapters that should be inserted into every new instance of this router.", None))
|
||||
self.uiSlot0Label.setText(_translate("IOSRouterWizard", "slot 0:", None))
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
Thread to wait for an IOS image to be decompressed.
|
||||
"""
|
||||
|
||||
import zipfile
|
||||
|
||||
from gns3.qt import QtCore
|
||||
from .decompress_ios import decompressIOS
|
||||
|
||||
@@ -52,6 +54,9 @@ class DecompressIOSThread(QtCore.QThread):
|
||||
self._is_running = True
|
||||
try:
|
||||
decompressIOS(self._ios_image, self._destination_file)
|
||||
except zipfile.BadZipFile as e:
|
||||
self.error.emit("File {} is corrupted {}".format(self._ios_image, e), True)
|
||||
return
|
||||
except OSError as e:
|
||||
self.error.emit("Could not decompress {}: {}".format(self._ios_image, e), True)
|
||||
return
|
||||
|
||||
@@ -282,8 +282,8 @@ class IOU(Module):
|
||||
|
||||
if len(self._settings["iourc_path"]) > 0:
|
||||
try:
|
||||
with open(self._settings["iourc_path"]) as f:
|
||||
settings["iourc_content"] = f.read()
|
||||
with open(self._settings["iourc_path"], 'rb') as f:
|
||||
settings["iourc_content"] = f.read().decode("utf-8")
|
||||
except OSError as e:
|
||||
print("Can't open iourc file {}: {}".format(self._settings["iourc_path"], e))
|
||||
|
||||
|
||||
@@ -150,10 +150,18 @@ class IOUDevice(VM):
|
||||
# other initial settings will be applied when the router has been created
|
||||
if initial_settings:
|
||||
self._inital_settings = initial_settings
|
||||
else:
|
||||
self._inital_settings = {}
|
||||
|
||||
if initial_config:
|
||||
params["initial_config_content"] = self._readBaseConfig(initial_config)
|
||||
|
||||
if len(self._module._settings["iourc_path"]) > 0:
|
||||
try:
|
||||
with open(self._module._settings["iourc_path"], 'rb') as f:
|
||||
self._inital_settings["iourc_content"] = f.read().decode("utf-8")
|
||||
except OSError as e:
|
||||
print("Can't open iourc file {}: {}".format(self._module._settings["iourc_path"], e))
|
||||
self.httpPost("/iou/vms", self._setupCallback, body=params)
|
||||
|
||||
def _setupCallback(self, result, error=False, **kwargs):
|
||||
|
||||
@@ -356,7 +356,7 @@ class VPCSDevice(VM):
|
||||
self.server_error_signal.emit(self.id(), result["message"])
|
||||
else:
|
||||
|
||||
if "startup_script" in result:
|
||||
if "startup_script" in result and result["startup_script"] is not None:
|
||||
config_path = os.path.join(self._export_directory, normalize_filename(self.name())) + "_startup.vpc"
|
||||
config = result["startup_script"].encode("utf-8")
|
||||
try:
|
||||
|
||||
@@ -110,7 +110,11 @@ class ServerPreferencesPage(QtGui.QWidget, Ui_ServerPreferencesPageWidget):
|
||||
"""
|
||||
|
||||
host = item.text(0)
|
||||
port = int(item.text(1))
|
||||
try:
|
||||
port = int(item.text(1))
|
||||
except ValueError:
|
||||
QtGui.QMessageBox.critical(self, "Remote server", "Invalid port")
|
||||
return
|
||||
self.uiRemoteServerPortLineEdit.setText(host)
|
||||
self.uiRemoteServerPortSpinBox.setValue(port)
|
||||
|
||||
@@ -232,6 +236,16 @@ class ServerPreferencesPage(QtGui.QWidget, Ui_ServerPreferencesPageWidget):
|
||||
new_settings["projects_path"] = current_settings["projects_path"]
|
||||
new_settings["report_errors"] = current_settings["report_errors"]
|
||||
|
||||
if new_settings["console_end_port_range"] <= new_settings["console_start_port_range"]:
|
||||
QtGui.QMessageBox.critical(self, "Local", "Invalid console port range from {} to {}".format(new_settings["console_start_port_range"],
|
||||
new_settings["console_end_port_range"]))
|
||||
return
|
||||
|
||||
if new_settings["udp_end_port_range"] <= new_settings["udp_start_port_range"]:
|
||||
QtGui.QMessageBox.critical(self, "Local", "Invalid UDP port range from {} to {}".format(new_settings["udp_start_port_range"],
|
||||
new_settings["udp_end_port_range"]))
|
||||
return
|
||||
|
||||
if new_settings["auto_start"]:
|
||||
if not os.path.isfile(new_settings["path"]):
|
||||
QtGui.QMessageBox.critical(self, "Local server", "Could not find local server {}".format(new_settings["path"]))
|
||||
|
||||
@@ -49,7 +49,10 @@ class Project(QtCore.QObject):
|
||||
self._type = None
|
||||
self._name = "untitled"
|
||||
self._project_instances.add(self)
|
||||
|
||||
# Manage project creations on multiple servers
|
||||
self._created_servers = set()
|
||||
self._callback_finish_creating_on_server = {}
|
||||
|
||||
super().__init__()
|
||||
|
||||
@@ -223,17 +226,22 @@ class Project(QtCore.QObject):
|
||||
"""
|
||||
|
||||
if server not in self._created_servers:
|
||||
func = functools.partial(self._projectOnServerCreated, method, path, callback, body, context=context)
|
||||
func = functools.partial(self._projectOnServerCreated, method, path, callback, body, context=context, server=server)
|
||||
|
||||
body = {
|
||||
"name": self._name,
|
||||
"temporary": self._temporary,
|
||||
"project_id": self._id
|
||||
}
|
||||
if server == self._servers.localServer():
|
||||
body["path"] = self.filesDir()
|
||||
if server not in self._callback_finish_creating_on_server:
|
||||
self._callback_finish_creating_on_server[server] = []
|
||||
body = {
|
||||
"name": self._name,
|
||||
"temporary": self._temporary,
|
||||
"project_id": self._id
|
||||
}
|
||||
if server == self._servers.localServer():
|
||||
body["path"] = self.filesDir()
|
||||
|
||||
server.post("/projects", func, body)
|
||||
server.post("/projects", func, body)
|
||||
else:
|
||||
# If the project creation is already in progress we bufferizze the query
|
||||
self._callback_finish_creating_on_server[server].append(func)
|
||||
else:
|
||||
self._projectOnServerCreated(method, path, callback, body, params={}, server=server, context=context)
|
||||
|
||||
@@ -272,6 +280,13 @@ class Project(QtCore.QObject):
|
||||
path = "/projects/{project_id}{path}".format(project_id=self._id, path=path)
|
||||
server.createHTTPQuery(method, path, callback, body=body, context=context)
|
||||
|
||||
# Call all operations waiting for project creation:
|
||||
if server in self._callback_finish_creating_on_server:
|
||||
callbacks = self._callback_finish_creating_on_server[server]
|
||||
del self._callback_finish_creating_on_server[server]
|
||||
for call in callbacks:
|
||||
call()
|
||||
|
||||
def close(self, local_server_shutdown=False):
|
||||
"""Close project"""
|
||||
|
||||
@@ -307,7 +322,10 @@ class Project(QtCore.QObject):
|
||||
if len(self._created_servers) == 0:
|
||||
self._closed = True
|
||||
self.project_closed_signal.emit()
|
||||
self._project_instances.remove(self)
|
||||
try:
|
||||
self._project_instances.remove(self)
|
||||
except KeyError:
|
||||
return
|
||||
|
||||
def moveFromTemporaryToPath(self, new_path):
|
||||
"""
|
||||
|
||||
@@ -514,8 +514,9 @@ class Topology(object):
|
||||
:params: A topology dictionnary
|
||||
"""
|
||||
topology["project_id"] = str(uuid.uuid4())
|
||||
for key, node in enumerate(topology["topology"]["nodes"]):
|
||||
topology["topology"]["nodes"][key]["vm_id"] = str(uuid.uuid4())
|
||||
if "nodes" in topology["topology"]:
|
||||
for key, node in enumerate(topology["topology"]["nodes"]):
|
||||
topology["topology"]["nodes"][key]["vm_id"] = str(uuid.uuid4())
|
||||
return topology
|
||||
|
||||
def loadFile(self, path, project):
|
||||
@@ -743,7 +744,6 @@ class Topology(object):
|
||||
image_path = topology_image["path"]
|
||||
|
||||
image_path = os.path.normpath(image_path)
|
||||
print(image_path)
|
||||
if not os.path.isfile(image_path):
|
||||
topology_file_errors.append("Path to image {} doesn't exist".format(image_path))
|
||||
continue
|
||||
|
||||
@@ -84,8 +84,6 @@ class ProcessFilesThread(QtCore.QThread):
|
||||
|
||||
# start create the destination sub-directories
|
||||
for directory in dirs:
|
||||
if not self._is_running:
|
||||
return
|
||||
try:
|
||||
destination_dir = os.path.join(base_dir, directory)
|
||||
os.makedirs(destination_dir)
|
||||
@@ -94,11 +92,11 @@ class ProcessFilesThread(QtCore.QThread):
|
||||
except OSError as e:
|
||||
self.error.emit("Could not create directory {}: {}".format(destination_dir, e), True)
|
||||
return
|
||||
if not self._is_running:
|
||||
return
|
||||
|
||||
# finally the files themselves
|
||||
for sfile in filenames:
|
||||
if not self._is_running:
|
||||
return
|
||||
source_file = os.path.join(path, sfile)
|
||||
destination_file = os.path.join(base_dir, sfile)
|
||||
try:
|
||||
@@ -113,6 +111,8 @@ class ProcessFilesThread(QtCore.QThread):
|
||||
else:
|
||||
log.warning("Cannot copy: {}".format(e))
|
||||
self.error.emit("Could not copy file to {}: {}".format(destination_file, e), False)
|
||||
if not self._is_running:
|
||||
return
|
||||
copied += 1
|
||||
# update the progress made
|
||||
progress = float(copied) / file_count * 100
|
||||
|
||||
@@ -71,7 +71,11 @@ class WaitForConnectionThread(QtCore.QThread):
|
||||
connection_success = True
|
||||
break
|
||||
|
||||
if not self._is_running:
|
||||
return
|
||||
|
||||
if not connection_success:
|
||||
|
||||
# let the GUI know about the connection was unsuccessful and finish the thread
|
||||
self.error.emit("Could not connect to {} on port {}: {}".format(self._host,
|
||||
self._port,
|
||||
|
||||
@@ -25,5 +25,5 @@ or negative for a release candidate or beta (after the base version
|
||||
number has been incremented)
|
||||
"""
|
||||
|
||||
__version__ = "1.3.0"
|
||||
__version_info__ = (1, 3, 0, 0)
|
||||
__version__ = "1.3.1"
|
||||
__version_info__ = (1, 3, 1, 0)
|
||||
|
||||
10
setup.py
10
setup.py
@@ -46,17 +46,17 @@ setup(
|
||||
long_description=open("README.rst", "r").read(),
|
||||
install_requires=[
|
||||
"apache-libcloud>=0.14.1",
|
||||
"requests==2.4.3",
|
||||
"paramiko==1.15.1",
|
||||
"gns3-converter",
|
||||
"raven==5.2.0"
|
||||
"requests>=2.4.3",
|
||||
"paramiko>=1.15.1",
|
||||
"gns3-converter>=1.2.3",
|
||||
"raven>=5.2.0"
|
||||
],
|
||||
entry_points={
|
||||
"gui_scripts": [
|
||||
"gns3 = gns3.main:main",
|
||||
]
|
||||
},
|
||||
packages=find_packages(),
|
||||
packages=find_packages(".", exclude=["docs", "tests"]),
|
||||
include_package_data=True,
|
||||
package_data={"gns3": ["configs/*.txt"]},
|
||||
platforms="any",
|
||||
|
||||
@@ -84,7 +84,7 @@ def test_post_not_connected(http_client, request, network_manager, response):
|
||||
assert network_manager.get.called
|
||||
|
||||
response.header.return_value = "application/json"
|
||||
response.readAll.return_value = ("{\"version\": \"" + __version__ + "\"}").encode()
|
||||
response.readAll.return_value = ("{\"version\": \"" + __version__ + "\", \"local\": true}").encode()
|
||||
|
||||
# Trigger the completion of /version
|
||||
response.finished.emit()
|
||||
@@ -98,7 +98,6 @@ def test_post_not_connected(http_client, request, network_manager, response):
|
||||
assert callback.called
|
||||
|
||||
args, kwargs = callback.call_args
|
||||
print(kwargs["context"])
|
||||
assert kwargs["context"]["toto"] == 42
|
||||
|
||||
|
||||
|
||||
@@ -119,6 +119,44 @@ def test_project_post_non_created_project_remote_server(remote_server):
|
||||
assert kwargs["body"] == {"test": "test"}
|
||||
|
||||
|
||||
def test_project_post_non_created_project_remote_server_two_query(remote_server):
|
||||
"""
|
||||
Test a post on a remote servers. The project
|
||||
is not created on the server and should be created automaticaly.
|
||||
And after make the call
|
||||
"""
|
||||
|
||||
uuid = uuid4()
|
||||
project = Project()
|
||||
project._created_servers = set()
|
||||
project.setId(uuid)
|
||||
|
||||
with patch("gns3.http_client.HTTPClient.createHTTPQuery") as mock:
|
||||
project.post(remote_server, "/test", lambda: 0, body={"test": "test"})
|
||||
args, kwargs = mock.call_args
|
||||
|
||||
assert args[0] == "POST"
|
||||
assert args[1] == "/projects"
|
||||
assert kwargs["body"] == {"name": "untitled", "temporary": False, "project_id": uuid}
|
||||
project.post(remote_server, "/test2", lambda: 0, body={"test": "test"})
|
||||
|
||||
assert mock.call_count == 1
|
||||
args[2]({}, server=remote_server)
|
||||
|
||||
assert len(project._created_servers) == 1
|
||||
|
||||
calls = mock.mock_calls
|
||||
name, args, kwargs = mock.mock_calls[1]
|
||||
assert args[0] == "POST"
|
||||
assert args[1] == "/projects/{uuid}/test".format(uuid=uuid)
|
||||
assert kwargs["body"] == {"test": "test"}
|
||||
|
||||
args, kwargs = mock.call_args
|
||||
assert args[0] == "POST"
|
||||
assert args[1] == "/projects/{uuid}/test2".format(uuid=uuid)
|
||||
assert kwargs["body"] == {"test": "test"}
|
||||
|
||||
|
||||
def test_project_post_on_created_project(local_server):
|
||||
"""
|
||||
Test a post on a remote servers.
|
||||
|
||||
@@ -401,10 +401,14 @@ def test_load_1_2_topology(project, monkeypatch, main_window, tmpdir):
|
||||
|
||||
monkeypatch.setattr('gns3.main_window.MainWindow.instance', lambda: main_window)
|
||||
|
||||
project_call = 0
|
||||
# We return an uuid for each HTTP post
|
||||
|
||||
def http_loader(self, method, path, callback, body={}, **kwargs):
|
||||
if path == "/projects":
|
||||
callback({"project_id": uuid.uuid4(), "path": str(tmpdir)}, error=False, server=local_server)
|
||||
project_call += 1
|
||||
assert project_call < 2
|
||||
else:
|
||||
callback({"vm_id": uuid.uuid4()})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user