From 53ece94a0884926e4d3c9b39b5fa8ee3c2642e33 Mon Sep 17 00:00:00 2001 From: grossmj Date: Thu, 23 May 2024 12:19:15 +0700 Subject: [PATCH 1/7] Development on 2.2.48.dev1 --- gns3/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3/version.py b/gns3/version.py index 59f956837..dd8531ab3 100644 --- a/gns3/version.py +++ b/gns3/version.py @@ -23,8 +23,8 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.2.47" -__version_info__ = (2, 2, 47, 0) +__version__ = "2.2.48.dev1" +__version_info__ = (2, 2, 48, 99) if "dev" in __version__: try: From b67a8c87a7882c9ed2fdcde9fa2d3b4c3df60a82 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 10 Jun 2024 17:20:52 +0200 Subject: [PATCH 2/7] Switch to PyQt5 5.15.10 for macOS build --- mac-requirements.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mac-requirements.txt b/mac-requirements.txt index fa6d90645..def2481a2 100644 --- a/mac-requirements.txt +++ b/mac-requirements.txt @@ -1,5 +1,3 @@ -rrequirements.txt -PyQt5-Qt5==5.15.2 -PyQt5-sip==12.12.2 -PyQt5==5.15.9 +PyQt5==5.15.10 From 80b654ba5345e111e972c85abb116a2baf7f70ad Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 3 Jul 2024 18:52:49 +0200 Subject: [PATCH 3/7] Upgrade sentry-sdk and psutil packages --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 21e540235..ef6131e48 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ jsonschema>=4.22.0,<4.23 -sentry-sdk==2.1.1,<2.2 -psutil==5.9.8 +sentry-sdk==2.7.1,<2.8 +psutil==6.0.0 distro>=1.9.0 truststore>=0.9.1; python_version >= '3.10' importlib-resources>=1.3; python_version < '3.9' From 60addccd950461eef15da59d28a1ec08bee17a32 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 6 Jul 2024 17:08:16 +0200 Subject: [PATCH 4/7] Option to keep the compute IDs unchanged when exporting a project --- gns3/dialogs/project_export_wizard.py | 12 ++--- gns3/ui/export_project_wizard.ui | 69 +++++++++++++++------------ gns3/ui/export_project_wizard_ui.py | 41 +++++++++------- gns3/utils/export_project_worker.py | 15 +++--- 4 files changed, 75 insertions(+), 62 deletions(-) diff --git a/gns3/dialogs/project_export_wizard.py b/gns3/dialogs/project_export_wizard.py index 3446247f5..dc810128f 100644 --- a/gns3/dialogs/project_export_wizard.py +++ b/gns3/dialogs/project_export_wizard.py @@ -126,20 +126,18 @@ def done(self, result): """ if result: + include_images = include_snapshots = reset_mac_addresses = keep_compute_ids = "no" if self.uiIncludeImagesCheckBox.isChecked(): include_images = "yes" - else: - include_images = "no" if self.uiIncludeSnapshotsCheckBox.isChecked(): include_snapshots = "yes" - else: - include_snapshots = "no" if self.uiResetMacAddressesCheckBox.isChecked(): reset_mac_addresses = "yes" - else: - reset_mac_addresses = "no" + if self.uiKeepComputeIdsCheckBox.isChecked(): + keep_compute_ids = "yes" + compression = self.uiCompressionComboBox.currentData() - export_worker = ExportProjectWorker(self._project, self._path, include_images, include_snapshots, reset_mac_addresses, compression) + export_worker = ExportProjectWorker(self._project, self._path, include_images, include_snapshots, reset_mac_addresses, keep_compute_ids, compression) progress_dialog = ProgressDialog(export_worker, "Exporting project", "Exporting portable project files...", "Cancel", parent=self, create_thread=False) progress_dialog.show() progress_dialog.exec_() diff --git a/gns3/ui/export_project_wizard.ui b/gns3/ui/export_project_wizard.ui index 95ff6bba7..0046b2de4 100644 --- a/gns3/ui/export_project_wizard.ui +++ b/gns3/ui/export_project_wizard.ui @@ -9,8 +9,8 @@ 0 0 - 900 - 600 + 602 + 367 @@ -27,19 +27,6 @@ Please select the location, whether to include base images or not and the compression type. - - - - - 0 - 0 - - - - Path: - - - @@ -54,31 +41,34 @@ - - + + - Compression: + &Reset MAC addresses - - - - - + + + + + 0 + 0 + + - &Include base images + Path: - - + + - &Include snapshots + Compression: - + Qt::Vertical @@ -91,10 +81,27 @@ - - + + + + + - &Reset MAC addresses + &Include base images + + + + + + + &Include snapshots + + + + + + + &Keep the original compute IDs diff --git a/gns3/ui/export_project_wizard_ui.py b/gns3/ui/export_project_wizard_ui.py index 2311bc915..1f5c6dbc4 100644 --- a/gns3/ui/export_project_wizard_ui.py +++ b/gns3/ui/export_project_wizard_ui.py @@ -2,9 +2,10 @@ # Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/export_project_wizard.ui' # -# Created by: PyQt5 UI code generator 5.13.2 +# 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 @@ -14,20 +15,12 @@ class Ui_ExportProjectWizard(object): def setupUi(self, ExportProjectWizard): ExportProjectWizard.setObjectName("ExportProjectWizard") ExportProjectWizard.setWindowModality(QtCore.Qt.ApplicationModal) - ExportProjectWizard.resize(900, 600) + ExportProjectWizard.resize(602, 367) ExportProjectWizard.setOptions(QtWidgets.QWizard.HaveHelpButton) self.uiExportOptionsWizardPage = QtWidgets.QWizardPage() self.uiExportOptionsWizardPage.setObjectName("uiExportOptionsWizardPage") self.gridLayout = QtWidgets.QGridLayout(self.uiExportOptionsWizardPage) self.gridLayout.setObjectName("gridLayout") - self.uiPathLabel = QtWidgets.QLabel(self.uiExportOptionsWizardPage) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.uiPathLabel.sizePolicy().hasHeightForWidth()) - self.uiPathLabel.setSizePolicy(sizePolicy) - self.uiPathLabel.setObjectName("uiPathLabel") - self.gridLayout.addWidget(self.uiPathLabel, 0, 0, 1, 1) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.uiPathLineEdit = QtWidgets.QLineEdit(self.uiExportOptionsWizardPage) @@ -37,9 +30,22 @@ def setupUi(self, ExportProjectWizard): self.uiPathBrowserToolButton.setObjectName("uiPathBrowserToolButton") self.horizontalLayout_3.addWidget(self.uiPathBrowserToolButton) self.gridLayout.addLayout(self.horizontalLayout_3, 0, 1, 1, 2) + self.uiResetMacAddressesCheckBox = QtWidgets.QCheckBox(self.uiExportOptionsWizardPage) + self.uiResetMacAddressesCheckBox.setObjectName("uiResetMacAddressesCheckBox") + self.gridLayout.addWidget(self.uiResetMacAddressesCheckBox, 5, 0, 1, 2) + self.uiPathLabel = QtWidgets.QLabel(self.uiExportOptionsWizardPage) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiPathLabel.sizePolicy().hasHeightForWidth()) + self.uiPathLabel.setSizePolicy(sizePolicy) + self.uiPathLabel.setObjectName("uiPathLabel") + self.gridLayout.addWidget(self.uiPathLabel, 0, 0, 1, 1) self.uiCompressionLabel = QtWidgets.QLabel(self.uiExportOptionsWizardPage) self.uiCompressionLabel.setObjectName("uiCompressionLabel") self.gridLayout.addWidget(self.uiCompressionLabel, 1, 0, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 247, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 7, 2, 1, 1) self.uiCompressionComboBox = QtWidgets.QComboBox(self.uiExportOptionsWizardPage) self.uiCompressionComboBox.setObjectName("uiCompressionComboBox") self.gridLayout.addWidget(self.uiCompressionComboBox, 1, 1, 1, 2) @@ -49,11 +55,9 @@ def setupUi(self, ExportProjectWizard): self.uiIncludeSnapshotsCheckBox = QtWidgets.QCheckBox(self.uiExportOptionsWizardPage) self.uiIncludeSnapshotsCheckBox.setObjectName("uiIncludeSnapshotsCheckBox") self.gridLayout.addWidget(self.uiIncludeSnapshotsCheckBox, 4, 0, 1, 2) - spacerItem = QtWidgets.QSpacerItem(20, 247, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout.addItem(spacerItem, 6, 2, 1, 1) - self.uiResetMacAddressesCheckBox = QtWidgets.QCheckBox(self.uiExportOptionsWizardPage) - self.uiResetMacAddressesCheckBox.setObjectName("uiResetMacAddressesCheckBox") - self.gridLayout.addWidget(self.uiResetMacAddressesCheckBox, 5, 0, 1, 2) + self.uiKeepComputeIdsCheckBox = QtWidgets.QCheckBox(self.uiExportOptionsWizardPage) + self.uiKeepComputeIdsCheckBox.setObjectName("uiKeepComputeIdsCheckBox") + self.gridLayout.addWidget(self.uiKeepComputeIdsCheckBox, 6, 0, 1, 3) ExportProjectWizard.addPage(self.uiExportOptionsWizardPage) self.uiProjectReadmeWizardPage = QtWidgets.QWizardPage() self.uiProjectReadmeWizardPage.setObjectName("uiProjectReadmeWizardPage") @@ -72,12 +76,13 @@ def retranslateUi(self, ExportProjectWizard): ExportProjectWizard.setWindowTitle(_translate("ExportProjectWizard", "Export project")) self.uiExportOptionsWizardPage.setTitle(_translate("ExportProjectWizard", "Export project")) self.uiExportOptionsWizardPage.setSubTitle(_translate("ExportProjectWizard", "Please select the location, whether to include base images or not and the compression type.")) - self.uiPathLabel.setText(_translate("ExportProjectWizard", "Path:")) self.uiPathBrowserToolButton.setText(_translate("ExportProjectWizard", "Browse...")) + self.uiResetMacAddressesCheckBox.setText(_translate("ExportProjectWizard", "&Reset MAC addresses")) + self.uiPathLabel.setText(_translate("ExportProjectWizard", "Path:")) self.uiCompressionLabel.setText(_translate("ExportProjectWizard", "Compression:")) self.uiIncludeImagesCheckBox.setText(_translate("ExportProjectWizard", "&Include base images")) self.uiIncludeSnapshotsCheckBox.setText(_translate("ExportProjectWizard", "&Include snapshots")) - self.uiResetMacAddressesCheckBox.setText(_translate("ExportProjectWizard", "&Reset MAC addresses")) + self.uiKeepComputeIdsCheckBox.setText(_translate("ExportProjectWizard", "&Keep the original compute IDs")) self.uiProjectReadmeWizardPage.setTitle(_translate("ExportProjectWizard", "Readme file")) self.uiProjectReadmeWizardPage.setSubTitle(_translate("ExportProjectWizard", "Write a summary of the project.")) self.uiReadmeTextEdit.setHtml(_translate("ExportProjectWizard", "\n" diff --git a/gns3/utils/export_project_worker.py b/gns3/utils/export_project_worker.py index 70d5003b0..05552bbd3 100644 --- a/gns3/utils/export_project_worker.py +++ b/gns3/utils/export_project_worker.py @@ -28,21 +28,24 @@ class ExportProjectWorker(QtCore.QObject): finished = QtCore.pyqtSignal() updated = QtCore.pyqtSignal(int) - def __init__(self, project, path, include_images, include_snapshots, reset_mac_addresses, compression): + def __init__(self, project, path, include_images, include_snapshots, reset_mac_addresses, keep_compute_ids, compression): super().__init__() self._project = project + self._path = path self._include_images = include_images self._include_snapshots = include_snapshots self._reset_mac_addresses = reset_mac_addresses - self._path = path + self._keep_compute_ids = keep_compute_ids self._compression = compression def run(self): if self._project: - self._project.get("/export?include_images={}&include_snapshots={}&reset_mac_addresses={}&compression={}".format(self._include_images, self._include_snapshots, self._reset_mac_addresses, self._compression), - self._exportReceived, - downloadProgressCallback=self._downloadFileProgress, - timeout=None) + self._project.get( + "/export?include_images={}&include_snapshots={}&reset_mac_addresses={}&keep_compute_ids={}&compression={}".format(self._include_images, self._include_snapshots, self._reset_mac_addresses, self._keep_compute_ids, self._compression), + self._exportReceived, + downloadProgressCallback=self._downloadFileProgress, + timeout=None + ) def _exportReceived(self, content, error=False, server=None, context={}, **kwargs): if error: From d7bb1956102e4d55aaab5fb462af7fe5003204a7 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sun, 7 Jul 2024 17:47:24 +0200 Subject: [PATCH 5/7] Update appliance_v8.json. Ref https://github.com/GNS3/gns3-registry/pull/897 --- gns3/schemas/appliance_v8.json | 330 ++++++++++++++++----------------- 1 file changed, 165 insertions(+), 165 deletions(-) diff --git a/gns3/schemas/appliance_v8.json b/gns3/schemas/appliance_v8.json index 043ef26ec..4b0e23ed4 100644 --- a/gns3/schemas/appliance_v8.json +++ b/gns3/schemas/appliance_v8.json @@ -720,174 +720,174 @@ "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" + }, + "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." + } }, - "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)" + "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": [ + "name" + ] + } } }, "required": [ From d340b1f50a13f9fed7d604c43f4f8451205bcdb4 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 8 Jul 2024 14:19:42 +0200 Subject: [PATCH 6/7] Use "experimental features" to allow bypassing hostname validation. Ref #3524 --- gns3/graphics_view.py | 2 +- gns3/modules/dynamips/pages/ios_router_configuration_page.py | 3 ++- gns3/modules/iou/pages/iou_device_configuration_page.py | 3 ++- gns3/settings.py | 1 - gns3/ui/general_preferences_page.ui | 2 +- gns3/ui/general_preferences_page_ui.py | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gns3/graphics_view.py b/gns3/graphics_view.py index 668ea8451..6481a6c6e 100644 --- a/gns3/graphics_view.py +++ b/gns3/graphics_view.py @@ -1032,7 +1032,7 @@ def changeHostnameActionSlot(self): if not new_hostname.strip(): QtWidgets.QMessageBox.critical(self, "Change hostname", "Hostname cannot be blank") continue - if hasattr(item.node(), "validateHostname"): + if hasattr(item.node(), "validateHostname") and not LocalConfig.instance().experimental(): if not item.node().validateHostname(new_hostname): QtWidgets.QMessageBox.critical(self, "Change hostname", "Invalid name detected for this node: {}".format(new_hostname)) continue diff --git a/gns3/modules/dynamips/pages/ios_router_configuration_page.py b/gns3/modules/dynamips/pages/ios_router_configuration_page.py index 112d15bd5..12fccab6f 100644 --- a/gns3/modules/dynamips/pages/ios_router_configuration_page.py +++ b/gns3/modules/dynamips/pages/ios_router_configuration_page.py @@ -24,6 +24,7 @@ from gns3.qt import QtCore, QtGui, QtWidgets from gns3.local_server import LocalServer +from gns3.local_config import LocalConfig from gns3.dialogs.node_properties_dialog import ConfigurationError from gns3.dialogs.symbol_selection_dialog import SymbolSelectionDialog from gns3.controller import Controller @@ -488,7 +489,7 @@ def saveSettings(self, settings, node=None, group=False): name = self.uiNameLineEdit.text() if not name: QtWidgets.QMessageBox.critical(self, "Name", "IOS router name cannot be empty!") - elif node and not node.validateHostname(name): + elif node and not node.validateHostname(name) and not LocalConfig.instance().experimental(): QtWidgets.QMessageBox.critical(self, "Name", "Invalid name detected for IOS router: {}".format(name)) else: settings["name"] = name diff --git a/gns3/modules/iou/pages/iou_device_configuration_page.py b/gns3/modules/iou/pages/iou_device_configuration_page.py index 4a712056d..eee9a94ca 100644 --- a/gns3/modules/iou/pages/iou_device_configuration_page.py +++ b/gns3/modules/iou/pages/iou_device_configuration_page.py @@ -23,6 +23,7 @@ from gns3.qt import QtWidgets from gns3.local_server import LocalServer +from gns3.local_config import LocalConfig from gns3.dialogs.node_properties_dialog import ConfigurationError from gns3.dialogs.symbol_selection_dialog import SymbolSelectionDialog from gns3.node import Node @@ -245,7 +246,7 @@ def saveSettings(self, settings, node=None, group=False): name = self.uiNameLineEdit.text() if not name: QtWidgets.QMessageBox.critical(self, "Name", "IOU device name cannot be empty!") - elif node and not node.validateHostname(name): + elif node and not node.validateHostname(name) and not LocalConfig.instance().experimental(): QtWidgets.QMessageBox.critical(self, "Name", "Invalid name detected for IOU device: {}".format(name)) else: settings["name"] = name diff --git a/gns3/settings.py b/gns3/settings.py index 47fecb3d2..2ec438dfa 100644 --- a/gns3/settings.py +++ b/gns3/settings.py @@ -287,7 +287,6 @@ "check_for_update": True, "overlay_notifications": True, "experimental_features": False, - "stats_visitor_id": str(uuid.uuid4()), # An anonymous id for stats "last_check_for_update": 0, "telnet_console_command": DEFAULT_TELNET_CONSOLE_COMMAND, "vnc_console_command": DEFAULT_VNC_CONSOLE_COMMAND, diff --git a/gns3/ui/general_preferences_page.ui b/gns3/ui/general_preferences_page.ui index f5ec5ab69..b7226e3d8 100755 --- a/gns3/ui/general_preferences_page.ui +++ b/gns3/ui/general_preferences_page.ui @@ -1012,7 +1012,7 @@ - Enable experimental features (dangerous, restart required) + Enable experimental features diff --git a/gns3/ui/general_preferences_page_ui.py b/gns3/ui/general_preferences_page_ui.py index fc3bd1a0b..c6f2fb2d8 100644 --- a/gns3/ui/general_preferences_page_ui.py +++ b/gns3/ui/general_preferences_page_ui.py @@ -598,7 +598,7 @@ def retranslateUi(self, GeneralPreferencesPageWidget): self.uiCheckForUpdateCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Automatically check for update")) self.uiCrashReportCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Send anonymous crash reports")) self.uiOverlayNotificationsCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Display error, warning and info in an overlay popup")) - self.uiExperimentalFeaturesCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Enable experimental features (dangerous, restart required)")) + self.uiExperimentalFeaturesCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Enable experimental features")) self.uiHdpiCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Enable HDPI mode (this may crash on Linux, restart required)")) self.uiMultiProfilesCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Request for profile settings at application startup")) self.uiDirectFileUpload.setToolTip(_translate("GeneralPreferencesPageWidget", "Experimental, requires computes visibility from GUI network")) From 1e80354e4e3a77f5121876200a0735fb1f360faa Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 8 Jul 2024 18:44:09 +0200 Subject: [PATCH 7/7] Release v2.2.48 --- CHANGELOG | 8 ++++++++ gns3/crash_report.py | 2 +- gns3/version.py | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4f8dccbf1..002098669 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,13 @@ # Change Log +## 2.2.48 08/07/2024 + +* Use "experimental features" to allow bypassing hostname validation. Ref #3524 +* Update appliance_v8.json. Ref https://github.com/GNS3/gns3-registry/pull/897 +* Option to keep the compute IDs unchanged when exporting a project +* Upgrade sentry-sdk and psutil packages +* Switch to PyQt5 5.15.10 for macOS build + ## 2.2.47 15/05/2024 * Remove maximum size for capture dialog. Ref #3576 diff --git a/gns3/crash_report.py b/gns3/crash_report.py index 2cd34b7ea..458792681 100644 --- a/gns3/crash_report.py +++ b/gns3/crash_report.py @@ -50,7 +50,7 @@ class CrashReport: Report crash to a third party service """ - DSN = "https://235ecbc961abe34327a4a397d8ce427a@o19455.ingest.us.sentry.io/38506" + DSN = "https://a9154d40d27d0cecfdbf5943b2ea68d5@o19455.ingest.us.sentry.io/38506" _instance = None def __init__(self): diff --git a/gns3/version.py b/gns3/version.py index dd8531ab3..bd0baa5c3 100644 --- a/gns3/version.py +++ b/gns3/version.py @@ -23,8 +23,8 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "2.2.48.dev1" -__version_info__ = (2, 2, 48, 99) +__version__ = "2.2.48" +__version_info__ = (2, 2, 48, 0) if "dev" in __version__: try: