mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-28 22:40:30 +03:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29b851207b | ||
|
|
ca5557e579 | ||
|
|
7331ae29ef | ||
|
|
3a7e06e14b | ||
|
|
0a81af8248 | ||
|
|
a882956ec9 | ||
|
|
9f4361d66f | ||
|
|
d10c3c7308 | ||
|
|
0cd7d7e4c2 | ||
|
|
8f3f72ff54 | ||
|
|
7fbc0befa1 | ||
|
|
9d9668442e | ||
|
|
932083be88 | ||
|
|
82e7c151c4 | ||
|
|
7e5c363bc3 | ||
|
|
15d029a7fb | ||
|
|
9087ba8f5a | ||
|
|
3d89d6e6cc | ||
|
|
91bae81300 | ||
|
|
7de5bf6bd5 | ||
|
|
9de238619a | ||
|
|
ed88466d63 | ||
|
|
478b793b04 | ||
|
|
841c29e6f6 | ||
|
|
f9d96051f5 | ||
|
|
607e201674 | ||
|
|
18950ca64f | ||
|
|
c0b5f39c4c | ||
|
|
3e717999ca | ||
|
|
800d14363d | ||
|
|
2dd9d61c57 | ||
|
|
10afb5a8de | ||
|
|
3413afe952 | ||
|
|
7222da9512 | ||
|
|
dbe8df5a37 | ||
|
|
a9890265b9 | ||
|
|
97b777ceea | ||
|
|
c06e534935 | ||
|
|
025276f8a7 | ||
|
|
6777961d29 | ||
|
|
7f6cace0d5 | ||
|
|
1a739c0c37 | ||
|
|
6d855045ef | ||
|
|
fef734bbbe | ||
|
|
b079443735 | ||
|
|
4a32ae9736 | ||
|
|
9793d00131 | ||
|
|
2b7840279a | ||
|
|
9243083321 | ||
|
|
3a8b3e5c4a | ||
|
|
e2168a3c81 | ||
|
|
01deb01e6a | ||
|
|
1133ee6e1b | ||
|
|
7512ffec64 | ||
|
|
a58451a552 | ||
|
|
0a43b9e6e9 | ||
|
|
8a5ab6b374 | ||
|
|
4b7cf4e553 | ||
|
|
b72358461c |
2
.github/workflows/testing.yml
vendored
2
.github/workflows/testing.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build and run Docker image
|
||||
run: |
|
||||
docker build -t gns3-gui-test .
|
||||
|
||||
17
CHANGELOG
17
CHANGELOG
@@ -1,5 +1,22 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.44 06/11/2023
|
||||
|
||||
* Fix timeout issue when creating Qemu disk image. Fixes https://github.com/GNS3/gns3-server/issues/2313
|
||||
* Refactor command variables support
|
||||
* Add vendor_logo_url in appliance schemas. Ref https://github.com/GNS3/gns3-registry/pull/825
|
||||
* Add Qemu IGB network device
|
||||
* Add the ability to edit width and height in the style edit dialog.
|
||||
|
||||
## 2.2.43 19/09/2023
|
||||
|
||||
* Add KiTTY to preconfigured telnet consoles. Fixes #3507
|
||||
* Fix generic icon in Wayland. Ref #3501
|
||||
* Support for appliance format version 8.
|
||||
* Use importlib instead of pkg_resources
|
||||
* Upgrade to PyQt 5.15.9 and pywin32
|
||||
* Add support for appliance version 8 format
|
||||
|
||||
## 2.2.42 09/08/2023
|
||||
|
||||
* Use the system's certificate store for SSL connections
|
||||
|
||||
@@ -5,7 +5,7 @@ image: Visual Studio 2022
|
||||
platform: x64
|
||||
|
||||
environment:
|
||||
PYTHON: "C:\\Python37-x64"
|
||||
PYTHON: "C:\\Python38-x64"
|
||||
DISTUTILS_USE_SDK: "1"
|
||||
|
||||
install:
|
||||
|
||||
@@ -46,6 +46,9 @@ class Application(QtWidgets.QApplication):
|
||||
|
||||
super().__init__(argv)
|
||||
|
||||
# this is tell Wayland what is the name of the desktop file (gns3.desktop)
|
||||
self.setDesktopFileName("gns3")
|
||||
|
||||
# this info is necessary for QSettings
|
||||
self.setOrganizationName("GNS3")
|
||||
self.setOrganizationDomain("gns3.net")
|
||||
|
||||
@@ -50,7 +50,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://bae0411a1718612ee8c25cdb12ec7f02@o19455.ingest.sentry.io/38506"
|
||||
DSN = "https://5c5fb544e56f9d41179e57bfff78e151@o19455.ingest.sentry.io/38506"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -94,9 +94,11 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
self.setWindowTitle("Install {} appliance".format(self._appliance["name"]))
|
||||
|
||||
# add a custom button to show appliance information
|
||||
self.setButtonText(QtWidgets.QWizard.CustomButton1, "&Appliance info")
|
||||
self.setOption(QtWidgets.QWizard.HaveCustomButton1, True)
|
||||
self.customButtonClicked.connect(self._showApplianceInfoSlot)
|
||||
if self._appliance["registry_version"] < 8:
|
||||
# FIXME: show appliance info for v8
|
||||
self.setButtonText(QtWidgets.QWizard.CustomButton1, "&Appliance info")
|
||||
self.setOption(QtWidgets.QWizard.HaveCustomButton1, True)
|
||||
self.customButtonClicked.connect(self._showApplianceInfoSlot)
|
||||
|
||||
# customize the server selection
|
||||
self.uiRemoteRadioButton.toggled.connect(self._remoteServerToggledSlot)
|
||||
@@ -144,18 +146,9 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
if self.page(page_id) == self.uiServerWizardPage:
|
||||
|
||||
Controller.instance().getSymbols(self._getSymbolsCallback)
|
||||
|
||||
if "qemu" in self._appliance:
|
||||
emulator_type = "qemu"
|
||||
elif "iou" in self._appliance:
|
||||
emulator_type = "iou"
|
||||
elif "docker" in self._appliance:
|
||||
emulator_type = "docker"
|
||||
elif "dynamips" in self._appliance:
|
||||
emulator_type = "dynamips"
|
||||
else:
|
||||
QtWidgets.QMessageBox.warning(self, "Appliance", "Could not determine the emulator type")
|
||||
|
||||
template_type = self._appliance.template_type()
|
||||
if not template_type:
|
||||
raise ApplianceError("No template type found for appliance {}".format(self._appliance["name"]))
|
||||
is_mac = ComputeManager.instance().localPlatform().startswith("darwin")
|
||||
is_win = ComputeManager.instance().localPlatform().startswith("win")
|
||||
|
||||
@@ -173,11 +166,11 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
if ComputeManager.instance().localPlatform() is None:
|
||||
self.uiLocalRadioButton.setEnabled(False)
|
||||
elif is_mac or is_win:
|
||||
if emulator_type == "qemu":
|
||||
if template_type == "qemu":
|
||||
# disallow usage of the local server because Qemu has issues on OSX and Windows
|
||||
if not LocalConfig.instance().experimental():
|
||||
self.uiLocalRadioButton.setEnabled(False)
|
||||
elif emulator_type != "dynamips":
|
||||
elif template_type != "dynamips":
|
||||
self.uiLocalRadioButton.setEnabled(False)
|
||||
|
||||
if ComputeManager.instance().vmCompute():
|
||||
@@ -195,27 +188,55 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
|
||||
elif self.page(page_id) == self.uiFilesWizardPage:
|
||||
if Controller.instance().isRemote() or self._compute_id != "local":
|
||||
self._registry.getRemoteImageList(self._appliance.emulator(), self._compute_id)
|
||||
self._registry.getRemoteImageList(self._appliance.template_type(), self._compute_id)
|
||||
else:
|
||||
self.images_changed_signal.emit()
|
||||
|
||||
elif self.page(page_id) == self.uiQemuWizardPage:
|
||||
if self._appliance['qemu'].get('kvm', 'require') == 'require':
|
||||
if self._appliance.template_properties().get('kvm', 'require') == 'require':
|
||||
self._server_check = False
|
||||
Qemu.instance().getQemuCapabilitiesFromServer(self._compute_id, qpartial(self._qemuServerCapabilitiesCallback))
|
||||
else:
|
||||
self._server_check = True
|
||||
Qemu.instance().getQemuBinariesFromServer(self._compute_id, qpartial(self._getQemuBinariesFromServerCallback), [self._appliance["qemu"]["arch"]])
|
||||
if self._appliance["registry_version"] >= 8:
|
||||
qemu_platform = self._appliance.template_properties()["platform"]
|
||||
else:
|
||||
qemu_platform = self._appliance.template_properties()["arch"]
|
||||
Qemu.instance().getQemuBinariesFromServer(self._compute_id, qpartial(self._getQemuBinariesFromServerCallback), [qemu_platform])
|
||||
|
||||
elif self.page(page_id) == self.uiInstructionsPage:
|
||||
|
||||
installation_instructions = self._appliance.get("installation_instructions", "No installation instructions available")
|
||||
self.uiInstructionsTextEdit.setText(installation_instructions.strip())
|
||||
|
||||
elif self.page(page_id) == self.uiUsageWizardPage:
|
||||
self.uiUsageTextEdit.setText("The template will be available in the {} category.\n\n{}".format(self._appliance["category"].replace("_", " "), self._appliance.get("usage", "")))
|
||||
# TODO: allow taking these info fields at the version level in v8
|
||||
category = self._appliance["category"].replace("_", " ")
|
||||
usage = self._appliance.get("usage", "No usage information available")
|
||||
if self._appliance["registry_version"] >= 8:
|
||||
default_username = self._appliance.get("default_username")
|
||||
default_password = self._appliance.get("default_password")
|
||||
if default_username and default_password:
|
||||
usage += "\n\nDefault username: {}\nDefault password: {}".format(default_username, default_password)
|
||||
|
||||
usage_info = """
|
||||
The template will be available in the {} category.
|
||||
|
||||
Usage: {}
|
||||
""".format(category, usage)
|
||||
|
||||
self.uiUsageTextEdit.setText(usage_info.strip())
|
||||
|
||||
def _qemuServerCapabilitiesCallback(self, result, error=None, *args, **kwargs):
|
||||
"""
|
||||
Check if the server supports KVM or not
|
||||
"""
|
||||
|
||||
if error is None and "kvm" in result and self._appliance["qemu"]["arch"] in result["kvm"]:
|
||||
if self._appliance["registry_version"] >= 8:
|
||||
qemu_platform = self._appliance.template_properties()["platform"]
|
||||
else:
|
||||
qemu_platform = self._appliance.template_properties()["arch"]
|
||||
if error is None and "kvm" in result and qemu_platform in result["kvm"]:
|
||||
self._server_check = True
|
||||
else:
|
||||
if error:
|
||||
@@ -236,7 +257,7 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
log.error("Error while uploading image '{}': {}".format(image_path, result["message"]))
|
||||
else:
|
||||
log.info("Image '{}' has been successfully uploaded".format(image_path))
|
||||
self._registry.getRemoteImageList(self._appliance.emulator(), self._compute_id)
|
||||
self._registry.getRemoteImageList(self._appliance.template_type(), self._compute_id)
|
||||
|
||||
def _showApplianceInfoSlot(self):
|
||||
"""
|
||||
@@ -407,7 +428,7 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
|
||||
for version in self._appliance["versions"]:
|
||||
for image in version["images"].values():
|
||||
img = self._registry.search_image_file(self._appliance.emulator(),
|
||||
img = self._registry.search_image_file(self._appliance.template_type(),
|
||||
image["filename"],
|
||||
image.get("md5sum"),
|
||||
image.get("filesize"),
|
||||
@@ -519,7 +540,7 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
if len(path) == 0:
|
||||
return
|
||||
|
||||
image = Image(self._appliance.emulator(), path, filename=disk["filename"])
|
||||
image = Image(self._appliance.template_type(), path, filename=disk["filename"])
|
||||
try:
|
||||
if "md5sum" in disk and image.md5sum != disk["md5sum"]:
|
||||
reply = QtWidgets.QMessageBox.question(self, "Add appliance",
|
||||
@@ -554,7 +575,11 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
if self.uiQemuListComboBox.count() == 1:
|
||||
self.next()
|
||||
else:
|
||||
i = self.uiQemuListComboBox.findData(self._appliance["qemu"]["arch"], flags=QtCore.Qt.MatchEndsWith)
|
||||
if self._appliance["registry_version"] >= 8:
|
||||
qemu_platform = self._appliance.template_properties()["platform"]
|
||||
else:
|
||||
qemu_platform = self._appliance.template_properties()["arch"]
|
||||
i = self.uiQemuListComboBox.findData(qemu_platform, flags=QtCore.Qt.MatchEndsWith)
|
||||
if i != -1:
|
||||
self.uiQemuListComboBox.setCurrentIndex(i)
|
||||
|
||||
@@ -567,8 +592,8 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
|
||||
if version is None:
|
||||
appliance_configuration = self._appliance.copy()
|
||||
if "docker" not in appliance_configuration:
|
||||
# only Docker do not have version
|
||||
if self._appliance.template_type() != "docker":
|
||||
# only Docker do not have versions
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
@@ -585,10 +610,15 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
return False
|
||||
appliance_configuration["name"] = appliance_configuration["name"].strip()
|
||||
|
||||
if "qemu" in appliance_configuration:
|
||||
if self._appliance["registry_version"] >= 8:
|
||||
if "settings" in appliance_configuration:
|
||||
for settings in appliance_configuration["settings"]:
|
||||
if settings["template_type"] == "qemu":
|
||||
settings["template_properties"]["path"] = self.uiQemuListComboBox.currentData()
|
||||
elif "qemu" in appliance_configuration:
|
||||
appliance_configuration["qemu"]["path"] = self.uiQemuListComboBox.currentData()
|
||||
|
||||
new_template = ApplianceToTemplate().new_template(appliance_configuration, self._compute_id, self._symbols, parent=self)
|
||||
new_template = ApplianceToTemplate().new_template(appliance_configuration, self._compute_id, version, self._symbols, parent=self)
|
||||
TemplateManager.instance().createTemplate(Template(new_template), callback=self._templateCreatedCallback)
|
||||
return False
|
||||
|
||||
@@ -632,7 +662,7 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
if not Controller.instance().isRemote() and self._compute_id == "local" and image["path"].startswith(ImageManager.instance().getDirectory()):
|
||||
log.debug("{} is already on the local server".format(image["path"]))
|
||||
return
|
||||
image = Image(self._appliance.emulator(), image["path"], filename=image["filename"])
|
||||
image = Image(self._appliance.template_type(), image["path"], filename=image["filename"])
|
||||
image_upload_manager = ImageUploadManager(image, Controller.instance(), self._compute_id, self._applianceImageUploadedCallback, LocalConfig.instance().directFileUpload())
|
||||
image_upload_manager.upload()
|
||||
self._image_uploading_count += 1
|
||||
@@ -649,12 +679,16 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
|
||||
def nextId(self):
|
||||
if self.currentPage() == self.uiServerWizardPage:
|
||||
if "docker" in self._appliance:
|
||||
if self._appliance.template_type() == "docker":
|
||||
# skip Qemu binary selection and files pages if this is a Docker appliance
|
||||
return super().nextId() + 2
|
||||
elif "qemu" not in self._appliance:
|
||||
return super().nextId() + 3
|
||||
elif self._appliance.template_type() != "qemu":
|
||||
# skip the Qemu binary selection page if not a Qemu appliance
|
||||
return super().nextId() + 1
|
||||
if self.currentPage() == self.uiQemuWizardPage:
|
||||
if not self._appliance.get("installation_instructions"):
|
||||
# skip the installation instructions page if there are no instructions
|
||||
return super().nextId() + 1
|
||||
return super().nextId()
|
||||
|
||||
def validateCurrentPage(self):
|
||||
@@ -722,7 +756,6 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
|
||||
elif self.currentPage() == self.uiQemuWizardPage:
|
||||
# validate the Qemu
|
||||
|
||||
if self._server_check is False:
|
||||
QtWidgets.QMessageBox.critical(self, "Checking for KVM support", "Please wait for the server to reply...")
|
||||
return False
|
||||
|
||||
@@ -78,8 +78,20 @@ class StyleEditorDialog(QtWidgets.QDialog, Ui_StyleEditorDialog):
|
||||
if not corner_radius:
|
||||
corner_radius = first_item.verticalCornerRadius()
|
||||
self.uiCornerRadiusSpinBox.setValue(corner_radius)
|
||||
else:
|
||||
self.uiCornerRadiusLabel.hide()
|
||||
self.uiCornerRadiusSpinBox.hide()
|
||||
self.uiRotationSpinBox.setValue(int(first_item.rotation()))
|
||||
self.uiBorderWidthSpinBox.setValue(pen.width())
|
||||
if isinstance(first_item, ShapeItem):
|
||||
rect = first_item.rect()
|
||||
self.uiWidthSpinBox.setValue(int(rect.width()))
|
||||
self.uiHeightSpinBox.setValue(int(rect.height()))
|
||||
else:
|
||||
self.uiWidthSpinBox.hide()
|
||||
self.uiWidthLabel.hide()
|
||||
self.uiHeightSpinBox.hide()
|
||||
self.uiHeightLabel.hide()
|
||||
index = self.uiBorderStyleComboBox.findData(pen.style())
|
||||
if index != -1:
|
||||
self.uiBorderStyleComboBox.setCurrentIndex(index)
|
||||
@@ -134,6 +146,8 @@ class StyleEditorDialog(QtWidgets.QDialog, Ui_StyleEditorDialog):
|
||||
# maybe we support setting them separately in the future
|
||||
item.setHorizontalCornerRadius(corner_radius)
|
||||
item.setVerticalCornerRadius(corner_radius)
|
||||
if isinstance(item, ShapeItem):
|
||||
item.setWidthAndHeight(self.uiWidthSpinBox.value(), self.uiHeightSpinBox.value())
|
||||
item.setRotation(self.uiRotationSpinBox.value())
|
||||
|
||||
def done(self, result):
|
||||
|
||||
@@ -171,6 +171,9 @@ class ShapeItem(DrawingItem):
|
||||
if not self.locked():
|
||||
self._graphics_view.setCursor(QtCore.Qt.ArrowCursor)
|
||||
|
||||
def setWidthAndHeight(self, width, height):
|
||||
self.setRect(0, 0, width, height)
|
||||
|
||||
def fromSvg(self, svg):
|
||||
"""
|
||||
Import element information from SVG
|
||||
|
||||
@@ -482,11 +482,15 @@ class LocalServer(QtCore.QObject):
|
||||
try:
|
||||
if sys.platform.startswith("win"):
|
||||
# use the string on Windows
|
||||
self._local_server_process = subprocess.Popen(command, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, stderr=subprocess.PIPE)
|
||||
self._local_server_process = subprocess.Popen(
|
||||
command,
|
||||
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP,
|
||||
stderr=subprocess.PIPE,
|
||||
env=os.environ)
|
||||
else:
|
||||
# use arguments on other platforms
|
||||
args = shlex.split(command)
|
||||
self._local_server_process = subprocess.Popen(args, stderr=subprocess.PIPE)
|
||||
self._local_server_process = subprocess.Popen(args, stderr=subprocess.PIPE, env=os.environ)
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
log.warning('Could not start local server "{}": {}'.format(command, e))
|
||||
return False
|
||||
|
||||
10
gns3/main.py
10
gns3/main.py
@@ -30,16 +30,6 @@ try:
|
||||
except Exception as e:
|
||||
print("Fail update installation: {}".format(str(e)))
|
||||
|
||||
|
||||
# WARNING
|
||||
# Due to buggy user machines we choose to put this as the first loading modules
|
||||
# otherwise the egg cache is initialized in his standard location and
|
||||
# if is not writetable the application crash. It's the user fault
|
||||
# because one day the user as used sudo to run an egg and break his
|
||||
# filesystem permissions, but it's a common mistake.
|
||||
from gns3.utils.get_resource import get_resource
|
||||
|
||||
|
||||
import datetime
|
||||
import traceback
|
||||
import time
|
||||
|
||||
@@ -57,6 +57,7 @@ class iouDeviceConfigurationPage(QtWidgets.QWidget, Ui_iouDeviceConfigPageWidget
|
||||
self.uiPrivateConfigToolButton.hide()
|
||||
|
||||
# location of the base config templates
|
||||
# FIXME: this does not work
|
||||
self._base_iou_l2_config_template = get_resource(os.path.join("configs", "iou_l2_base_startup-config.txt"))
|
||||
self._base_iou_l3_config_template = get_resource(os.path.join("configs", "iou_l3_base_startup-config.txt"))
|
||||
self._default_configs_dir = LocalServer.instance().localServerSettings()["configs_path"]
|
||||
|
||||
@@ -121,7 +121,7 @@ class Qemu(Module):
|
||||
:param options: Options for the image creation
|
||||
"""
|
||||
|
||||
Controller.instance().postCompute("/qemu/img", compute_id, callback, body=options)
|
||||
Controller.instance().postCompute("/qemu/img", compute_id, callback, timeout=None, body=options)
|
||||
|
||||
def updateDiskImage(self, compute_id, callback, options):
|
||||
"""
|
||||
|
||||
@@ -101,7 +101,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
self.uiOnCloseComboBox.addItem(name, option_name)
|
||||
|
||||
# Supported NIC models: e1000, e1000-82544gc, e1000-82545em, e1000e, i82550, i82551, i82557a, i82557b, i82557c, i82558a
|
||||
# i82558b, i82559a, i82559b, i82559c, i82559er, i82562, i82801, ne2k_pci, pcnet, rocker, rtl8139, virtio-net-pci, vmxnet3
|
||||
# i82558b, i82559a, i82559b, i82559c, i82559er, i82562, i82801, igb, ne2k_pci, pcnet, rocker, rtl8139, virtio-net-pci, vmxnet3
|
||||
# This list can be retrieved using "qemu-system-x86_64 -nic model=?" or "qemu-system-x86_64 -device help"
|
||||
self._legacy_devices = ("e1000", "i82551", "i82557b", "i82559er", "ne2k_pci", "pcnet", "rtl8139", "virtio")
|
||||
self._qemu_network_devices = OrderedDict([("e1000", "Intel Gigabit Ethernet"),
|
||||
@@ -121,6 +121,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
|
||||
("i82559er", "Intel i82559ER Ethernet"),
|
||||
("i82562", "Intel i82562 Ethernet"),
|
||||
("i82801", "Intel i82801 Ethernet"),
|
||||
("igb", "Intel 82576 Gigabit Ethernet"),
|
||||
("ne2k_pci", "NE2000 Ethernet"),
|
||||
("pcnet", "AMD PCNet Ethernet"),
|
||||
("rocker", "Rocker L2 switch device"),
|
||||
|
||||
@@ -146,13 +146,19 @@ class PacketCapture:
|
||||
|
||||
# PCAP capture file path
|
||||
command = command.replace("%c", '"' + capture_file_path + '"')
|
||||
command = command.replace("{pcap_file}", '"' + capture_file_path + '"')
|
||||
|
||||
# Add description
|
||||
# Add project name
|
||||
command = command.replace("%P", link.project().name())
|
||||
command = command.replace("{project}", link.project().name().replace('"', '\\"'))
|
||||
|
||||
# Add link description
|
||||
description = "{}[{}]->{}[{}]".format(link.sourceNode().name(),
|
||||
link.sourcePort().name(),
|
||||
link.destinationNode().name(),
|
||||
link.destinationPort().name())
|
||||
command = command.replace("%d", description)
|
||||
command = command.replace("{link_description}", description)
|
||||
|
||||
if not sys.platform.startswith("win"):
|
||||
command = shlex.split(command)
|
||||
@@ -160,7 +166,7 @@ class PacketCapture:
|
||||
QtWidgets.QMessageBox.critical(self.parent(), "Packet Capture Analyzer", "No packet capture analyzer program configured")
|
||||
return
|
||||
try:
|
||||
subprocess.Popen(command)
|
||||
subprocess.Popen(command, env=os.environ)
|
||||
except OSError as e:
|
||||
QtWidgets.QMessageBox.critical(self.parent(), "Packet Capture Analyzer", "Can't start packet capture analyzer program {}".format(str(e)))
|
||||
return
|
||||
@@ -204,13 +210,19 @@ class PacketCapture:
|
||||
|
||||
# PCAP capture file path
|
||||
command = command.replace("%c", '"' + capture_file_path + '"')
|
||||
command = command.replace("{pcap_file}", '"' + capture_file_path + '"')
|
||||
|
||||
# Add description
|
||||
# Add project name
|
||||
command = command.replace("%P", link.project().name())
|
||||
command = command.replace("{project}", link.project().name().replace('"', '\\"'))
|
||||
|
||||
# Add link description
|
||||
description = "{} {} to {} {}".format(link.sourceNode().name(),
|
||||
link.sourcePort().name(),
|
||||
link.destinationNode().name(),
|
||||
link.destinationPort().name())
|
||||
command = command.replace("%d", description)
|
||||
command = command.replace("{link_description}", description)
|
||||
|
||||
if "|" in command:
|
||||
# live traffic capture (using tail)
|
||||
|
||||
@@ -21,11 +21,13 @@ import copy
|
||||
import os
|
||||
import collections.abc
|
||||
import jsonschema
|
||||
|
||||
|
||||
from gns3.utils.get_resource import get_resource
|
||||
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApplianceError(Exception):
|
||||
pass
|
||||
|
||||
@@ -38,6 +40,7 @@ class Appliance(collections.abc.Mapping):
|
||||
:params path: Path of the appliance file on disk or file content
|
||||
"""
|
||||
self._registry = registry
|
||||
self._registry_version = None
|
||||
|
||||
if os.path.isabs(path):
|
||||
try:
|
||||
@@ -58,16 +61,25 @@ class Appliance(collections.abc.Mapping):
|
||||
:param appliance: Sanity check on the appliance configuration
|
||||
"""
|
||||
if "registry_version" not in self._appliance:
|
||||
raise ApplianceError("Invalid appliance configuration please report the issue on https://github.com/GNS3/gns3-registry")
|
||||
if self._appliance["registry_version"] > 7:
|
||||
raise ApplianceError("Please update GNS3 in order to install this appliance")
|
||||
raise ApplianceError("Invalid appliance configuration please report the issue on https://github.com/GNS3/gns3-registry/issues")
|
||||
|
||||
with open(get_resource(os.path.join("schemas", "appliance.json"))) as f:
|
||||
self._registry_version = self._appliance["registry_version"]
|
||||
if self._registry_version > 8:
|
||||
# we only support registry version 8 and below
|
||||
raise ApplianceError("Registry version {} is not supported in this version of GNS3".format(self._registry_version))
|
||||
|
||||
if self._registry_version == 8:
|
||||
# registry version 8 has a different schema with support for multiple settings sets
|
||||
appliance_file = "appliance_v8.json"
|
||||
else:
|
||||
appliance_file = "appliance.json"
|
||||
|
||||
with open(get_resource("schemas/{}".format(appliance_file))) as f:
|
||||
schema = json.load(f)
|
||||
v = jsonschema.Draft4Validator(schema)
|
||||
try:
|
||||
v.validate(self._appliance)
|
||||
except jsonschema.ValidationError as e:
|
||||
except jsonschema.ValidationError:
|
||||
error = jsonschema.exceptions.best_match(v.iter_errors(self._appliance)).message
|
||||
raise ApplianceError("Invalid appliance file: {}".format(error))
|
||||
|
||||
@@ -82,10 +94,11 @@ class Appliance(collections.abc.Mapping):
|
||||
|
||||
def _resolve_version(self):
|
||||
"""
|
||||
Replace image field in versions by their the complete information from images
|
||||
Replace image field in versions by the complete information from images
|
||||
"""
|
||||
|
||||
if "versions" not in self._appliance:
|
||||
log.debug("No versions found in appliance")
|
||||
return
|
||||
|
||||
for version in self._appliance["versions"]:
|
||||
@@ -96,7 +109,7 @@ class Appliance(collections.abc.Mapping):
|
||||
for file in self._appliance["images"]:
|
||||
file = copy.copy(file)
|
||||
|
||||
if "idlepc" in version:
|
||||
if self._registry_version < 8 and "idlepc" in version:
|
||||
file["idlepc"] = version["idlepc"]
|
||||
|
||||
if "/" in filename:
|
||||
@@ -127,7 +140,7 @@ class Appliance(collections.abc.Mapping):
|
||||
def search_images_for_version(self, version_name):
|
||||
"""
|
||||
Search on disk the images required by this version.
|
||||
And keep only the require images in the images fields. Add to the images
|
||||
And keep only the required images in the images fields. Add to the images
|
||||
their disk type and path.
|
||||
|
||||
:param version_name: Version name
|
||||
@@ -142,10 +155,18 @@ class Appliance(collections.abc.Mapping):
|
||||
for image_type, image in version["images"].items():
|
||||
image["type"] = image_type
|
||||
|
||||
img = self._registry.search_image_file(self.emulator(), image["filename"], image.get("md5sum"), image.get("filesize"))
|
||||
checksum = image.get("md5sum")
|
||||
if checksum is None and self._registry_version >= 8:
|
||||
# registry version >= 8 has the checksum and checksum_type fields
|
||||
checksum_type = image.get("checksum_type", "md5") # md5 is the default and only supported type
|
||||
if checksum_type != "md5":
|
||||
raise ApplianceError("Checksum type {} is not supported".format(checksum_type))
|
||||
checksum = image.pop("checksum")
|
||||
|
||||
img = self._registry.search_image_file(self.template_type(), image["filename"], checksum, image.get("filesize"))
|
||||
if img is None:
|
||||
if "md5sum" in image:
|
||||
raise ApplianceError("File {} with checksum {} not found for {}".format(image["filename"], image["md5sum"], appliance["name"]))
|
||||
if checksum:
|
||||
raise ApplianceError("File {} with checksum {} not found for {}".format(image["filename"], checksum, appliance["name"]))
|
||||
else:
|
||||
raise ApplianceError("File {} not found for {}".format(image["filename"], appliance["name"]))
|
||||
|
||||
@@ -186,9 +207,51 @@ class Appliance(collections.abc.Mapping):
|
||||
except ApplianceError:
|
||||
return False
|
||||
|
||||
def emulator(self):
|
||||
if "qemu" in self._appliance:
|
||||
return "qemu"
|
||||
if "iou" in self._appliance:
|
||||
return "iou"
|
||||
return "dynamips"
|
||||
def template_type(self):
|
||||
|
||||
if self._registry_version >= 8:
|
||||
template_type = None
|
||||
for settings in self._appliance["settings"]:
|
||||
if settings["template_type"] and not template_type:
|
||||
template_type = settings["template_type"]
|
||||
elif settings["template_type"] and template_type != settings["template_type"]:
|
||||
# we are currently not supporting multiple different template types in the same appliance
|
||||
raise ApplianceError("Multiple different template types found in appliance")
|
||||
if not template_type:
|
||||
raise ApplianceError("No template type found in appliance {}".format(self._appliance["name"]))
|
||||
return template_type
|
||||
else:
|
||||
if "qemu" in self._appliance:
|
||||
return "qemu"
|
||||
if "iou" in self._appliance:
|
||||
return "iou"
|
||||
if "dynamips" in self._appliance:
|
||||
return "dynamips"
|
||||
if "docker" in self._appliance:
|
||||
return "docker"
|
||||
return None
|
||||
|
||||
def template_properties(self):
|
||||
"""
|
||||
Get template properties
|
||||
"""
|
||||
|
||||
if self._registry_version >= 8:
|
||||
# find the default settings if any
|
||||
for settings in self._appliance["settings"]:
|
||||
if settings.get("default", False):
|
||||
return settings["template_properties"]
|
||||
# otherwise take the first settings we find
|
||||
for settings in self._appliance["settings"]:
|
||||
if settings["template_type"]:
|
||||
return settings["template_properties"]
|
||||
else:
|
||||
if "qemu" in self._appliance:
|
||||
return self._appliance["qemu"]
|
||||
if "iou" in self._appliance:
|
||||
return self._appliance["iou"]
|
||||
if "dynamips" in self._appliance:
|
||||
return self._appliance["dynamips"]
|
||||
if "docker" in self._appliance:
|
||||
return self._appliance["docker"]
|
||||
return None
|
||||
|
||||
@@ -34,7 +34,7 @@ class ApplianceToTemplate:
|
||||
Appliance installation.
|
||||
"""
|
||||
|
||||
def new_template(self, appliance_config, server, controller_symbols=None, parent=None):
|
||||
def new_template(self, appliance_config, server, appliance_version=None, controller_symbols=None, parent=None):
|
||||
"""
|
||||
Creates a new template from an appliance.
|
||||
|
||||
@@ -43,6 +43,7 @@ class ApplianceToTemplate:
|
||||
"""
|
||||
|
||||
self._parent = parent
|
||||
self._registry_version = appliance_config["registry_version"]
|
||||
new_template = {
|
||||
"compute_id": server,
|
||||
"name": appliance_config["name"]
|
||||
@@ -74,45 +75,101 @@ class ApplianceToTemplate:
|
||||
elif appliance_config["category"] == "firewall":
|
||||
new_template["symbol"] = ":/symbols/firewall.svg"
|
||||
|
||||
if "qemu" in appliance_config:
|
||||
new_template["template_type"] = "qemu"
|
||||
self._add_qemu_config(new_template, appliance_config)
|
||||
elif "iou" in appliance_config:
|
||||
new_template["template_type"] = "iou"
|
||||
self._add_iou_config(new_template, appliance_config)
|
||||
elif "dynamips" in appliance_config:
|
||||
new_template["template_type"] = "dynamips"
|
||||
self._add_dynamips_config(new_template, appliance_config)
|
||||
elif "docker" in appliance_config:
|
||||
new_template["template_type"] = "docker"
|
||||
self._add_docker_config(new_template, appliance_config)
|
||||
if self._registry_version >= 8:
|
||||
if appliance_version:
|
||||
for version in appliance_config["versions"]:
|
||||
if appliance_version and version["name"] == appliance_version:
|
||||
# inject "usage", "category" and "symbol" specified at the version
|
||||
# level into the template properties
|
||||
usage = version.get("usage")
|
||||
if usage:
|
||||
new_template["usage"] = usage
|
||||
new_template["symbol"] = version.get("symbol", new_template["symbol"])
|
||||
new_template["category"] = version.get("category", new_template["category"])
|
||||
settings = self._get_settings(appliance_config, version.get("settings"))
|
||||
template_type = settings["template_type"]
|
||||
if template_type == "qemu":
|
||||
self._add_qemu_config(new_template, settings["template_properties"], appliance_config)
|
||||
elif template_type == "iou":
|
||||
self._add_iou_config(new_template, settings["template_properties"], appliance_config)
|
||||
elif template_type == "dynamips":
|
||||
self._add_dynamips_config(new_template, settings["template_properties"], appliance_config)
|
||||
else:
|
||||
# docker appliances have no version
|
||||
settings = self._get_settings(appliance_config)
|
||||
if settings["template_type"] == "docker":
|
||||
self._add_docker_config(new_template, settings["template_properties"], appliance_config)
|
||||
else:
|
||||
raise ConfigException("{} no configuration found for known emulators".format(new_template["name"]))
|
||||
if "qemu" in appliance_config:
|
||||
self._add_qemu_config(new_template, appliance_config["qemu"], appliance_config)
|
||||
elif "iou" in appliance_config:
|
||||
self._add_iou_config(new_template, appliance_config["iou"], appliance_config)
|
||||
elif "dynamips" in appliance_config:
|
||||
self._add_dynamips_config(new_template, appliance_config["dynamips"], appliance_config)
|
||||
elif "docker" in appliance_config:
|
||||
self._add_docker_config(new_template, appliance_config["docker"], appliance_config)
|
||||
else:
|
||||
raise ConfigException("{} no configuration found for known emulators".format(new_template["name"]))
|
||||
|
||||
return new_template
|
||||
|
||||
def _add_qemu_config(self, new_config, appliance_config):
|
||||
def _get_settings(self, appliance_config, settings_name=None):
|
||||
|
||||
new_config.update(appliance_config["qemu"])
|
||||
default_settings = None
|
||||
# first look for default settings, if any ('default' = true, first set that has it)
|
||||
for settings in appliance_config["settings"]:
|
||||
if settings.get("default", False):
|
||||
default_settings = settings
|
||||
break
|
||||
|
||||
# then look for specific settings set if a name is provided
|
||||
if settings_name:
|
||||
for settings in appliance_config["settings"]:
|
||||
if settings.get("name") == settings_name:
|
||||
if settings.get("inherit_default_properties", True) and \
|
||||
default_settings and default_settings["template_type"] == settings["template_type"]:
|
||||
default_settings["template_properties"].update(settings["template_properties"])
|
||||
return default_settings
|
||||
return settings
|
||||
raise ConfigException("Settings '{}' cannot be found in the appliance file", settings_name)
|
||||
elif default_settings:
|
||||
return default_settings
|
||||
|
||||
if not appliance_config.get("settings"):
|
||||
raise ConfigException("No settings found in the appliance file")
|
||||
|
||||
# if no default settings are specified, use the first available settings set
|
||||
return appliance_config["settings"][0]
|
||||
|
||||
def _add_qemu_config(self, new_config, template_properties, appliance_config):
|
||||
|
||||
new_config["template_type"] = "qemu"
|
||||
new_config.update(template_properties)
|
||||
|
||||
# the following properties are not valid for a template
|
||||
new_config.pop("kvm", None)
|
||||
new_config.pop("path", None)
|
||||
new_config.pop("arch", None)
|
||||
new_config.pop("kvm", None) # To check KVM setting against the server capabilities
|
||||
new_config.pop("path", None) # Qemu binary selected in previous step
|
||||
new_config.pop("arch", None) # Used for selecting the Qemu binary
|
||||
|
||||
options = appliance_config["qemu"].get("options", "")
|
||||
if appliance_config["qemu"].get("kvm", "allow") == "disable" and "-machine accel=tcg" not in options:
|
||||
options = template_properties.get("options", "")
|
||||
if template_properties.get("kvm", "allow") == "disable" and "-machine accel=tcg" not in options:
|
||||
options += " -machine accel=tcg"
|
||||
new_config["options"] = options.strip()
|
||||
options = options.strip()
|
||||
if options:
|
||||
new_config["options"] = options
|
||||
|
||||
for image in appliance_config["images"]:
|
||||
if image.get("path"):
|
||||
new_config[image["type"]] = self._relative_image_path("QEMU", image["path"])
|
||||
|
||||
if "path" in appliance_config["qemu"]:
|
||||
new_config["qemu_path"] = appliance_config["qemu"]["path"]
|
||||
if "path" in template_properties:
|
||||
new_config["qemu_path"] = template_properties["path"]
|
||||
else:
|
||||
new_config["qemu_path"] = "qemu-system-{}".format(appliance_config["qemu"]["arch"])
|
||||
if self._registry_version >= 8:
|
||||
# the "arch" field was replaced by the "platform" field in registry version 8
|
||||
new_config["qemu_path"] = "qemu-system-{}".format(template_properties["platform"])
|
||||
else:
|
||||
new_config["qemu_path"] = "qemu-system-{}".format(template_properties["arch"])
|
||||
|
||||
if "first_port_name" in appliance_config:
|
||||
new_config["first_port_name"] = appliance_config["first_port_name"]
|
||||
@@ -129,24 +186,28 @@ class ApplianceToTemplate:
|
||||
if "linked_clone" in appliance_config:
|
||||
new_config["linked_clone"] = appliance_config["linked_clone"]
|
||||
|
||||
def _add_docker_config(self, new_config, appliance_config):
|
||||
def _add_docker_config(self, new_config, template_properties, appliance_config):
|
||||
|
||||
new_config.update(appliance_config["docker"])
|
||||
new_config["template_type"] = "docker"
|
||||
new_config.update(template_properties)
|
||||
|
||||
if "custom_adapters" in appliance_config:
|
||||
new_config["custom_adapters"] = appliance_config["custom_adapters"]
|
||||
|
||||
def _add_dynamips_config(self, new_config, appliance_config):
|
||||
def _add_dynamips_config(self, new_config, template_properties, appliance_config):
|
||||
|
||||
new_config.update(appliance_config["dynamips"])
|
||||
new_config["template_type"] = "dynamips"
|
||||
new_config.update(template_properties)
|
||||
|
||||
for image in appliance_config["images"]:
|
||||
new_config[image["type"]] = self._relative_image_path("IOS", image["path"])
|
||||
new_config["idlepc"] = image.get("idlepc", "")
|
||||
if self._registry_version < 8:
|
||||
new_config["idlepc"] = image.get("idlepc", "")
|
||||
|
||||
def _add_iou_config(self, new_config, appliance_config):
|
||||
def _add_iou_config(self, new_config, template_properties, appliance_config):
|
||||
|
||||
new_config.update(appliance_config["iou"])
|
||||
new_config["template_type"] = "iou"
|
||||
new_config.update(template_properties)
|
||||
for image in appliance_config["images"]:
|
||||
if "path" not in image:
|
||||
raise ConfigException("Disk image is missing")
|
||||
|
||||
@@ -71,6 +71,11 @@
|
||||
"format": "uri",
|
||||
"title": "Website of the vendor"
|
||||
},
|
||||
"vendor_logo_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"title": "Link to the vendor logo (used by the GNS3 marketplace)"
|
||||
},
|
||||
"documentation_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
@@ -86,7 +91,7 @@
|
||||
"title": "An optional product url on vendor website"
|
||||
},
|
||||
"registry_version": {
|
||||
"enum": [1, 2, 3, 4, 5, 6],
|
||||
"enum": [1, 2, 3, 4, 5, 6, 7],
|
||||
"title": "Version of the registry compatible with this appliance"
|
||||
},
|
||||
"status": {
|
||||
@@ -282,6 +287,7 @@
|
||||
"i82559er",
|
||||
"i82562",
|
||||
"i82801",
|
||||
"igb",
|
||||
"ne2k_pci",
|
||||
"pcnet",
|
||||
"rocker",
|
||||
@@ -400,7 +406,6 @@
|
||||
"md5sum": {
|
||||
"type": "string",
|
||||
"title": "md5sum of the file",
|
||||
"type": "string",
|
||||
"pattern": "^[a-f0-9]{32}$"
|
||||
},
|
||||
"filesize": {
|
||||
|
||||
905
gns3/schemas/appliance_v8.json
Normal file
905
gns3/schemas/appliance_v8.json
Normal file
@@ -0,0 +1,905 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"title": "JSON schema validating a GNS3 appliance",
|
||||
"definitions": {
|
||||
"categories": {
|
||||
"enum": [
|
||||
"router",
|
||||
"multilayer_switch",
|
||||
"firewall",
|
||||
"guest"
|
||||
]
|
||||
},
|
||||
"docker_properties": {
|
||||
"type": "object",
|
||||
"title": "Docker template properties",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name of the template"
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/definitions/categories",
|
||||
"title": "Category of the template"
|
||||
},
|
||||
"default_name_format": {
|
||||
"type": "string",
|
||||
"title": "Default name format"
|
||||
},
|
||||
"usage": {
|
||||
"type": "string",
|
||||
"title": "How to use the template"
|
||||
},
|
||||
"symbol": {
|
||||
"type": "string",
|
||||
"title": "Symbol of the template"
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"title": "Docker image"
|
||||
},
|
||||
"adapters": {
|
||||
"type": "integer",
|
||||
"title": "Number of ethernet adapters"
|
||||
},
|
||||
"start_command": {
|
||||
"type": "string",
|
||||
"title": "Command executed when the container start. Empty will use the default"
|
||||
},
|
||||
"environment": {
|
||||
"type": "string",
|
||||
"title": "One KEY=VAR environment by line"
|
||||
},
|
||||
"console_type": {
|
||||
"enum": [
|
||||
"telnet",
|
||||
"vnc",
|
||||
"http",
|
||||
"https"
|
||||
],
|
||||
"title": "Type of console"
|
||||
},
|
||||
"console_http_port": {
|
||||
"title": "Internal port in the container of the HTTP server",
|
||||
"type": "integer"
|
||||
},
|
||||
"console_http_path": {
|
||||
"title": "Path of the web interface",
|
||||
"type": "string"
|
||||
},
|
||||
"console_resolution": {
|
||||
"title": "Console resolution for VNC, for example 1024x768",
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]+x[0-9]+$"
|
||||
},
|
||||
"extra_hosts": {
|
||||
"title": "Docker extra hosts (added to /etc/hosts)",
|
||||
"type": "string"
|
||||
},
|
||||
"extra_volumes": {
|
||||
"title": "Additional directories to make persistent",
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
"iou_properties": {
|
||||
"type": "object",
|
||||
"title": "IOU template properties",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name of the template"
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/definitions/categories",
|
||||
"title": "Category of the template"
|
||||
},
|
||||
"default_name_format": {
|
||||
"type": "string",
|
||||
"title": "Default name format"
|
||||
},
|
||||
"usage": {
|
||||
"type": "string",
|
||||
"title": "How to use the template"
|
||||
},
|
||||
"symbol": {
|
||||
"type": "string",
|
||||
"title": "Symbol of the template"
|
||||
},
|
||||
"ethernet_adapters": {
|
||||
"type": "integer",
|
||||
"title": "Number of ethernet adapters"
|
||||
},
|
||||
"serial_adapters": {
|
||||
"type": "integer",
|
||||
"title": "Number of serial adapters"
|
||||
},
|
||||
"ram": {
|
||||
"type": "integer",
|
||||
"title": "Host RAM"
|
||||
},
|
||||
"nvram": {
|
||||
"type": "integer",
|
||||
"title": "Host NVRAM"
|
||||
},
|
||||
"startup_config": {
|
||||
"type": "string",
|
||||
"title": "Config loaded at startup"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dynamips_slot": {
|
||||
"enum": [
|
||||
"C2600-MB-2FE",
|
||||
"C2600-MB-1E",
|
||||
"PA-A1",
|
||||
"PA-8E",
|
||||
"C1700-MB-1FE",
|
||||
"PA-8T",
|
||||
"PA-2FE-TX",
|
||||
"PA-FE-TX",
|
||||
"PA-GE",
|
||||
"C2600-MB-2E",
|
||||
"C7200-IO-FE",
|
||||
"NM-4T",
|
||||
"C2600-MB-1FE",
|
||||
"C7200-IO-2FE",
|
||||
"PA-POS-OC3",
|
||||
"PA-4T+",
|
||||
"C1700-MB-WIC1",
|
||||
"NM-16ESW",
|
||||
"C7200-IO-GE-E",
|
||||
"NM-4E",
|
||||
"GT96100-FE",
|
||||
"NM-1FE-TX",
|
||||
"Leopard-2FE",
|
||||
"NM-1E",
|
||||
"PA-4E",
|
||||
""
|
||||
]
|
||||
},
|
||||
"dynamips_wic": {
|
||||
"enum": [
|
||||
"WIC-1ENET",
|
||||
"WIC-1T",
|
||||
"WIC-2T",
|
||||
""
|
||||
]
|
||||
},
|
||||
"dynamips_properties": {
|
||||
"type": "object",
|
||||
"title": "Dynamips template properties",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name of the template"
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/definitions/categories",
|
||||
"title": "Category of the template"
|
||||
},
|
||||
"default_name_format": {
|
||||
"type": "string",
|
||||
"title": "Default name format"
|
||||
},
|
||||
"usage": {
|
||||
"type": "string",
|
||||
"title": "How to use the template"
|
||||
},
|
||||
"symbol": {
|
||||
"type": "string",
|
||||
"title": "Symbol of the template"
|
||||
},
|
||||
"chassis": {
|
||||
"title": "Chassis type",
|
||||
"enum": [
|
||||
"1720",
|
||||
"1721",
|
||||
"1750",
|
||||
"1751",
|
||||
"1760",
|
||||
"2610",
|
||||
"2620",
|
||||
"2610XM",
|
||||
"2620XM",
|
||||
"2650XM",
|
||||
"2621",
|
||||
"2611XM",
|
||||
"2621XM",
|
||||
"2651XM",
|
||||
"3620",
|
||||
"3640",
|
||||
"3660",
|
||||
""
|
||||
]
|
||||
},
|
||||
"platform": {
|
||||
"title": "Platform type",
|
||||
"enum": [
|
||||
"c1700",
|
||||
"c2600",
|
||||
"c2691",
|
||||
"c3725",
|
||||
"c3745",
|
||||
"c3600",
|
||||
"c7200"
|
||||
]
|
||||
},
|
||||
"ram": {
|
||||
"title": "Amount of ram",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"nvram": {
|
||||
"title": "Amount of nvram",
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"idlepc": {
|
||||
"type": "string",
|
||||
"pattern": "^0x[0-9a-f]{8}"
|
||||
},
|
||||
"startup_config": {
|
||||
"type": "string",
|
||||
"title": "Config loaded at startup"
|
||||
},
|
||||
"wic0": {
|
||||
"$ref": "#/definitions/dynamips_wic"
|
||||
},
|
||||
"wic1": {
|
||||
"$ref": "#/definitions/dynamips_wic"
|
||||
},
|
||||
"wic2": {
|
||||
"$ref": "#/definitions/dynamips_wic"
|
||||
},
|
||||
"slot0": {
|
||||
"$ref": "#/definitions/dynamips_slot"
|
||||
},
|
||||
"slot1": {
|
||||
"$ref": "#/definitions/dynamips_slot"
|
||||
},
|
||||
"slot2": {
|
||||
"$ref": "#/definitions/dynamips_slot"
|
||||
},
|
||||
"slot3": {
|
||||
"$ref": "#/definitions/dynamips_slot"
|
||||
},
|
||||
"slot4": {
|
||||
"$ref": "#/definitions/dynamips_slot"
|
||||
},
|
||||
"slot5": {
|
||||
"$ref": "#/definitions/dynamips_slot"
|
||||
},
|
||||
"slot6": {
|
||||
"$ref": "#/definitions/dynamips_slot"
|
||||
},
|
||||
"midplane": {
|
||||
"enum": [
|
||||
"std",
|
||||
"vxr"
|
||||
]
|
||||
},
|
||||
"npe": {
|
||||
"enum": [
|
||||
"npe-100",
|
||||
"npe-150",
|
||||
"npe-175",
|
||||
"npe-200",
|
||||
"npe-225",
|
||||
"npe-300",
|
||||
"npe-400",
|
||||
"npe-g2"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"platform"
|
||||
]
|
||||
},
|
||||
"qemu_disk_interfaces": {
|
||||
"enum": [
|
||||
"ide",
|
||||
"scsi",
|
||||
"sd",
|
||||
"mtd",
|
||||
"floppy",
|
||||
"pflash",
|
||||
"virtio",
|
||||
"sata"
|
||||
]
|
||||
},
|
||||
"qemu_properties": {
|
||||
"type": "object",
|
||||
"title": "Qemu template properties",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name of the template"
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/definitions/categories",
|
||||
"title": "Category of the template"
|
||||
},
|
||||
"default_name_format": {
|
||||
"type": "string",
|
||||
"title": "Default name format"
|
||||
},
|
||||
"usage": {
|
||||
"type": "string",
|
||||
"title": "How to use the template"
|
||||
},
|
||||
"symbol": {
|
||||
"type": "string",
|
||||
"title": "Symbol of the template"
|
||||
},
|
||||
"adapter_type": {
|
||||
"enum": [
|
||||
"e1000",
|
||||
"i82550",
|
||||
"i82551",
|
||||
"i82557a",
|
||||
"i82557b",
|
||||
"i82557c",
|
||||
"i82558a",
|
||||
"i82558b",
|
||||
"i82559a",
|
||||
"i82559b",
|
||||
"i82559c",
|
||||
"i82559er",
|
||||
"i82562",
|
||||
"i82801",
|
||||
"igb",
|
||||
"ne2k_pci",
|
||||
"pcnet",
|
||||
"rtl8139",
|
||||
"virtio",
|
||||
"virtio-net-pci",
|
||||
"vmxnet3"
|
||||
],
|
||||
"title": "Type of network adapter"
|
||||
},
|
||||
"adapters": {
|
||||
"type": "integer",
|
||||
"title": "Number of adapters"
|
||||
},
|
||||
"custom_adapters": {
|
||||
"type": "array",
|
||||
"title": "Custom adapters",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"adapter_number": {
|
||||
"title": "Adapter number",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_name": {
|
||||
"title": "Custom port name",
|
||||
"type": "string",
|
||||
"minimum": 1
|
||||
},
|
||||
"adapter_type": {
|
||||
"title": "Custom adapter type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"e1000",
|
||||
"i82550",
|
||||
"i82551",
|
||||
"i82557a",
|
||||
"i82557b",
|
||||
"i82557c",
|
||||
"i82558a",
|
||||
"i82558b",
|
||||
"i82559a",
|
||||
"i82559b",
|
||||
"i82559c",
|
||||
"i82559er",
|
||||
"i82562",
|
||||
"i82801",
|
||||
"igb",
|
||||
"ne2k_pci",
|
||||
"pcnet",
|
||||
"rtl8139",
|
||||
"virtio",
|
||||
"virtio-net-pci",
|
||||
"vmxnet3"
|
||||
]
|
||||
},
|
||||
"mac_address": {
|
||||
"title": "Custom MAC address",
|
||||
"type": "string",
|
||||
"minimum": 1,
|
||||
"pattern": "^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"adapter_number"
|
||||
]
|
||||
}
|
||||
},
|
||||
"first_port_name": {
|
||||
"type": "string",
|
||||
"title": "Optional name of the first networking port example: eth0"
|
||||
},
|
||||
"port_name_format": {
|
||||
"type": "string",
|
||||
"title": "Optional formating of the networking port example: eth{0}"
|
||||
},
|
||||
"port_segment_size": {
|
||||
"type": "integer",
|
||||
"title": "Optional port segment size. A port segment is a block of port. For example Ethernet0/0 Ethernet0/1 is the module 0 with a port segment size of 2"
|
||||
},
|
||||
"linked_clone": {
|
||||
"type": "boolean",
|
||||
"title": "False if you don't want to use a single image for all nodes"
|
||||
},
|
||||
"ram": {
|
||||
"type": "integer",
|
||||
"title": "Ram allocated to the appliance (MB)"
|
||||
},
|
||||
"cpus": {
|
||||
"type": "integer",
|
||||
"title": "Number of Virtual CPU"
|
||||
},
|
||||
"hda_disk_interface": {
|
||||
"$ref": "#/definitions/qemu_disk_interfaces",
|
||||
"title": "Disk interface for the installed hda_disk_image"
|
||||
},
|
||||
"hdb_disk_interface": {
|
||||
"$ref": "#/definitions/qemu_disk_interfaces",
|
||||
"title": "Disk interface for the installed hdb_disk_image"
|
||||
},
|
||||
"hdc_disk_interface": {
|
||||
"$ref": "#/definitions/qemu_disk_interfaces",
|
||||
"title": "Disk interface for the installed hdc_disk_image"
|
||||
},
|
||||
"hdd_disk_interface": {
|
||||
"$ref": "#/definitions/qemu_disk_interfaces",
|
||||
"title": "Disk interface for the installed hdd_disk_image"
|
||||
},
|
||||
"platform": {
|
||||
"enum": [
|
||||
"aarch64",
|
||||
"alpha",
|
||||
"arm",
|
||||
"cris",
|
||||
"i386",
|
||||
"lm32",
|
||||
"m68k",
|
||||
"microblaze",
|
||||
"microblazeel",
|
||||
"mips",
|
||||
"mips64",
|
||||
"mips64el",
|
||||
"mipsel",
|
||||
"moxie",
|
||||
"or32",
|
||||
"ppc",
|
||||
"ppc64",
|
||||
"ppcemb",
|
||||
"s390x",
|
||||
"sh4",
|
||||
"sh4eb",
|
||||
"sparc",
|
||||
"sparc64",
|
||||
"tricore",
|
||||
"unicore32",
|
||||
"x86_64",
|
||||
"xtensa",
|
||||
"xtensaeb"
|
||||
],
|
||||
"title": "Platform to emulate"
|
||||
},
|
||||
"console_type": {
|
||||
"enum": [
|
||||
"telnet",
|
||||
"vnc",
|
||||
"spice",
|
||||
"spice+agent"
|
||||
],
|
||||
"title": "Type of console connection for the administration of the appliance"
|
||||
},
|
||||
"boot_priority": {
|
||||
"enum": [
|
||||
"d",
|
||||
"c",
|
||||
"dc",
|
||||
"cd",
|
||||
"n",
|
||||
"nc",
|
||||
"nd",
|
||||
"cn",
|
||||
"dn"
|
||||
],
|
||||
"title": "Optional define the disk boot priory. Refer to -boot option in qemu manual for more details."
|
||||
},
|
||||
"kernel_command_line": {
|
||||
"type": "string",
|
||||
"title": "Command line parameters send to the kernel"
|
||||
},
|
||||
"options": {
|
||||
"type": "string",
|
||||
"title": "Optional additional qemu command line options"
|
||||
},
|
||||
"cpu_throttling": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"title": "Throttle the CPU"
|
||||
},
|
||||
"tpm": {
|
||||
"type": "boolean",
|
||||
"title": "Enable the Trusted Platform Module (TPM)"
|
||||
},
|
||||
"uefi": {
|
||||
"type": "boolean",
|
||||
"title": "Enable the UEFI boot mode"
|
||||
},
|
||||
"on_close": {
|
||||
"title": "Action to execute on the VM is closed",
|
||||
"enum": [
|
||||
"power_off",
|
||||
"shutdown_signal",
|
||||
"save_vm_state"
|
||||
]
|
||||
},
|
||||
"process_priority": {
|
||||
"title": "Process priority for QEMU",
|
||||
"enum": [
|
||||
"realtime",
|
||||
"very high",
|
||||
"high",
|
||||
"normal",
|
||||
"low",
|
||||
"very low",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"appliance_id": {
|
||||
"title": "Appliance ID",
|
||||
"type": "string",
|
||||
"minLength": 36,
|
||||
"maxLength": 36,
|
||||
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Appliance name"
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/definitions/categories",
|
||||
"title": "Category of the appliance"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"title": "Description of the appliance. Could be a marketing description"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"title": "Name of the vendor"
|
||||
},
|
||||
"vendor_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"title": "Website of the vendor"
|
||||
},
|
||||
"vendor_logo_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"title": "Link to the vendor logo (used by the GNS3 marketplace)"
|
||||
},
|
||||
"documentation_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"title": "An optional documentation for using the appliance on vendor website"
|
||||
},
|
||||
"product_name": {
|
||||
"type": "string",
|
||||
"title": "Product name"
|
||||
},
|
||||
"product_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"title": "An optional product url on vendor website"
|
||||
},
|
||||
"registry_version": {
|
||||
"enum": [
|
||||
8
|
||||
],
|
||||
"title": "Version of the registry compatible with this appliance (version >=8 introduced breaking changes)"
|
||||
},
|
||||
"status": {
|
||||
"enum": [
|
||||
"stable",
|
||||
"experimental",
|
||||
"broken"
|
||||
],
|
||||
"title": "Document if the appliance is working or not"
|
||||
},
|
||||
"availability": {
|
||||
"enum": [
|
||||
"free",
|
||||
"with-registration",
|
||||
"free-to-try",
|
||||
"service-contract"
|
||||
],
|
||||
"title": "About image availability: can be downloaded directly; download requires a free registration; paid but a trial version (time or feature limited) is available; not available publicly"
|
||||
},
|
||||
"maintainer": {
|
||||
"type": "string",
|
||||
"title": "Maintainer name"
|
||||
},
|
||||
"maintainer_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"title": "Maintainer email"
|
||||
},
|
||||
"installation_instructions": {
|
||||
"type": "string",
|
||||
"title": "Optional installation instructions"
|
||||
},
|
||||
"usage": {
|
||||
"type": "string",
|
||||
"title": "How to use the appliance"
|
||||
},
|
||||
"default_username": {
|
||||
"type": "string",
|
||||
"title": "Default username for the appliance"
|
||||
},
|
||||
"default_password": {
|
||||
"type": "string",
|
||||
"title": "Default password for the appliance"
|
||||
},
|
||||
"symbol": {
|
||||
"type": "string",
|
||||
"title": "An optional symbol for the appliance"
|
||||
},
|
||||
"settings": {
|
||||
"type": "array",
|
||||
"title": "Settings for running the appliance",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"title": "Emulator settings",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name of the settings set"
|
||||
},
|
||||
"default": {
|
||||
"type": "boolean",
|
||||
"title": "Whether these are the default settings"
|
||||
},
|
||||
"inherit_default_properties": {
|
||||
"type": "boolean",
|
||||
"title": "Whether the default properties should be used",
|
||||
"default": "true"
|
||||
},
|
||||
"template_type": {
|
||||
"enum": [
|
||||
"docker",
|
||||
"iou",
|
||||
"dynamips",
|
||||
"qemu"
|
||||
],
|
||||
"title": "Type of emulator properties"
|
||||
},
|
||||
"template_properties": {
|
||||
"type": "object",
|
||||
"title": "Properties for the template",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/qemu_properties"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/dynamips_properties"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/iou_properties"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/docker_properties"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"template_type",
|
||||
"template_properties"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"images": {
|
||||
"type": "array",
|
||||
"title": "Images for this appliance",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"title": "An image file",
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"title": "Filename"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"title": "Version of the image file"
|
||||
},
|
||||
"md5sum": {
|
||||
"type": "string",
|
||||
"title": "MD5 cheksum of the image file",
|
||||
"pattern": "^[a-f0-9]{32}$"
|
||||
},
|
||||
"checksum": {
|
||||
"type": "string",
|
||||
"title": "checksum of the image file"
|
||||
},
|
||||
"checksum_type": {
|
||||
"title": "checksum type of the image file",
|
||||
"enum": [
|
||||
"md5"
|
||||
]
|
||||
},
|
||||
"filesize": {
|
||||
"type": "integer",
|
||||
"title": "File size in bytes of the image file"
|
||||
},
|
||||
"download_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"title": "Download URL where you can download the image file from a browser"
|
||||
},
|
||||
"direct_download_url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"title": "Optional. Non authenticated URL to the image file where you can download the image directly"
|
||||
},
|
||||
"compression": {
|
||||
"enum": [
|
||||
"bzip2",
|
||||
"gzip",
|
||||
"lzma",
|
||||
"xz",
|
||||
"rar",
|
||||
"zip",
|
||||
"7z"
|
||||
],
|
||||
"title": "Optional, compression type of direct download URL image."
|
||||
},
|
||||
"compression_target": {
|
||||
"type": "string",
|
||||
"title": "Optional, file name of the image file inside the compressed file."
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"filename",
|
||||
"version",
|
||||
"md5sum",
|
||||
"filesize"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"filename",
|
||||
"version",
|
||||
"checksum",
|
||||
"filesize"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"versions": {
|
||||
"type": "array",
|
||||
"title": "Versions of the appliance",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"title": "A version of the appliance",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name of the version"
|
||||
},
|
||||
"settings": {
|
||||
"type": "string",
|
||||
"title": "Template settings to use to run the version"
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/definitions/categories",
|
||||
"title": "Category of the version"
|
||||
},
|
||||
"installation_instructions": {
|
||||
"type": "string",
|
||||
"title": "Optional installation instructions for the version"
|
||||
},
|
||||
"usage": {
|
||||
"type": "string",
|
||||
"title": "Optional instructions about using the version"
|
||||
},
|
||||
"default_username": {
|
||||
"type": "string",
|
||||
"title": "Default username for the version"
|
||||
},
|
||||
"default_password": {
|
||||
"type": "string",
|
||||
"title": "Default password for the version"
|
||||
},
|
||||
"symbol": {
|
||||
"type": "string",
|
||||
"title": "An optional symbol for the version"
|
||||
},
|
||||
"images": {
|
||||
"type": "object",
|
||||
"title": "Images used for this version",
|
||||
"properties": {
|
||||
"kernel_image": {
|
||||
"type": "string",
|
||||
"title": "Kernel image (Qemu only)"
|
||||
},
|
||||
"initrd": {
|
||||
"type": "string",
|
||||
"title": "Initrd disk image (Qemu only)"
|
||||
},
|
||||
"image": {
|
||||
"type": "string",
|
||||
"title": "OS image (IOU and Dynamips only)"
|
||||
},
|
||||
"bios_image": {
|
||||
"type": "string",
|
||||
"title": "Bios image (Qemu only)"
|
||||
},
|
||||
"hda_disk_image": {
|
||||
"type": "string",
|
||||
"title": "Hda disk image (Qemu only)"
|
||||
},
|
||||
"hdb_disk_image": {
|
||||
"type": "string",
|
||||
"title": "Hdc disk image (Qemu only)"
|
||||
},
|
||||
"hdc_disk_image": {
|
||||
"type": "string",
|
||||
"title": "Hdd disk image (Qemu only)"
|
||||
},
|
||||
"hdd_disk_image": {
|
||||
"type": "string",
|
||||
"title": "Hdd disk image (Qemu only)"
|
||||
},
|
||||
"cdrom_image": {
|
||||
"type": "string",
|
||||
"title": "cdrom image (Qemu only)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"appliance_id",
|
||||
"name",
|
||||
"category",
|
||||
"description",
|
||||
"vendor_name",
|
||||
"vendor_url",
|
||||
"product_name",
|
||||
"registry_version",
|
||||
"status",
|
||||
"maintainer",
|
||||
"maintainer_email",
|
||||
"settings"
|
||||
]
|
||||
}
|
||||
118
gns3/settings.py
118
gns3/settings.py
@@ -55,28 +55,29 @@ if sys.platform.startswith("win"):
|
||||
# windows 32-bit
|
||||
program_files_x86 = program_files = os.environ["PROGRAMFILES"]
|
||||
|
||||
PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Putty (normal standalone version)': 'putty_standalone.exe -telnet %h %p -loghost "%d"',
|
||||
'MobaXterm': r'"{}\Mobatek\MobaXterm Personal Edition\MobaXterm.exe" -newtab "telnet %h %p"'.format(program_files_x86),
|
||||
'Royal TS V3': r'{}\code4ward.net\Royal TS V3\RTS3App.exe /connectadhoc:%h /adhoctype:terminal /p:IsTelnetConnection="true" /p:ConnectionType="telnet;Telnet Connection" /p:Port="%p" /p:Name="%d"'.format(program_files),
|
||||
'Royal TS V5': r'"{}\Royal TS V5\RoyalTS.exe" /protocol:terminal /using:adhoc /uri:"%h" /property:Port="%p" /property:IsTelnetConnection="true" /property:Name="%d"'.format(program_files_x86),
|
||||
'SuperPutty': r'SuperPutty.exe -telnet "%h -P %p -wt \"%d\""',
|
||||
'SecureCRT': r'"{}\VanDyke Software\SecureCRT\SecureCRT.exe" /N "%d" /T /TELNET %h %p'.format(program_files),
|
||||
'SecureCRT (personal profile)': r'"{}\AppData\Local\VanDyke Software\SecureCRT\SecureCRT.exe" /T /N "%d" /TELNET %h %p'.format(userprofile),
|
||||
'TeraTerm Pro': r'"{}\teraterm\ttermpro.exe" /W="%d" /M="ttstart.macro" /T=1 %h %p'.format(program_files_x86),
|
||||
'Telnet': 'telnet %h %p',
|
||||
'Windows Terminal': 'wt.exe -w 1 new-tab --title %d telnet %h %p',
|
||||
'Xshell 4': r'"{}\NetSarang\Xshell 4\xshell.exe" -url telnet://%h:%p'.format(program_files_x86),
|
||||
'Xshell 5': r'"{}\NetSarang\Xshell 5\xshell.exe" -url telnet://%h:%p -newtab %d'.format(program_files_x86),
|
||||
'ZOC 6': r'"{}\ZOC6\zoc.exe" "/TELNET:%h:%p" /TABBED "/TITLE:%d"'.format(program_files_x86)}
|
||||
PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Putty (normal standalone version)': 'putty_standalone.exe -telnet {host} {port} -loghost "{name}"',
|
||||
'KiTTY': r'kitty -title "{name}" telnet://{host} {port}',
|
||||
'MobaXterm': r'"{}\Mobatek\MobaXterm Personal Edition\MobaXterm.exe" -newtab "telnet {{host}} {{port}}"'.format(program_files_x86),
|
||||
'Royal TS V3': r'{}\code4ward.net\Royal TS V3\RTS3App.exe /connectadhoc:{{host}} /adhoctype:terminal /p:IsTelnetConnection="true" /p:ConnectionType="telnet;Telnet Connection" /p:Port="{{port}}" /p:Name="{{name}}"'.format(program_files),
|
||||
'Royal TS V5': r'"{}\Royal TS V5\RoyalTS.exe" /protocol:terminal /using:adhoc /uri:"{{host}}" /property:Port="{{port}}" /property:IsTelnetConnection="true" /property:Name="{{name}}"'.format(program_files_x86),
|
||||
'SuperPutty': r'SuperPutty.exe -telnet "{host} -P {port} -wt \"{name}\""',
|
||||
'SecureCRT': r'"{}\VanDyke Software\SecureCRT\SecureCRT.exe" /N "{{name}}" /T /TELNET {{host}} {{port}}'.format(program_files),
|
||||
'SecureCRT (personal profile)': r'"{}\AppData\Local\VanDyke Software\SecureCRT\SecureCRT.exe" /T /N "{{name}}" /TELNET {{host}} {{port}}'.format(userprofile),
|
||||
'TeraTerm Pro': r'"{}\teraterm\ttermpro.exe" /W="{{name}}" /M="ttstart.macro" /T=1 {{host}} {{port}}'.format(program_files_x86),
|
||||
'Telnet': 'telnet {host} {port}',
|
||||
'Windows Terminal': 'wt.exe -w 1 new-tab --title {name} telnet {host} {port}',
|
||||
'Xshell 4': r'"{}\NetSarang\Xshell 4\xshell.exe" -url telnet://{{host}}:{{port}}'.format(program_files_x86),
|
||||
'Xshell 5': r'"{}\NetSarang\Xshell 5\xshell.exe" -url telnet://{{host}}:{{port}} -newtab {{name}}'.format(program_files_x86),
|
||||
'ZOC 6': r'"{}\ZOC6\zoc.exe" "/TELNET:{{host}}:{{port}}" /TABBED "/TITLE:{{name}}"'.format(program_files_x86)}
|
||||
|
||||
# default on Windows
|
||||
if shutil.which("Solar-PuTTY.exe"):
|
||||
# Solar-Putty is the default if it is installed.
|
||||
PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3)"] = 'Solar-PuTTY.exe --telnet --hostname %h --port %p --name "%d"'
|
||||
PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3)"] = 'Solar-PuTTY.exe --telnet --hostname {host} --port {port} --name "{name}"'
|
||||
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3)"]
|
||||
DEFAULT_DELAY_CONSOLE_ALL = 1500
|
||||
else:
|
||||
PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3 downloaded from gns3.com)"] = 'Solar-PuTTY.exe --telnet --hostname %h --port %p --name "%d"'
|
||||
PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Solar-Putty (included with GNS3 downloaded from gns3.com)"] = 'Solar-PuTTY.exe --telnet --hostname {host} --port {port} --name "{name}"'
|
||||
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Putty (normal standalone version)"]
|
||||
|
||||
elif sys.platform.startswith("darwin"):
|
||||
@@ -86,7 +87,7 @@ elif sys.platform.startswith("darwin"):
|
||||
r""" -e 'set posix_path to do shell script "echo \"$PATH\""'"""
|
||||
r""" -e 'tell application "Terminal"'"""
|
||||
r""" -e 'activate'"""
|
||||
r""" -e 'do script "echo -n -e \"\\033]0;%d\\007\"; clear; PATH=" & quoted form of posix_path & " telnet %h %p ; exit"'"""
|
||||
r""" -e 'do script "echo -n -e \"\\033]0;{name}\\007\"; clear; PATH=" & quoted form of posix_path & " telnet {host} {port} ; exit"'"""
|
||||
r""" -e 'end tell'""",
|
||||
'Terminal tabbed (experimental)': r"""osascript"""
|
||||
r""" -e 'set posix_path to do shell script "echo \"$PATH\""'"""
|
||||
@@ -102,7 +103,7 @@ elif sys.platform.startswith("darwin"):
|
||||
r""" -e 'repeat while the busy of window 1 = true'"""
|
||||
r""" -e 'delay 0.01'"""
|
||||
r""" -e 'end repeat'"""
|
||||
r""" -e 'do script "echo -n -e \"\\033]0;%d\\007\"; clear; PATH=" & quoted form of posix_path & " telnet %h %p ; exit" in window 1'"""
|
||||
r""" -e 'do script "echo -n -e \"\\033]0;{name}\\007\"; clear; PATH=" & quoted form of posix_path & " telnet {host} {port} ; exit" in window 1'"""
|
||||
r""" -e 'end tell'""",
|
||||
'iTerm2 2.x': r"""osascript"""
|
||||
r""" -e 'set posix_path to do shell script "echo \"$PATH\""'"""
|
||||
@@ -117,7 +118,7 @@ elif sys.platform.startswith("darwin"):
|
||||
r""" -e ' set s to (make new session at the end of sessions)'"""
|
||||
r""" -e ' tell s'"""
|
||||
r""" -e ' exec command "sh"'"""
|
||||
r""" -e ' write text "PATH=" & quoted form of posix_path & " exec telnet %h %p"'"""
|
||||
r""" -e ' write text "PATH=" & quoted form of posix_path & " exec telnet {host} {port}"'"""
|
||||
r""" -e ' end tell'"""
|
||||
r""" -e 'end tell'"""
|
||||
r""" -e 'end tell'""",
|
||||
@@ -134,33 +135,33 @@ elif sys.platform.startswith("darwin"):
|
||||
r""" -e ' create tab with default profile command "sh"'"""
|
||||
r""" -e ' set s to current session'"""
|
||||
r""" -e ' tell s'"""
|
||||
r""" -e ' set name to "%d"'"""
|
||||
r""" -e ' write text "PATH=" & quoted form of posix_path & " exec telnet %h %p"'"""
|
||||
r""" -e ' set name to "{name}"'"""
|
||||
r""" -e ' write text "PATH=" & quoted form of posix_path & " exec telnet {host} {port}"'"""
|
||||
r""" -e ' end tell'"""
|
||||
r""" -e 'end tell'"""
|
||||
r""" -e 'end tell'""",
|
||||
'Royal TSX': "open 'rtsx://telnet%3A%2F%2F%h:%p'",
|
||||
'SecureCRT': '/Applications/SecureCRT.app/Contents/MacOS/SecureCRT /N "%d" /T /TELNET %h %p',
|
||||
'ZOC 6': '/Applications/zoc6.app/Contents/MacOS/zoc6 "/TELNET:%h:%p" /TABBED "/TITLE:%d"',
|
||||
'ZOC 7': '/Applications/zoc7.app/Contents/MacOS/zoc7 "/TELNET:%h:%p" /TABBED "/TITLE:%d"',
|
||||
'ZOC 8': '/Applications/zoc8.app/Contents/MacOS/zoc8 "/TELNET:%h:%p" /TABBED "/TITLE:%d"'
|
||||
'Royal TSX': "open 'rtsx://telnet%3A%2F%2F{host}:{port}'",
|
||||
'SecureCRT': '/Applications/SecureCRT.app/Contents/MacOS/SecureCRT /N "{name}" /T /TELNET {host} {port}',
|
||||
'ZOC 6': '/Applications/zoc6.app/Contents/MacOS/zoc6 "/TELNET:{host}:{port}" /TABBED "/TITLE:{name}"',
|
||||
'ZOC 7': '/Applications/zoc7.app/Contents/MacOS/zoc7 "/TELNET:{host}:{port}" /TABBED "/TITLE:{name}"',
|
||||
'ZOC 8': '/Applications/zoc8.app/Contents/MacOS/zoc8 "/TELNET:{host}:{port}" /TABBED "/TITLE:{name}"'
|
||||
}
|
||||
|
||||
# default Mac OS X Telnet console command
|
||||
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Terminal"]
|
||||
|
||||
else:
|
||||
PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Xterm': 'xterm -T "%d" -e "telnet %h %p"',
|
||||
'Putty': 'putty -telnet %h %p -title "%d" -sl 2500 -fg SALMON1 -bg BLACK',
|
||||
'Gnome Terminal': 'gnome-terminal --tab -t "%d" -- telnet %h %p',
|
||||
'Xfce4 Terminal': 'xfce4-terminal --tab -T "%d" -e "telnet %h %p"',
|
||||
'ROXTerm': 'roxterm -n "%d" --tab -e "telnet %h %p"',
|
||||
'KDE Konsole': 'konsole --new-tab -p tabtitle="%d" -e "telnet %h %p"',
|
||||
'SecureCRT': 'SecureCRT /T /N "%d" /TELNET %h %p',
|
||||
'Mate Terminal': 'mate-terminal --tab -e "telnet %h %p" -t "%d"',
|
||||
'terminator': 'terminator -e "telnet %h %p" -T "%d"',
|
||||
'urxvt': 'urxvt -title %d -e telnet %h %p',
|
||||
'kitty': 'kitty -T %d telnet %h %p'}
|
||||
PRECONFIGURED_TELNET_CONSOLE_COMMANDS = {'Xterm': 'xterm -T "{name}" -e "telnet {host} {port}"',
|
||||
'Putty': 'putty -telnet {host} {port} -title "{name}" -sl 2500 -fg SALMON1 -bg BLACK',
|
||||
'Gnome Terminal': 'gnome-terminal --tab -t "{name}" -- telnet {host} {port}',
|
||||
'Xfce4 Terminal': 'xfce4-terminal --tab -T "{name}" -e "telnet {host} {port}"',
|
||||
'ROXTerm': 'roxterm -n "{name}" --tab -e "telnet {host} {port}"',
|
||||
'KDE Konsole': 'konsole --new-tab -p tabtitle="{name}" -e "telnet {host} {port}"',
|
||||
'SecureCRT': 'SecureCRT /T /N "{name}" /TELNET {host} {port}',
|
||||
'Mate Terminal': 'mate-terminal --tab -e "telnet {host} {port}" -t "{name}"',
|
||||
'terminator': 'terminator -e "telnet {host} {port}" -T "{name}"',
|
||||
'urxvt': 'urxvt -title {name} -e telnet {host} {port}',
|
||||
'kitty': 'kitty -T {name} telnet {host} {port}'}
|
||||
|
||||
# default Telnet console command on other systems
|
||||
DEFAULT_TELNET_CONSOLE_COMMAND = PRECONFIGURED_TELNET_CONSOLE_COMMANDS["Xterm"]
|
||||
@@ -177,8 +178,8 @@ else:
|
||||
if sys.platform.startswith("win"):
|
||||
# Windows
|
||||
PRECONFIGURED_VNC_CONSOLE_COMMANDS = {
|
||||
'TightVNC (included with GNS3)': 'tvnviewer.exe %h:%p',
|
||||
'UltraVNC': r'"{}\uvnc bvba\UltraVNC\vncviewer.exe" %h:%p'.format(program_files)
|
||||
'TightVNC (included with GNS3)': 'tvnviewer.exe {host}:{port}',
|
||||
'UltraVNC': r'"{}\uvnc bvba\UltraVNC\vncviewer.exe" {{host}}:{{port}}'.format(program_files)
|
||||
}
|
||||
|
||||
# default Windows VNC console command
|
||||
@@ -190,11 +191,11 @@ elif sys.platform.startswith("darwin"):
|
||||
'OSX builtin screen sharing': "osascript"
|
||||
" -e 'tell application \"Screen Sharing\"'"
|
||||
" -e ' display dialog \"WARNING OSX VNC support is limited if you have trouble connecting to a device please use an alternative client like Chicken of the VNC.\" buttons {\"OK\"} default button 1 with icon caution with title \"GNS3\"'"
|
||||
" -e ' open location \"vnc://%h:%p\"'"
|
||||
" -e ' open location \"vnc://{host}:{port}\"'"
|
||||
" -e 'end tell'",
|
||||
'Chicken of the VNC': "/Applications/Chicken.app/Contents/MacOS/Chicken %h:%p",
|
||||
'Chicken of the VNC < 2.2': r"/Applications/Chicken\ of\ the\ VNC.app/Contents/MacOS/Chicken\ of\ the\ VNC %h:%p",
|
||||
'Royal TSX': "open 'rtsx://vnc%3A%2F%2F%h:%p'",
|
||||
'Chicken of the VNC': "/Applications/Chicken.app/Contents/MacOS/Chicken {host}:{port}",
|
||||
'Chicken of the VNC < 2.2': r"/Applications/Chicken\ of\ the\ VNC.app/Contents/MacOS/Chicken\ of\ the\ VNC {host}:{port}",
|
||||
'Royal TSX': "open 'rtsx://vnc%3A%2F%2F{host}:{port}'",
|
||||
}
|
||||
|
||||
# default Mac OS X VNC console command
|
||||
@@ -202,10 +203,10 @@ elif sys.platform.startswith("darwin"):
|
||||
|
||||
else:
|
||||
PRECONFIGURED_VNC_CONSOLE_COMMANDS = {
|
||||
'TightVNC': 'vncviewer %h:%p',
|
||||
'Vinagre': 'vinagre %h::%p',
|
||||
'gvncviewer': 'gvncviewer %h:%P',
|
||||
'Remote Viewer': 'remote-viewer vnc://%h:%p'
|
||||
'TightVNC': 'vncviewer {host}:{port}',
|
||||
'Vinagre': 'vinagre {host}::{port}',
|
||||
'gvncviewer': 'gvncviewer {host}:{display}',
|
||||
'Remote Viewer': 'remote-viewer vnc://{host}:{port}'
|
||||
}
|
||||
|
||||
# default VNC console command on other systems
|
||||
@@ -215,7 +216,7 @@ else:
|
||||
if sys.platform.startswith("win"):
|
||||
# Windows
|
||||
PRECONFIGURED_SPICE_CONSOLE_COMMANDS = {
|
||||
'Remote Viewer': r'"{}\VirtViewer v11.0-256\bin\remote-viewer.exe" spice://%h:%p'.format(program_files),
|
||||
'Remote Viewer': r'"{}\VirtViewer v11.0-256\bin\remote-viewer.exe" spice://{{host}}:{{port}}'.format(program_files),
|
||||
}
|
||||
|
||||
# default Windows SPICE console command
|
||||
@@ -224,7 +225,7 @@ if sys.platform.startswith("win"):
|
||||
elif sys.platform.startswith("darwin"):
|
||||
# Mac OS X
|
||||
PRECONFIGURED_SPICE_CONSOLE_COMMANDS = {
|
||||
'Remote Viewer': '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer spice://%h:%p',
|
||||
'Remote Viewer': '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer spice://{host}:{port}',
|
||||
}
|
||||
|
||||
# default Mac OS X SPICE console command
|
||||
@@ -232,7 +233,7 @@ elif sys.platform.startswith("darwin"):
|
||||
|
||||
else:
|
||||
PRECONFIGURED_SPICE_CONSOLE_COMMANDS = {
|
||||
'Remote Viewer': 'remote-viewer spice://%h:%p',
|
||||
'Remote Viewer': 'remote-viewer spice://{host}:{port}',
|
||||
}
|
||||
|
||||
# default SPICE console command on other systems
|
||||
@@ -243,29 +244,28 @@ WIRESHARK_NORMAL_CAPTURE = "Wireshark Traditional Capture"
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE = "Wireshark Live Traffic Capture"
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: r"{}\Wireshark\wireshark.exe %c".format(program_files),
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE: r'tail.exe -f -c +0b %c | "{}\Wireshark\wireshark.exe" -o "gui.window_title:%d" -k -i -'.format(program_files)}
|
||||
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: r'{}\Wireshark\wireshark.exe {{pcap_file}} --capture-comment "{{project}} {{link_description}}"'.format(program_files),
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE: r'tail.exe -f -c +0b {{pcap_file}} | "{}\Wireshark\wireshark.exe" --capture-comment "{{project}} {{link_description}}" -o "gui.window_title:{{link_description}}" -k -i -'.format(program_files)}
|
||||
|
||||
elif sys.platform.startswith("darwin"):
|
||||
# Mac OS X
|
||||
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: "/usr/bin/open -a /Applications/Wireshark.app %c",
|
||||
"Wireshark V1.X Live Traffic Capture": 'tail -f -c +0 %c | /Applications/Wireshark.app/Contents/Resources/bin/wireshark -o "gui.window_title:%d" -k -i -',
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail -f -c +0 %c | /Applications/Wireshark.app/Contents/MacOS/Wireshark -o "gui.window_title:%d" -k -i -'}
|
||||
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: '/usr/bin/open -a /Applications/Wireshark.app {pcap_file} --capture-comment {project} {link_description}"',
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail -f -c +0 {pcap_file} | /Applications/Wireshark.app/Contents/MacOS/Wireshark --capture-comment "{project} {link_description}" -o "gui.window_title:{link_description}" -k -i -'}
|
||||
|
||||
elif sys.platform.startswith("freebsd"):
|
||||
# FreeBSD
|
||||
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: "wireshark %c",
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'gtail -f -c +0b %c | wireshark -o "gui.window_title:%d" -k -i -'}
|
||||
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: 'wireshark {pcap_file} --capture-comment "{project} {link_description}"',
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'gtail -f -c +0b {pcap_file} | wireshark --capture-comment "{project} {link_description}" -o "gui.window_title:{link_description}" -k -i -'}
|
||||
else:
|
||||
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: "wireshark %c",
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail -f -c +0b %c | wireshark -o "gui.window_title:%d" -k -i -'}
|
||||
PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS = {WIRESHARK_NORMAL_CAPTURE: 'wireshark {pcap_file} --capture-comment "{project} {link_description}"',
|
||||
WIRESHARK_LIVE_TRAFFIC_CAPTURE: 'tail -f -c +0b {pcap_file} | wireshark --capture-comment "{project} {link_description}" -o "gui.window_title:{link_description}" -k -i -'}
|
||||
|
||||
DEFAULT_PACKET_CAPTURE_READER_COMMAND = PRECONFIGURED_PACKET_CAPTURE_READER_COMMANDS[WIRESHARK_LIVE_TRAFFIC_CAPTURE]
|
||||
|
||||
DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = ""
|
||||
if sys.platform.startswith("win"):
|
||||
# Windows 64-bit
|
||||
DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = r'"{}\SolarWinds\ResponseTimeViewer\ResponseTimeViewer.exe" %c'.format(program_files_x86)
|
||||
DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND = r'"{}\SolarWinds\ResponseTimeViewer\ResponseTimeViewer.exe" {{pcap_file}}'.format(program_files_x86)
|
||||
|
||||
STYLES = ["Charcoal", "Classic", "Legacy"]
|
||||
|
||||
|
||||
@@ -54,14 +54,24 @@ def spiceConsole(node, port, command):
|
||||
command = command.replace("%h", host)
|
||||
command = command.replace("%p", str(port))
|
||||
command = command.replace("%d", name.replace('"', '\\"'))
|
||||
command = command.replace("%P", node.project().name().replace('"', '\\"'))
|
||||
command = command.replace("%i", node.project().id())
|
||||
command = command.replace("%n", str(node.id()))
|
||||
command = command.replace("%c", Controller.instance().httpClient().fullUrl())
|
||||
|
||||
command = command.replace("{host}", host)
|
||||
command = command.replace("{port}", str(port))
|
||||
command = command.replace("{name}", name.replace('"', '\\"'))
|
||||
command = command.replace("{project}", node.project().name())
|
||||
command = command.replace("{project_id}", node.project().id())
|
||||
command = command.replace("{node_id}", str(node.id()))
|
||||
command = command.replace("{url}", Controller.instance().httpClient().fullUrl())
|
||||
|
||||
try:
|
||||
log.debug('starting SPICE program "{}"'.format(command))
|
||||
if sys.platform.startswith("win"):
|
||||
# use the string on Windows
|
||||
subprocess.Popen(command)
|
||||
subprocess.Popen(command, env=os.environ)
|
||||
else:
|
||||
# use arguments on other platforms
|
||||
args = shlex.split(command)
|
||||
|
||||
@@ -87,7 +87,7 @@ class ConsoleThread(QtCore.QThread):
|
||||
|
||||
if sys.platform.startswith("win"):
|
||||
# use the string on Windows
|
||||
subprocess.call(command)
|
||||
subprocess.Popen(command, env=os.environ)
|
||||
else:
|
||||
# use arguments on other platforms
|
||||
try:
|
||||
@@ -102,7 +102,7 @@ class ConsoleThread(QtCore.QThread):
|
||||
# inject gnome-terminal environment variables
|
||||
if "GNOME_TERMINAL_SERVICE" not in env or "GNOME_TERMINAL_SCREEN" not in env:
|
||||
env.update(gnome_terminal_env())
|
||||
subprocess.call(args, env=env)
|
||||
subprocess.Popen(args, env=env)
|
||||
|
||||
def run(self):
|
||||
|
||||
@@ -113,10 +113,19 @@ class ConsoleThread(QtCore.QThread):
|
||||
command = self._command.replace("%h", host)
|
||||
command = command.replace("%p", str(port))
|
||||
command = command.replace("%d", self._name.replace('"', '\\"'))
|
||||
command = command.replace("%P", self._node.project().name().replace('"', '\\"'))
|
||||
command = command.replace("%i", self._node.project().id())
|
||||
command = command.replace("%n", str(self._node.id()))
|
||||
command = command.replace("%c", Controller.instance().httpClient().fullUrl())
|
||||
|
||||
command = command.replace("{host}", host)
|
||||
command = command.replace("{port}", str(port))
|
||||
command = command.replace("{name}", self._name.replace('"', '\\"'))
|
||||
command = command.replace("{project}", self._node.project().name().replace('"', '\\"'))
|
||||
command = command.replace("{project_id}", self._node.project().id())
|
||||
command = command.replace("{node_id}", str(self._node.id()))
|
||||
command = command.replace("{url}", Controller.instance().httpClient().fullUrl())
|
||||
|
||||
# If the console use an apple script we lock to avoid multiple console
|
||||
# to interact at the same time
|
||||
if sys.platform.startswith("darwin") and "osascript" in command:
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>900</width>
|
||||
<height>601</height>
|
||||
<width>726</width>
|
||||
<height>428</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -219,6 +219,27 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWizardPage" name="uiInstructionsPage">
|
||||
<property name="title">
|
||||
<string>Installation instructions</string>
|
||||
</property>
|
||||
<property name="subTitle">
|
||||
<string>Please read the following instructions in order to install your new appliance.</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="uiInstructionsTextEdit">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWizardPage" name="uiFilesWizardPage">
|
||||
<property name="title">
|
||||
<string>Required files</string>
|
||||
@@ -232,12 +253,12 @@
|
||||
<property name="indentation">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>120</number>
|
||||
</attribute>
|
||||
<attribute name="headerMinimumSectionSize">
|
||||
<number>20</number>
|
||||
</attribute>
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>120</number>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Appliance version and files</string>
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/appliance_wizard.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.9
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_ApplianceWizard(object):
|
||||
def setupUi(self, ApplianceWizard):
|
||||
ApplianceWizard.setObjectName("ApplianceWizard")
|
||||
ApplianceWizard.resize(900, 601)
|
||||
ApplianceWizard.resize(726, 428)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
@@ -112,6 +115,14 @@ class Ui_ApplianceWizard(object):
|
||||
self.uiQemuListComboBox.setObjectName("uiQemuListComboBox")
|
||||
self.horizontalLayout_2.addWidget(self.uiQemuListComboBox)
|
||||
ApplianceWizard.addPage(self.uiQemuWizardPage)
|
||||
self.uiInstructionsPage = QtWidgets.QWizardPage()
|
||||
self.uiInstructionsPage.setObjectName("uiInstructionsPage")
|
||||
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.uiInstructionsPage)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.uiInstructionsTextEdit = QtWidgets.QTextEdit(self.uiInstructionsPage)
|
||||
self.uiInstructionsTextEdit.setObjectName("uiInstructionsTextEdit")
|
||||
self.verticalLayout_3.addWidget(self.uiInstructionsTextEdit)
|
||||
ApplianceWizard.addPage(self.uiInstructionsPage)
|
||||
self.uiFilesWizardPage = QtWidgets.QWizardPage()
|
||||
self.uiFilesWizardPage.setObjectName("uiFilesWizardPage")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(self.uiFilesWizardPage)
|
||||
@@ -174,6 +185,13 @@ class Ui_ApplianceWizard(object):
|
||||
self.uiQemuWizardPage.setTitle(_translate("ApplianceWizard", "Qemu settings"))
|
||||
self.uiQemuWizardPage.setSubTitle(_translate("ApplianceWizard", "Please choose the qemu binary that will be used to run this appliance."))
|
||||
self.uiQemuListLabel.setText(_translate("ApplianceWizard", "Qemu binary:"))
|
||||
self.uiInstructionsPage.setTitle(_translate("ApplianceWizard", "Installation instructions"))
|
||||
self.uiInstructionsPage.setSubTitle(_translate("ApplianceWizard", "Please read the following instructions in order to install your new appliance."))
|
||||
self.uiInstructionsTextEdit.setHtml(_translate("ApplianceWizard", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'Ubuntu\'; font-size:11pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>"))
|
||||
self.uiFilesWizardPage.setTitle(_translate("ApplianceWizard", "Required files"))
|
||||
self.uiFilesWizardPage.setSubTitle(_translate("ApplianceWizard", "The following files are required to install the appliance"))
|
||||
self.uiApplianceVersionTreeWidget.headerItem().setText(0, _translate("ApplianceWizard", "Appliance version and files"))
|
||||
@@ -191,5 +209,4 @@ class Ui_ApplianceWizard(object):
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'Ubuntu\'; font-size:11pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">The default username/password is admin/admin. A default configuration is present.</p></body></html>"))
|
||||
|
||||
from . import resources_rc
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>965</width>
|
||||
<height>547</height>
|
||||
<width>576</width>
|
||||
<height>346</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -70,7 +70,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Or customize the command in the next input field. <br/>The following variables are replaced by GNS3: </p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h: console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p: console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P: VNC display</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%s: path of the serial connection</li></ul><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d: title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i: Project UUID</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c: server URL (<span style=" font-style:italic;">http://user:password@server:port</span>)</li></ul></body></html></string>
|
||||
<string><html><head/><body><p>Or customize the command in the next input field. <br/>The following variables are replaced by GNS3: </p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h or {host}: console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p or {port}: console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%D or {display}: VNC display</li></ul><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d or {name}: title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P or {project}: project name</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i or {project_id}: project UUID</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c or {url}: server URL (<span style=" font-style:italic;">http://user:password@server:port</span>)</li></ul></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/console_command_dialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.5.1
|
||||
# Created by: PyQt5 UI code generator 5.15.6
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_uiConsoleCommandDialog(object):
|
||||
def setupUi(self, uiConsoleCommandDialog):
|
||||
uiConsoleCommandDialog.setObjectName("uiConsoleCommandDialog")
|
||||
uiConsoleCommandDialog.resize(965, 547)
|
||||
uiConsoleCommandDialog.resize(576, 346)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
@@ -57,8 +60,8 @@ class Ui_uiConsoleCommandDialog(object):
|
||||
self.verticalLayout.addWidget(self.uiButtonBox)
|
||||
|
||||
self.retranslateUi(uiConsoleCommandDialog)
|
||||
self.uiButtonBox.accepted.connect(uiConsoleCommandDialog.accept)
|
||||
self.uiButtonBox.rejected.connect(uiConsoleCommandDialog.reject)
|
||||
self.uiButtonBox.accepted.connect(uiConsoleCommandDialog.accept) # type: ignore
|
||||
self.uiButtonBox.rejected.connect(uiConsoleCommandDialog.reject) # type: ignore
|
||||
QtCore.QMetaObject.connectSlotsByName(uiConsoleCommandDialog)
|
||||
|
||||
def retranslateUi(self, uiConsoleCommandDialog):
|
||||
@@ -67,5 +70,4 @@ class Ui_uiConsoleCommandDialog(object):
|
||||
self.label_2.setText(_translate("uiConsoleCommandDialog", "Choose a predefined command:"))
|
||||
self.uiRemovePushButton.setText(_translate("uiConsoleCommandDialog", "Remove"))
|
||||
self.uiSavePushButton.setText(_translate("uiConsoleCommandDialog", "Save"))
|
||||
self.label.setText(_translate("uiConsoleCommandDialog", "<html><head/><body><p>Or customize the command in the next input field. <br/>The following variables are replaced by GNS3: </p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h: console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p: console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%P: VNC display</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%s: path of the serial connection</li></ul><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d: title of the console</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i: Project UUID</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%c: server URL (<span style=\" font-style:italic;\">http://user:password@server:port</span>)</li></ul></body></html>"))
|
||||
|
||||
self.label.setText(_translate("uiConsoleCommandDialog", "<html><head/><body><p>Or customize the command in the next input field. <br/>The following variables are replaced by GNS3: </p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h or {host}: console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p or {port}: console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%D or {display}: VNC display</li></ul><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d or {name}: title of the console</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%P or {project}: project name</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i or {project_id}: project UUID</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%c or {url}: server URL (<span style=\" font-style:italic;\">http://user:password@server:port</span>)</li></ul></body></html>"))
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d = title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i = project UUID</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n = node UUID</li></ul><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c = server URL</li></ul></body></html></string>
|
||||
<string><html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h or {host} = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p or {port} = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d or {name} = title of the console (node name)</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P or {project} = project</li></ul><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i or {project_id} = project UUID</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n or {node_id} = node UUID</li></ul><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c or {url} = server URL</li></ul></body></html></string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
@@ -528,7 +528,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P = VNC display</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d = title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i = project UUID</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n = node UUID</li></ul></body></html></string>
|
||||
<string><html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h or {host} = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p or {port} = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P or {display} = VNC display</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d or {name} = node name</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%T or {project} = project name</li></ul><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i or {project_id} = project UUID</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n or {node_id} = node UUID</li></ul><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c or {url} = server URL</li></ul></body></html></string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
@@ -597,7 +597,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d = title of the console</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i = project UUID</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n = node UUID</li></ul><p><br/></p></body></html></string>
|
||||
<string><html><head/><body><p>Command line replacements:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h or {host} = console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p or {port} = console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d or {name} = node name</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%P or {project} = project name</li></ul><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%i or {project_id} = project UUID</li><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%n or {node_id} = node UUID</li></ul><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%c or {url} = server URL</li></ul></body></html></string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
|
||||
@@ -558,7 +558,7 @@ class Ui_GeneralPreferencesPageWidget(object):
|
||||
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiImagesTab), _translate("GeneralPreferencesPageWidget", "Binary images"))
|
||||
self.uiTelnetConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Console settings"))
|
||||
self.uiTelnetConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for Telnet:"))
|
||||
self.uiTelnetConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d = title of the console</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i = project UUID</li><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n = node UUID</li></ul><li style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%c = server URL</li></ul></body></html>"))
|
||||
self.uiTelnetConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h or {host} = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p or {port} = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d or {name} = title of the console (node name)</li><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%P or {project} = project</li></ul><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i or {project_id} = project UUID</li><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n or {node_id} = node UUID</li></ul><li style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%c or {url} = server URL</li></ul></body></html>"))
|
||||
self.uiTelnetConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
|
||||
self.uiConsoleMiscGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Miscellaneous"))
|
||||
self.uiDelayConsoleAllSpinBox.setSuffix(_translate("GeneralPreferencesPageWidget", " ms"))
|
||||
@@ -566,12 +566,12 @@ class Ui_GeneralPreferencesPageWidget(object):
|
||||
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiConsoleTab), _translate("GeneralPreferencesPageWidget", "Console applications"))
|
||||
self.uiVNCConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Settings for VNC connections"))
|
||||
self.uiVNCConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for VNC:"))
|
||||
self.uiVNCConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%P = VNC display</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d = title of the console</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i = project UUID</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n = node UUID</li></ul></body></html>"))
|
||||
self.uiVNCConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h or {host} = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p or {port} = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%P or {display} = VNC display</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d or {name} = node name</li><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%T or {project} = project name</li></ul><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i or {project_id} = project UUID</li><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n or {node_id} = node UUID</li></ul><li style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%c or {url} = server URL</li></ul></body></html>"))
|
||||
self.uiVNCConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
|
||||
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiVNCTab), _translate("GeneralPreferencesPageWidget", "VNC"))
|
||||
self.uiSPICEConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Settings for SPICE connections"))
|
||||
self.uiSPICEConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for SPICE:"))
|
||||
self.uiSPICEConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d = title of the console</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i = project UUID</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n = node UUID</li></ul><p><br/></p></body></html>"))
|
||||
self.uiSPICEConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h or {host} = console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p or {port} = console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d or {name} = node name</li><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%P or {project} = project name</li></ul><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%i or {project_id} = project UUID</li><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%n or {node_id} = node UUID</li></ul><li style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%c or {url} = server URL</li></ul></body></html>"))
|
||||
self.uiSPICEConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
|
||||
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiSPICETab), _translate("GeneralPreferencesPageWidget", "SPICE"))
|
||||
self.uiSceneWidthLabel.setText(_translate("GeneralPreferencesPageWidget", "Default width:"))
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="uiCaptureReaderCommandLineEdit">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><p>%c = capture file (PCAP format)</p></body></html></string>
|
||||
<string><html><head/><body><p>Command line replacements:</p><p>%c or {pcap_file} = capture file (PCAP format)</p><p>%P or {project} = project name</p><p>%d or {link_description} = link description</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/packet_capture_preferences_page.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.9
|
||||
# Created by: PyQt5 UI code generator 5.15.6
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_PacketCapturePreferencesPageWidget(object):
|
||||
def setupUi(self, PacketCapturePreferencesPageWidget):
|
||||
PacketCapturePreferencesPageWidget.setObjectName("PacketCapturePreferencesPageWidget")
|
||||
@@ -64,6 +67,11 @@ class Ui_PacketCapturePreferencesPageWidget(object):
|
||||
|
||||
self.retranslateUi(PacketCapturePreferencesPageWidget)
|
||||
QtCore.QMetaObject.connectSlotsByName(PacketCapturePreferencesPageWidget)
|
||||
PacketCapturePreferencesPageWidget.setTabOrder(self.uiPreconfiguredCaptureReaderCommandComboBox, self.uiPreconfiguredCaptureReaderCommandPushButton)
|
||||
PacketCapturePreferencesPageWidget.setTabOrder(self.uiPreconfiguredCaptureReaderCommandPushButton, self.uiCaptureReaderCommandLineEdit)
|
||||
PacketCapturePreferencesPageWidget.setTabOrder(self.uiCaptureReaderCommandLineEdit, self.uiAutoStartCheckBox)
|
||||
PacketCapturePreferencesPageWidget.setTabOrder(self.uiAutoStartCheckBox, self.uiCaptureAnalyzerCommandLineEdit)
|
||||
PacketCapturePreferencesPageWidget.setTabOrder(self.uiCaptureAnalyzerCommandLineEdit, self.uiRestoreDefaultsPushButton)
|
||||
|
||||
def retranslateUi(self, PacketCapturePreferencesPageWidget):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
@@ -74,6 +82,5 @@ class Ui_PacketCapturePreferencesPageWidget(object):
|
||||
self.uiCaptureReaderCommandLabel.setText(_translate("PacketCapturePreferencesPageWidget", "Packet capture reader command:"))
|
||||
self.uiAutoStartCheckBox.setText(_translate("PacketCapturePreferencesPageWidget", "Automatically start the packet capture application"))
|
||||
self.uiCaptureAnalyzerCommandLabel.setText(_translate("PacketCapturePreferencesPageWidget", "Packet capture analyzer command:"))
|
||||
self.uiCaptureReaderCommandLineEdit.setToolTip(_translate("PacketCapturePreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><p>%c = capture file (PCAP format)</p></body></html>"))
|
||||
self.uiCaptureReaderCommandLineEdit.setToolTip(_translate("PacketCapturePreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><p>%c or {pcap_file} = capture file (PCAP format)</p><p>%P or {project} = project name</p><p>%d or {link_description} = link description</p></body></html>"))
|
||||
self.uiRestoreDefaultsPushButton.setText(_translate("PacketCapturePreferencesPageWidget", "Restore defaults"))
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>270</width>
|
||||
<height>294</height>
|
||||
<width>288</width>
|
||||
<height>358</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -84,14 +84,14 @@
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="uiBorderStyleComboBox"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="uiRotationLabel">
|
||||
<property name="text">
|
||||
<string>Rotation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QSpinBox" name="uiRotationSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
@@ -114,14 +114,14 @@ editing (notes only) with ALT and '+' (or P) / ALT and '-' (or M)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="uiCornerRadiusLabel">
|
||||
<property name="text">
|
||||
<string>Corner radius:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="uiCornerRadiusSpinBox">
|
||||
<property name="suffix">
|
||||
<string>°</string>
|
||||
@@ -131,6 +131,46 @@ editing (notes only) with ALT and '+' (or P) / ALT and '-' (or M)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="uiWidthLabel">
|
||||
<property name="text">
|
||||
<string>Width:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="uiWidthSpinBox">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="uiHeightLabel">
|
||||
<property name="text">
|
||||
<string>Height:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="uiHeightSpinBox">
|
||||
<property name="suffix">
|
||||
<string> px</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/style_editor_dialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
# Created by: PyQt5 UI code generator 5.15.6
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
class Ui_StyleEditorDialog(object):
|
||||
def setupUi(self, StyleEditorDialog):
|
||||
StyleEditorDialog.setObjectName("StyleEditorDialog")
|
||||
StyleEditorDialog.resize(270, 294)
|
||||
StyleEditorDialog.resize(288, 358)
|
||||
StyleEditorDialog.setModal(True)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(StyleEditorDialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
@@ -53,7 +53,7 @@ class Ui_StyleEditorDialog(object):
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.uiBorderStyleComboBox)
|
||||
self.uiRotationLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiRotationLabel.setObjectName("uiRotationLabel")
|
||||
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.uiRotationLabel)
|
||||
self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.uiRotationLabel)
|
||||
self.uiRotationSpinBox = QtWidgets.QSpinBox(self.uiStyleSettingsGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@@ -63,14 +63,30 @@ class Ui_StyleEditorDialog(object):
|
||||
self.uiRotationSpinBox.setMinimum(-360)
|
||||
self.uiRotationSpinBox.setMaximum(360)
|
||||
self.uiRotationSpinBox.setObjectName("uiRotationSpinBox")
|
||||
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.uiRotationSpinBox)
|
||||
self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.uiRotationSpinBox)
|
||||
self.uiCornerRadiusLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiCornerRadiusLabel.setObjectName("uiCornerRadiusLabel")
|
||||
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.uiCornerRadiusLabel)
|
||||
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.uiCornerRadiusLabel)
|
||||
self.uiCornerRadiusSpinBox = QtWidgets.QSpinBox(self.uiStyleSettingsGroupBox)
|
||||
self.uiCornerRadiusSpinBox.setMaximum(100)
|
||||
self.uiCornerRadiusSpinBox.setObjectName("uiCornerRadiusSpinBox")
|
||||
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uiCornerRadiusSpinBox)
|
||||
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.uiCornerRadiusSpinBox)
|
||||
self.uiWidthLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiWidthLabel.setObjectName("uiWidthLabel")
|
||||
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.uiWidthLabel)
|
||||
self.uiWidthSpinBox = QtWidgets.QSpinBox(self.uiStyleSettingsGroupBox)
|
||||
self.uiWidthSpinBox.setMinimum(10)
|
||||
self.uiWidthSpinBox.setMaximum(1000)
|
||||
self.uiWidthSpinBox.setObjectName("uiWidthSpinBox")
|
||||
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uiWidthSpinBox)
|
||||
self.uiHeightLabel = QtWidgets.QLabel(self.uiStyleSettingsGroupBox)
|
||||
self.uiHeightLabel.setObjectName("uiHeightLabel")
|
||||
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.uiHeightLabel)
|
||||
self.uiHeightSpinBox = QtWidgets.QSpinBox(self.uiStyleSettingsGroupBox)
|
||||
self.uiHeightSpinBox.setMinimum(10)
|
||||
self.uiHeightSpinBox.setMaximum(1000)
|
||||
self.uiHeightSpinBox.setObjectName("uiHeightSpinBox")
|
||||
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.uiHeightSpinBox)
|
||||
self.verticalLayout.addWidget(self.uiStyleSettingsGroupBox)
|
||||
self.uiButtonBox = QtWidgets.QDialogButtonBox(StyleEditorDialog)
|
||||
self.uiButtonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
@@ -100,4 +116,8 @@ class Ui_StyleEditorDialog(object):
|
||||
self.uiRotationSpinBox.setSuffix(_translate("StyleEditorDialog", "°"))
|
||||
self.uiCornerRadiusLabel.setText(_translate("StyleEditorDialog", "Corner radius:"))
|
||||
self.uiCornerRadiusSpinBox.setSuffix(_translate("StyleEditorDialog", "°"))
|
||||
self.uiWidthLabel.setText(_translate("StyleEditorDialog", "Width:"))
|
||||
self.uiWidthSpinBox.setSuffix(_translate("StyleEditorDialog", " px"))
|
||||
self.uiHeightLabel.setText(_translate("StyleEditorDialog", "Height:"))
|
||||
self.uiHeightSpinBox.setSuffix(_translate("StyleEditorDialog", " px"))
|
||||
from . import resources_rc
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2014 GNS3 Technologies Inc.
|
||||
# Copyright (C) 2023 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -15,50 +15,35 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
import pkg_resources
|
||||
import atexit
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import importlib_resources
|
||||
except ImportError:
|
||||
from importlib import resources as importlib_resources
|
||||
|
||||
|
||||
from contextlib import ExitStack
|
||||
resource_manager = ExitStack()
|
||||
atexit.register(resource_manager.close)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
egg_cache_dir = tempfile.mkdtemp()
|
||||
pkg_resources.set_extraction_path(egg_cache_dir)
|
||||
except ValueError:
|
||||
# If the path is already set the module throw an error
|
||||
pass
|
||||
|
||||
|
||||
@atexit.register
|
||||
def clean_egg_cache():
|
||||
try:
|
||||
import shutil
|
||||
shutil.rmtree(egg_cache_dir, ignore_errors=True)
|
||||
except Exception:
|
||||
# We don't care if we can not cleanup
|
||||
pass
|
||||
|
||||
|
||||
def get_resource(resource_name):
|
||||
"""
|
||||
Return a resource in current directory or in frozen package
|
||||
"""
|
||||
|
||||
resource_path = None
|
||||
if hasattr(sys, "frozen"):
|
||||
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), resource_name))
|
||||
if sys.platform.startswith("darwin") and not os.path.exists(resource_path):
|
||||
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), "lib", resource_name))
|
||||
elif not hasattr(sys, "frozen"):
|
||||
if pkg_resources.resource_exists("gns3", resource_name):
|
||||
try:
|
||||
resource_path = pkg_resources.resource_filename("gns3", resource_name)
|
||||
except pkg_resources.ExtractionError as e:
|
||||
log.fatal(e)
|
||||
sys.stderr.write(e)
|
||||
sys.exit(1)
|
||||
resource_path = os.path.normpath(resource_path)
|
||||
else:
|
||||
resource_path = os.path.dirname(os.path.realpath(__file__))
|
||||
resource_path = os.path.join(resource_path, "..", "..", "resources", resource_name)
|
||||
else:
|
||||
ref = importlib_resources.files("gns3") / resource_name
|
||||
path = resource_manager.enter_context(importlib_resources.as_file(ref))
|
||||
if os.path.exists(path):
|
||||
resource_path = os.path.normpath(path)
|
||||
return resource_path
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "2.2.42"
|
||||
__version_info__ = (2, 2, 42, 0)
|
||||
__version__ = "2.2.44"
|
||||
__version_info__ = (2, 2, 44, 0)
|
||||
|
||||
if "dev" in __version__:
|
||||
try:
|
||||
import os
|
||||
|
||||
@@ -48,16 +48,27 @@ def vncConsole(node, port, command):
|
||||
# replace the place-holders by the actual values
|
||||
command = command.replace("%h", host)
|
||||
command = command.replace("%p", str(port))
|
||||
command = command.replace("%P", str(port - 5900))
|
||||
command = command.replace("%D", str(port - 5900))
|
||||
command = command.replace("%d", name.replace('"', '\\"'))
|
||||
command = command.replace("%P", node.project().name().replace('"', '\\"'))
|
||||
command = command.replace("%i", node.project().id())
|
||||
command = command.replace("%n", str(node.id()))
|
||||
command = command.replace("%c", Controller.instance().httpClient().fullUrl())
|
||||
|
||||
command = command.replace("{host}", host)
|
||||
command = command.replace("{port}", str(port))
|
||||
command = command.replace("{display}", str(port - 5900))
|
||||
command = command.replace("{name}", name.replace('"', '\\"'))
|
||||
command = command.replace("{project}", node.project().name().replace('"', '\\"'))
|
||||
command = command.replace("{project_id}", node.project().id())
|
||||
command = command.replace("{node_id}", str(node.id()))
|
||||
command = command.replace("{url}", Controller.instance().httpClient().fullUrl())
|
||||
|
||||
try:
|
||||
log.debug('starting VNC program "{}"'.format(command))
|
||||
if sys.platform.startswith("win"):
|
||||
# use the string on Windows
|
||||
subprocess.Popen(command)
|
||||
subprocess.Popen(command, env=os.environ)
|
||||
else:
|
||||
# use arguments on other platforms
|
||||
args = shlex.split(command)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
-rrequirements.txt
|
||||
|
||||
PyQt5==5.15.7
|
||||
PyQt5-Qt5==5.15.2
|
||||
PyQt5-sip==12.12.2
|
||||
PyQt5==5.15.9
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
jsonschema>=4.17.3,<4.18; python_version >= '3.7'
|
||||
jsonschema>=4.17.3,<4.18; python_version >= '3.7' # v4.17.3 is the last version to support Python 3.7
|
||||
jsonschema==3.2.0; python_version < '3.7' # v3.2.0 is the last version to support Python 3.6
|
||||
sentry-sdk==1.29.2,<1.30
|
||||
psutil==5.9.5
|
||||
sentry-sdk==1.34.0,<1.35
|
||||
psutil==5.9.6
|
||||
distro>=1.8.0
|
||||
truststore>=0.7.0; python_version >= '3.10'
|
||||
truststore>=0.8.0; python_version >= '3.10'
|
||||
importlib-resources>=1.3; python_version < '3.9'
|
||||
setuptools>=60.8.1; python_version >= '3.7'
|
||||
setuptools==59.6.0; python_version < '3.7' # v59.6.0 is the last version to support Python 3.6
|
||||
|
||||
1
setup.py
1
setup.py
@@ -101,6 +101,7 @@ setup(
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -75,6 +75,7 @@ def controller():
|
||||
Controller._instance = None
|
||||
c = Controller.instance()
|
||||
c._http_client = MagicMock()
|
||||
c._http_client.fullUrl.return_value = "http://localhost:3080"
|
||||
return c
|
||||
|
||||
|
||||
@@ -172,7 +173,7 @@ def local_server_config():
|
||||
return LocalServerConfig.instance()
|
||||
|
||||
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
@pytest.fixture(autouse=True)
|
||||
def run_around_tests(local_config, main_window):
|
||||
"""
|
||||
This setup a temporay environnement around tests
|
||||
|
||||
50
tests/registry/appliances/arista-veos-v8.gns3a
Normal file
50
tests/registry/appliances/arista-veos-v8.gns3a
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"appliance_id": "1c784362-8aaf-4312-b0f5-4b138cf2e25b",
|
||||
"name": "Arista vEOS",
|
||||
"category": "router",
|
||||
"description": "Arista EOS® is the core of Arista cloud networking solutions for next-generation data centers and cloud networks. Cloud architectures built with Arista EOS scale to tens of thousands of compute and storage nodes with management and provisioning capabilities that work at scale. Through its programmability, EOS enables a set of software applications that deliver workflow automation, high availability, unprecedented network visibility and analytics and rapid integration with a wide range of third-party applications for virtualization, management, automation and orchestration services.\n\nArista Extensible Operating System (EOS) is a fully programmable and highly modular, Linux-based network operation system, using familiar industry standard CLI and runs a single binary software image across the Arista switching family. Architected for resiliency and programmability, EOS has a unique multi-process state sharing architecture that separates state information and packet forwarding from protocol processing and application logic.",
|
||||
"vendor_name": "Arista",
|
||||
"vendor_url": "http://www.arista.com/",
|
||||
"documentation_url": "http://www.arista.com/docs/Manuals/ConfigGuide.pdf",
|
||||
"product_name": "Arista vEOS",
|
||||
"product_url": "https://eos.arista.com/",
|
||||
"registry_version": 8,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"settings": [
|
||||
{
|
||||
"template_type": "qemu",
|
||||
"template_properties": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 8,
|
||||
"ram": 2048,
|
||||
"platform": "x86_64",
|
||||
"console_type": "telnet"
|
||||
}
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"filename": "Aboot-veos-serial-2.1.0.iso",
|
||||
"version": "2.1.0",
|
||||
"md5sum": "2687534f2ff11b998dec0511066457c0",
|
||||
"download_url": "https://www.arista.com/en/support/software-download"
|
||||
},
|
||||
{
|
||||
"filename": "vEOS-lab-4.13.8M.vmdk",
|
||||
"version": "4.13.8M",
|
||||
"md5sum": "a47145b9e6e7a24171c0850f8755535e",
|
||||
"download_url": "https://www.arista.com/en/support/software-download"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "4.13.8M",
|
||||
"images": {
|
||||
"hda_disk_image": "Aboot-veos-serial-2.1.0.iso",
|
||||
"hdb_disk_image": "vEOS-lab-4.13.8M.vmdk"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"appliance_id": "1c784362-8aaf-4312-b0f5-4b138cf2e25b",
|
||||
"name": "Arista vEOS",
|
||||
"category": "router",
|
||||
"description": "Arista EOS® is the core of Arista cloud networking solutions for next-generation data centers and cloud networks. Cloud architectures built with Arista EOS scale to tens of thousands of compute and storage nodes with management and provisioning capabilities that work at scale. Through its programmability, EOS enables a set of software applications that deliver workflow automation, high availability, unprecedented network visibility and analytics and rapid integration with a wide range of third-party applications for virtualization, management, automation and orchestration services.\n\nArista Extensible Operating System (EOS) is a fully programmable and highly modular, Linux-based network operation system, using familiar industry standard CLI and runs a single binary software image across the Arista switching family. Architected for resiliency and programmability, EOS has a unique multi-process state sharing architecture that separates state information and packet forwarding from protocol processing and application logic.",
|
||||
@@ -11,7 +12,6 @@
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 8,
|
||||
@@ -19,7 +19,6 @@
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet"
|
||||
},
|
||||
|
||||
"images": [
|
||||
{
|
||||
"filename": "Aboot-veos-serial-2.1.0.iso",
|
||||
@@ -34,7 +33,6 @@
|
||||
"download_url": "https://www.arista.com/en/support/software-download"
|
||||
}
|
||||
],
|
||||
|
||||
"versions": [
|
||||
{
|
||||
"name": "4.13.8M",
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
@@ -19,7 +18,6 @@
|
||||
"arch": "i386",
|
||||
"console_type": "telnet"
|
||||
},
|
||||
|
||||
"images": [
|
||||
{
|
||||
"filename": "linux-microcore-3.4.1.img",
|
||||
@@ -30,7 +28,6 @@
|
||||
"direct_download_url": "http://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/linux-microcore-3.4.1.img"
|
||||
}
|
||||
],
|
||||
|
||||
"versions": [
|
||||
{
|
||||
"name": "3.4.1",
|
||||
|
||||
51
tests/registry/appliances/cisco-3745-v8.gns3a
Normal file
51
tests/registry/appliances/cisco-3745-v8.gns3a
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"appliance_id": "96dac9ff-581c-4262-a9f0-5c68890d049e",
|
||||
"category": "router",
|
||||
"status": "experimental",
|
||||
"maintainer": "GNS3 Team",
|
||||
"name": "Cisco 3745",
|
||||
"vendor_name": "Cisco",
|
||||
"product_name": "3745",
|
||||
"vendor_url": "http://www.cisco.com",
|
||||
"description": "Cisco 3745 Multiservice Access Router",
|
||||
"registry_version": 8,
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"documentation_url": "http://www.cisco.com/c/en/us/support/routers/3745-multiservice-access-router/model.html",
|
||||
"settings": [
|
||||
{
|
||||
"template_type": "dynamips",
|
||||
"template_properties": {
|
||||
"chassis": "",
|
||||
"platform": "c3745",
|
||||
"ram": 256,
|
||||
"nvram": 256,
|
||||
"startup_config": "ios_base_startup-config.txt",
|
||||
"slot0": "GT96100-FE",
|
||||
"slot1": "NM-1FE-TX",
|
||||
"slot2": "NM-4T",
|
||||
"slot3": "",
|
||||
"slot4": "",
|
||||
"wic0": "WIC-1T",
|
||||
"wic1": "WIC-1T",
|
||||
"wic2": "WIC-1T",
|
||||
"idlepc": "0x60aa1da0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "124-25d",
|
||||
"images": {
|
||||
"image": "c3745-adventerprisek9-mz.124-25d.image"
|
||||
}
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"filesize": 82053028,
|
||||
"md5sum": "ddbaf74274822b50fa9670e10c75b08f",
|
||||
"version": "124-25d",
|
||||
"filename": "c3745-adventerprisek9-mz.124-25d.image"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"appliance_id": "96dac9ff-581c-4262-a9f0-5c68890d049e",
|
||||
"category": "router",
|
||||
"status": "experimental",
|
||||
"maintainer": "GNS3 Team",
|
||||
@@ -10,7 +11,6 @@
|
||||
"registry_version": 2,
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"documentation_url": "http://www.cisco.com/c/en/us/support/routers/3745-multiservice-access-router/model.html",
|
||||
|
||||
"dynamips": {
|
||||
"chassis": "",
|
||||
"platform": "c3745",
|
||||
@@ -26,7 +26,6 @@
|
||||
"wic1": "WIC-1T",
|
||||
"wic2": "WIC-1T"
|
||||
},
|
||||
|
||||
"versions": [
|
||||
{
|
||||
"images": {
|
||||
|
||||
41
tests/registry/appliances/cisco-iou-l3-v8.gns3a
Normal file
41
tests/registry/appliances/cisco-iou-l3-v8.gns3a
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"appliance_id": "a8f5935d-7229-4b32-8a01-24ef41758f2f",
|
||||
"category": "router",
|
||||
"status": "experimental",
|
||||
"maintainer": "GNS3 Team",
|
||||
"name": "Cisco IOU L3",
|
||||
"vendor_name": "Cisco",
|
||||
"product_name": "Cisco IOU L3",
|
||||
"vendor_url": "http://www.cisco.com",
|
||||
"description": "Cisco IOS on UNIX Layer 3 image.",
|
||||
"registry_version": 8,
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"settings": [
|
||||
{
|
||||
"template_type": "iou",
|
||||
"template_properties": {
|
||||
"ethernet_adapters": 2,
|
||||
"serial_adapters": 2,
|
||||
"nvram": 128,
|
||||
"ram": 256,
|
||||
"startup_config": "iou_l3_base_startup-config.txt"
|
||||
}
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"images": {
|
||||
"image": "i86bi-linux-l3-adventerprisek9-15.4.1T.bin"
|
||||
},
|
||||
"name": "15.4.1T"
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"filesize": 152677848,
|
||||
"md5sum": "5d41402abc4b2a76b9719d911017c592",
|
||||
"version": "15.4.1T",
|
||||
"filename": "i86bi-linux-l3-adventerprisek9-15.4.1T.bin"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"appliance_id": "a8f5935d-7229-4b32-8a01-24ef41758f2f",
|
||||
"category": "router",
|
||||
"status": "experimental",
|
||||
"maintainer": "GNS3 Team",
|
||||
@@ -9,7 +10,6 @@
|
||||
"description": "Cisco IOS on UNIX Layer 3 image.",
|
||||
"registry_version": 2,
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
|
||||
"iou": {
|
||||
"ethernet_adapters": 2,
|
||||
"serial_adapters": 2,
|
||||
@@ -17,7 +17,6 @@
|
||||
"ram": 256,
|
||||
"startup_config": "iou_l3_base_startup-config.txt"
|
||||
},
|
||||
|
||||
"versions": [
|
||||
{
|
||||
"images": {
|
||||
|
||||
115
tests/registry/appliances/empty-vm-v8.gns3a
Normal file
115
tests/registry/appliances/empty-vm-v8.gns3a
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"appliance_id": "1cfdf900-7c30-4cb7-8f03-3f61d2581633",
|
||||
"name": "Empty VM",
|
||||
"category": "guest",
|
||||
"description": "A empty VM with empty hard disks 8G, 30G, 100G & 200G.",
|
||||
"vendor_name": "GNS3",
|
||||
"vendor_url": "https://gns3.com",
|
||||
"documentation_url": "",
|
||||
"product_name": "QEMU",
|
||||
"product_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"registry_version": 8,
|
||||
"status": "experimental",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Default at first boot the VM will start from the cdrom.",
|
||||
"settings": [
|
||||
{
|
||||
"default": true,
|
||||
"template_type": "qemu",
|
||||
"template_properties": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
"ram": 1024,
|
||||
"hda_disk_interface": "sata",
|
||||
"platform": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"boot_priority": "d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "i386 settings",
|
||||
"template_type": "qemu",
|
||||
"template_properties": {
|
||||
"platform": "i386",
|
||||
"adapters": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ARM settings",
|
||||
"inherit_default_properties": false,
|
||||
"template_type": "qemu",
|
||||
"template_properties": {
|
||||
"platform": "arm",
|
||||
"ram": 512
|
||||
}
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"filename": "empty8G.qcow2",
|
||||
"version": "8G",
|
||||
"md5sum": "f1d2c25b6990f99bd05b433ab603bdb4",
|
||||
"filesize": 197120,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty8G.qcow2/download"
|
||||
},
|
||||
{
|
||||
"filename": "empty30G.qcow2",
|
||||
"version": "30G",
|
||||
"checksum": "3411a599e822f2ac6be560a26405821a",
|
||||
"filesize": 197120,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty30G.qcow2/download"
|
||||
},
|
||||
{
|
||||
"filename": "empty100G.qcow2",
|
||||
"version": "100G",
|
||||
"checksum": "d08fdec95fffbda3f04e9a00db49295df73ae4a507396e442ba9e4ad5c14ce5a",
|
||||
"checksum_type": "sha256",
|
||||
"filesize": 198656,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty100G.qcow2/download"
|
||||
},
|
||||
{
|
||||
"filename": "empty200G.qcow2",
|
||||
"version": "200G",
|
||||
"md5sum": "d1686d2f25695dee32eab9a6f4652c7c",
|
||||
"filesize": 200192,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Empty%20Qemu%20disk/empty200G.qcow2/download"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8G",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "30G",
|
||||
"settings": "i386 settings",
|
||||
"images": {
|
||||
"hda_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "100G",
|
||||
"settings": "ARM settings",
|
||||
"images": {
|
||||
"hda_disk_image": "empty100G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "200G",
|
||||
"settings": "ARM settings",
|
||||
"usage": "This is how to use this version",
|
||||
"symbol": "ethernet_switch",
|
||||
"category": "switch",
|
||||
"images": {
|
||||
"hda_disk_image": "empty200G.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
"vendor_name": "Juniper",
|
||||
"product_name": "vSRX",
|
||||
"name": "vSRX",
|
||||
|
||||
|
||||
"description": "The vSRX delivers core firewall, networking, advanced security, and automated lifecycle management capabilities for enterprises and service providers. The industry\u2019s fastest virtual security platform, the vSRX offers firewall speeds up to 17 Gbps using only two virtual CPUs, providing scalable, secure protection across private, public, and hybrid clouds.",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"documentation_url": "http://www.juniper.net/techpubs/",
|
||||
@@ -13,7 +11,6 @@
|
||||
"status": "experimental",
|
||||
"vendor_url": "https://www.juniper.net",
|
||||
"registry_version": 1,
|
||||
|
||||
"qemu": {
|
||||
"console_type": "telnet",
|
||||
"ram": 2000,
|
||||
@@ -23,8 +20,6 @@
|
||||
"options": "-smp 2",
|
||||
"kvm": "require"
|
||||
},
|
||||
|
||||
|
||||
"images": [
|
||||
{
|
||||
"version": "12.1X47.4-domestic",
|
||||
@@ -34,7 +29,6 @@
|
||||
"download_url": "https://www.juniper.net/us/en/dm/free-vsrx-trial/"
|
||||
}
|
||||
],
|
||||
|
||||
"versions": [
|
||||
{
|
||||
"name": "12.1X47.4-domestic",
|
||||
@@ -43,4 +37,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Just start the appliance",
|
||||
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
@@ -21,7 +20,6 @@
|
||||
"console_type": "telnet",
|
||||
"kvm": "allow"
|
||||
},
|
||||
|
||||
"images": [
|
||||
{
|
||||
"filename": "linux-microcore-3.4.1.img",
|
||||
@@ -40,7 +38,6 @@
|
||||
"direct_download_url": "http://downloads.sourceforge.net/project/gns-3/Qemu%20Appliances/linux-microcore-4.0.2-clean.img"
|
||||
}
|
||||
],
|
||||
|
||||
"versions": [
|
||||
{
|
||||
"name": "3.4.1",
|
||||
|
||||
24
tests/registry/appliances/openvswitch-v8.gns3a
Normal file
24
tests/registry/appliances/openvswitch-v8.gns3a
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"appliance_id": "40c84186-752f-4a71-b6fb-961ba36e8cf7",
|
||||
"name": "Open vSwitch",
|
||||
"category": "multilayer_switch",
|
||||
"description": "Open vSwitch is a production quality, multilayer virtual switch licensed under the open source Apache 2.0 license. It is designed to enable massive network automation through programmatic extension, while still supporting standard management interfaces and protocols (e.g. NetFlow, sFlow, IPFIX, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed to support distribution across multiple physical servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.",
|
||||
"vendor_name": "Open vSwitch",
|
||||
"vendor_url": "http://openvswitch.org/",
|
||||
"documentation_url": "http://openvswitch.org/support/",
|
||||
"product_name": "Open vSwitch",
|
||||
"registry_version": 8,
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "By default all interfaces are connected to the br0",
|
||||
"settings": [
|
||||
{
|
||||
"template_type": "docker",
|
||||
"template_properties": {
|
||||
"adapters": 16,
|
||||
"image": "gns3/openvswitch:latest"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"appliance_id": "40c84186-752f-4a71-b6fb-961ba36e8cf7",
|
||||
"name": "Open vSwitch",
|
||||
"category": "multilayer_switch",
|
||||
"description": "Open vSwitch is a production quality, multilayer virtual switch licensed under the open source Apache 2.0 license. It is designed to enable massive network automation through programmatic extension, while still supporting standard management interfaces and protocols (e.g. NetFlow, sFlow, IPFIX, RSPAN, CLI, LACP, 802.1ag). In addition, it is designed to support distribution across multiple physical servers similar to VMware's vNetwork distributed vswitch or Cisco's Nexus 1000V.",
|
||||
|
||||
@@ -202,6 +202,62 @@ def test_create_new_version():
|
||||
os.remove(wrong_appliance_file)
|
||||
|
||||
|
||||
def test_emulator():
|
||||
assert Appliance(registry, os.path.abspath("tests/registry/appliances/microcore-linux.gns3a")).emulator() == "qemu"
|
||||
assert Appliance(registry, os.path.abspath("tests/registry/appliances/cisco-iou-l3.gns3a")).emulator() == "iou"
|
||||
def test_template_type():
|
||||
assert Appliance(registry, os.path.abspath("tests/registry/appliances/microcore-linux.gns3a")).template_type() == "qemu"
|
||||
assert Appliance(registry, os.path.abspath("tests/registry/appliances/cisco-iou-l3.gns3a")).template_type() == "iou"
|
||||
|
||||
|
||||
def test_checksum_in_appliance_format_v8(registry, images_dir):
|
||||
|
||||
path_empty_8g = os.path.join(images_dir, "QEMU", "empty8G.qcow2")
|
||||
with open(path_empty_8g, 'w+') as f:
|
||||
f.write("hello")
|
||||
|
||||
appliance = Appliance(registry, os.path.abspath("tests/registry/appliances/empty-vm-v8.gns3a"))
|
||||
appliance._appliance['versions'][0]['images']['hda_disk_image']['filesize'] = 5
|
||||
appliance._appliance['versions'][0]['images']['hda_disk_image']['md5sum'] = "5d41402abc4b2a76b9719d911017c592"
|
||||
|
||||
detected = appliance.search_images_for_version("8G")
|
||||
assert detected["images"][0]["md5sum"] == "5d41402abc4b2a76b9719d911017c592"
|
||||
assert detected["images"][0]["filesize"] == 5
|
||||
|
||||
path_empty_30g = os.path.join(images_dir, "QEMU", "empty30G.qcow2")
|
||||
os.rename(path_empty_8g, path_empty_30g)
|
||||
appliance._appliance['versions'][1]['images']['hda_disk_image']['filesize'] = 5
|
||||
appliance._appliance['versions'][1]['images']['hda_disk_image']['checksum'] = "5d41402abc4b2a76b9719d911017c592"
|
||||
detected = appliance.search_images_for_version("30G")
|
||||
assert detected["images"][0]["md5sum"] == "5d41402abc4b2a76b9719d911017c592"
|
||||
assert detected["images"][0]["filesize"] == 5
|
||||
|
||||
with pytest.raises(ApplianceError):
|
||||
appliance.search_images_for_version("100G")
|
||||
|
||||
|
||||
def test_multiple_different_template_types_found():
|
||||
|
||||
appliance_path = "tests/registry/appliances/empty-vm-v8.gns3a"
|
||||
wrong_appliance_fp, wrong_appliance_file = tempfile.mkstemp()
|
||||
|
||||
with open(appliance_path, encoding='utf-8') as f:
|
||||
appliance = json.loads(f.read())
|
||||
appliance["settings"][0]["template_type"] = "dynamips"
|
||||
os.write(wrong_appliance_fp, json.dumps(appliance).encode())
|
||||
os.close(wrong_appliance_fp)
|
||||
|
||||
with pytest.raises(ApplianceError):
|
||||
Appliance(registry, wrong_appliance_file).template_type()
|
||||
|
||||
|
||||
def test_appliance_without_settings():
|
||||
|
||||
appliance_path = "tests/registry/appliances/empty-vm-v8.gns3a"
|
||||
wrong_appliance_fp, wrong_appliance_file = tempfile.mkstemp()
|
||||
|
||||
with open(appliance_path, encoding='utf-8') as f:
|
||||
appliance = json.loads(f.read())
|
||||
del appliance["settings"]
|
||||
os.write(wrong_appliance_fp, json.dumps(appliance).encode())
|
||||
os.close(wrong_appliance_fp)
|
||||
|
||||
with pytest.raises(ApplianceError):
|
||||
Appliance(registry, wrong_appliance_file).template_type()
|
||||
|
||||
@@ -64,8 +64,15 @@ def empty_config(tmpdir, images_dir, symbols_dir, local_server_config):
|
||||
return Config(path)
|
||||
|
||||
|
||||
def test_add_appliance_iou(iou_l3):
|
||||
with open("tests/registry/appliances/cisco-iou-l3.gns3a", encoding="utf-8") as f:
|
||||
@pytest.mark.parametrize(
|
||||
"appliance_file",
|
||||
[
|
||||
"cisco-iou-l3.gns3a",
|
||||
"cisco-iou-l3-v8.gns3a"
|
||||
]
|
||||
)
|
||||
def test_add_appliance_iou(iou_l3, appliance_file):
|
||||
with open("tests/registry/appliances/{}".format(appliance_file), encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
config["images"] = [
|
||||
{
|
||||
@@ -74,7 +81,7 @@ def test_add_appliance_iou(iou_l3):
|
||||
"path": iou_l3
|
||||
}
|
||||
]
|
||||
new_template = ApplianceToTemplate().new_template(config, "local")
|
||||
new_template = ApplianceToTemplate().new_template(config, "local", "15.4.1T")
|
||||
assert new_template == {
|
||||
"category": "router",
|
||||
"template_type": "iou",
|
||||
@@ -91,8 +98,15 @@ def test_add_appliance_iou(iou_l3):
|
||||
}
|
||||
|
||||
|
||||
def test_add_appliance_docker():
|
||||
with open("tests/registry/appliances/openvswitch.gns3a", encoding="utf-8") as f:
|
||||
@pytest.mark.parametrize(
|
||||
"appliance_file",
|
||||
[
|
||||
"openvswitch.gns3a",
|
||||
"openvswitch-v8.gns3a"
|
||||
]
|
||||
)
|
||||
def test_add_appliance_docker(appliance_file):
|
||||
with open("tests/registry/appliances/{}".format(appliance_file), encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
|
||||
new_template = ApplianceToTemplate().new_template(config, "local")
|
||||
@@ -108,8 +122,15 @@ def test_add_appliance_docker():
|
||||
}
|
||||
|
||||
|
||||
def test_add_appliance_dynamips(cisco_3745):
|
||||
with open("tests/registry/appliances/cisco-3745.gns3a", encoding="utf-8") as f:
|
||||
@pytest.mark.parametrize(
|
||||
"appliance_file",
|
||||
[
|
||||
"cisco-3745.gns3a",
|
||||
"cisco-3745-v8.gns3a"
|
||||
]
|
||||
)
|
||||
def test_add_appliance_dynamips(cisco_3745, appliance_file):
|
||||
with open("tests/registry/appliances/{}".format(appliance_file), encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
config["images"] = [
|
||||
{
|
||||
@@ -120,7 +141,7 @@ def test_add_appliance_dynamips(cisco_3745):
|
||||
}
|
||||
]
|
||||
|
||||
new_template = ApplianceToTemplate().new_template(config, "local")
|
||||
new_template = ApplianceToTemplate().new_template(config, "local", "124-25d")
|
||||
assert new_template == {
|
||||
"template_type": "dynamips",
|
||||
"category": "router",
|
||||
@@ -166,7 +187,6 @@ def test_add_appliance_guest(linux_microcore_img):
|
||||
"symbol": ":/symbols/qemu_guest.svg",
|
||||
"hda_disk_image": "linux-microcore-3.4.1.img",
|
||||
"name": "Micro Core Linux",
|
||||
"options": "",
|
||||
"qemu_path": "qemu-system-i386",
|
||||
"usage": "Just start the appliance",
|
||||
"ram": 32,
|
||||
@@ -238,8 +258,15 @@ def test_add_appliance_with_boot_priority(linux_microcore_img):
|
||||
assert new_template["boot_priority"] == "dc"
|
||||
|
||||
|
||||
def test_add_appliance_router_two_disk(images_dir):
|
||||
with open("tests/registry/appliances/arista-veos.gns3a", encoding="utf-8") as f:
|
||||
@pytest.mark.parametrize(
|
||||
"appliance_file",
|
||||
[
|
||||
"arista-veos.gns3a",
|
||||
"arista-veos-v8.gns3a"
|
||||
]
|
||||
)
|
||||
def test_add_appliance_router_two_disk(images_dir, appliance_file):
|
||||
with open("tests/registry/appliances/{}".format(appliance_file), encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
|
||||
config["images"] = [
|
||||
@@ -255,8 +282,8 @@ def test_add_appliance_router_two_disk(images_dir):
|
||||
}
|
||||
]
|
||||
|
||||
new_template = ApplianceToTemplate().new_template(config, "local")
|
||||
assert new_template == {
|
||||
new_template = ApplianceToTemplate().new_template(config, "local", "4.13.8M")
|
||||
expected_result = {
|
||||
"template_type": "qemu",
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 8,
|
||||
@@ -265,12 +292,76 @@ def test_add_appliance_router_two_disk(images_dir):
|
||||
"hda_disk_image": "a",
|
||||
"hdb_disk_image": "b",
|
||||
"name": "Arista vEOS",
|
||||
"options": "",
|
||||
"qemu_path": "qemu-system-x86_64",
|
||||
"ram": 2048,
|
||||
"console_type": "telnet",
|
||||
"compute_id": "local"
|
||||
}
|
||||
if "v8" in appliance_file:
|
||||
expected_result["platform"] = "x86_64" # platform was added in v8
|
||||
assert new_template == expected_result
|
||||
|
||||
|
||||
def test_add_appliance_v8_default_properties_inheritance(images_dir):
|
||||
with open("tests/registry/appliances/empty-vm-v8.gns3a", encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
|
||||
# check that default properties are used
|
||||
new_template = ApplianceToTemplate().new_template(config, "local", "8G")
|
||||
expected_result = {
|
||||
"name": "Empty VM",
|
||||
"template_type": "qemu",
|
||||
"symbol": ":/symbols/qemu_guest.svg",
|
||||
"category": "guest",
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 1,
|
||||
"ram": 1024,
|
||||
"qemu_path": "qemu-system-x86_64",
|
||||
"hda_disk_interface": "sata",
|
||||
"platform": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"boot_priority": "d",
|
||||
"compute_id": "local",
|
||||
"usage": "Default at first boot the VM will start from the cdrom."
|
||||
}
|
||||
assert new_template == expected_result
|
||||
|
||||
# check that specific properties are used along with default properties
|
||||
new_template = ApplianceToTemplate().new_template(config, "local", "30G")
|
||||
expected_result.update(
|
||||
{
|
||||
"adapters": 8,
|
||||
"qemu_path": "qemu-system-i386",
|
||||
"platform": "i386",
|
||||
}
|
||||
)
|
||||
assert new_template == expected_result
|
||||
|
||||
# check that specific properties are used along without default properties
|
||||
new_template = ApplianceToTemplate().new_template(config, "local", "100G")
|
||||
expected_result = {
|
||||
"name": "Empty VM",
|
||||
"template_type": "qemu",
|
||||
"symbol": ":/symbols/qemu_guest.svg",
|
||||
"category": "guest",
|
||||
"ram": 512,
|
||||
"qemu_path": "qemu-system-arm",
|
||||
"platform": "arm",
|
||||
"compute_id": "local",
|
||||
"usage": "Default at first boot the VM will start from the cdrom."
|
||||
}
|
||||
assert new_template == expected_result
|
||||
|
||||
# check that specific properties are used with "usage", "symbol" and "category" defined at the version level
|
||||
new_template = ApplianceToTemplate().new_template(config, "local", "200G")
|
||||
expected_result.update(
|
||||
{
|
||||
"usage": "This is how to use this version",
|
||||
"symbol": "ethernet_switch",
|
||||
"category": "switch"
|
||||
}
|
||||
)
|
||||
assert new_template == expected_result
|
||||
|
||||
|
||||
def test_add_appliance_path_relative_to_images_dir(tmpdir, linux_microcore_img):
|
||||
|
||||
@@ -47,7 +47,7 @@ def http_client(http_request, network_manager):
|
||||
return HTTPClient({"protocol": "http", "host": "127.0.0.1", "port": "3080"}, network_manager=network_manager)
|
||||
|
||||
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
@pytest.fixture(autouse=True)
|
||||
def http_request():
|
||||
|
||||
mock = unittest.mock.Mock()
|
||||
|
||||
@@ -34,7 +34,7 @@ def images_dir(tmpdir):
|
||||
return path
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
@pytest.fixture
|
||||
def image_manager(tmpdir, images_dir):
|
||||
ImageManager._instance = None
|
||||
settings = LOCAL_SERVER_SETTINGS
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import json
|
||||
import pytest
|
||||
import logging
|
||||
import subprocess
|
||||
@@ -32,7 +31,7 @@ def local_server_path(tmpdir):
|
||||
return str(tmpdir / "gns3server")
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
@pytest.fixture
|
||||
def local_server(local_server_path, tmpdir):
|
||||
with open(str(tmpdir / "test.cfg"), "w+") as f:
|
||||
f.write("""
|
||||
@@ -87,7 +86,7 @@ def test_startLocalServer(tmpdir, local_server, local_server_path):
|
||||
'--debug',
|
||||
'--log=' + str(tmpdir / "gns3_server.log"),
|
||||
'--pid=' + str(tmpdir / "gns3_server.pid")
|
||||
], stderr=unittest.mock.ANY)
|
||||
], stderr=unittest.mock.ANY, env=unittest.mock.ANY)
|
||||
|
||||
|
||||
def test_killAlreadyRunningServer(local_server):
|
||||
|
||||
@@ -17,28 +17,30 @@
|
||||
|
||||
import os
|
||||
import shlex
|
||||
import pytest
|
||||
|
||||
from unittest.mock import patch
|
||||
from gns3.spice_console import spiceConsole
|
||||
|
||||
|
||||
def test_spice_console_on_linux_and_mac(vpcs_device):
|
||||
|
||||
with patch('subprocess.Popen') as popen, \
|
||||
patch('sys.platform', new="linux"):
|
||||
|
||||
vpcs_device.settings()["console_host"] = "localhost"
|
||||
spiceConsole(vpcs_device, '2525', 'command %h %p')
|
||||
popen.assert_called_once_with(shlex.split('command localhost 2525'), env=os.environ)
|
||||
|
||||
popen.assert_called_with(shlex.split('command localhost 2525'), env=os.environ)
|
||||
spiceConsole(vpcs_device, '2525', 'command {host} {port}')
|
||||
popen.assert_called_with(shlex.split('command localhost 2525'), env=os.environ)
|
||||
|
||||
def test_spice_console_on_windows(vpcs_device):
|
||||
with patch('subprocess.Popen') as popen, \
|
||||
|
||||
with patch('subprocess.Popen') as p, \
|
||||
patch('sys.platform', new="win"):
|
||||
vpcs_device.settings()["console_host"] = "localhost"
|
||||
spiceConsole(vpcs_device, '2525', 'command %h %p')
|
||||
popen.assert_called_once_with('command localhost 2525')
|
||||
|
||||
p.assert_called_with('command localhost 2525', env=os.environ)
|
||||
spiceConsole(vpcs_device, '2525', 'command {host} {port}')
|
||||
p.assert_called_with('command localhost 2525', env=os.environ)
|
||||
|
||||
# def test_spice_console_on_linux_with_popen_issues():
|
||||
# with patch('subprocess.Popen', side_effect=OSError("Dummy")), \
|
||||
@@ -49,9 +51,11 @@ def test_spice_console_on_windows(vpcs_device):
|
||||
|
||||
|
||||
def test_spice_console_with_ipv6_support(vpcs_device):
|
||||
|
||||
with patch('subprocess.Popen') as popen, \
|
||||
patch('sys.platform', new="linux"):
|
||||
|
||||
vpcs_device.settings()["console_host"] = "::1"
|
||||
spiceConsole(vpcs_device, '2525', 'command %h %p')
|
||||
popen.assert_called_once_with(shlex.split('command [::1] 2525'), env=os.environ)
|
||||
popen.assert_called_with(shlex.split('command [::1] 2525'), env=os.environ)
|
||||
spiceConsole(vpcs_device, '2525', 'command {host} {port}')
|
||||
popen.assert_called_with(shlex.split('command [::1] 2525'), env=os.environ)
|
||||
|
||||
@@ -26,14 +26,14 @@ from gns3.update_manager import UpdateManager
|
||||
from gns3 import version
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
@pytest.fixture
|
||||
def frozen():
|
||||
sys.frozen = True
|
||||
yield
|
||||
delattr(sys, 'frozen')
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
@pytest.fixture
|
||||
def devVersion():
|
||||
old_version_info = version.__version_info__
|
||||
old_version = version.__version__
|
||||
@@ -44,7 +44,7 @@ def devVersion():
|
||||
version.__version__ = old_version
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
@pytest.fixture
|
||||
def stableVersion():
|
||||
old_version_info = version.__version_info__
|
||||
old_version = version.__version__
|
||||
|
||||
@@ -17,31 +17,36 @@
|
||||
|
||||
import os
|
||||
import shlex
|
||||
import pytest
|
||||
|
||||
from unittest.mock import patch
|
||||
from gns3.vnc_console import vncConsole
|
||||
|
||||
|
||||
def test_vnc_console_on_linux_and_mac(vpcs_device):
|
||||
with patch('subprocess.Popen') as popen, \
|
||||
|
||||
with patch('subprocess.Popen') as p, \
|
||||
patch('sys.platform', new="linux"):
|
||||
vpcs_device.settings()["console_host"] = "localhost"
|
||||
vncConsole(vpcs_device, 6000, 'command %h %p %P')
|
||||
popen.assert_called_once_with(shlex.split('command localhost 6000 100'), env=os.environ)
|
||||
vncConsole(vpcs_device, 6000, 'command %h %p %D')
|
||||
p.assert_called_with(shlex.split('command localhost 6000 100'), env=os.environ)
|
||||
vncConsole(vpcs_device, 6000, 'command {host} {port} {display}')
|
||||
p.assert_called_with(shlex.split('command localhost 6000 100'), env=os.environ)
|
||||
|
||||
|
||||
def test_vnc_console_on_windows(vpcs_device):
|
||||
with patch('subprocess.Popen') as popen, \
|
||||
|
||||
with patch('subprocess.Popen') as p, \
|
||||
patch('sys.platform', new="win"):
|
||||
vpcs_device.settings()["console_host"] = "localhost"
|
||||
vncConsole(vpcs_device, 6000, 'command %h %p %P')
|
||||
popen.assert_called_once_with('command localhost 6000 100')
|
||||
vncConsole(vpcs_device, 6000, 'command %h %p %D')
|
||||
p.assert_called_with('command localhost 6000 100', env=os.environ)
|
||||
vncConsole(vpcs_device, 6000, 'command {host} {port} {display}')
|
||||
p.assert_called_with('command localhost 6000 100', env=os.environ)
|
||||
|
||||
|
||||
# def test_vnc_console_on_linux_with_popen_issues():
|
||||
# with patch('subprocess.Popen', side_effect=OSError("Dummy")), \
|
||||
# def test_vnc_console_on_linux_with_popen_issues(vpcs_device):
|
||||
# with patch('subprocess.Popen', side_effect=subprocess.SubprocessError()), \
|
||||
# patch('sys.platform', new="linux"):
|
||||
# vpcs_device.settings()["console_host"] = "localhost"
|
||||
#
|
||||
# with pytest.raises(OSError):
|
||||
# vncConsole('localhost', 6000, 'command %h %p %P')
|
||||
# with pytest.raises(subprocess.SubprocessError):
|
||||
# vncConsole(vpcs_device, 6000, 'command %h %p %P')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-rrequirements.txt
|
||||
|
||||
PyQt5==5.15.7 # pyup: ignore
|
||||
pywin32==305 # pyup: ignore
|
||||
PyQt5==5.15.10 # pyup: ignore
|
||||
pywin32==306 # pyup: ignore
|
||||
|
||||
Reference in New Issue
Block a user