From 999f41b03e86b60a4cef860c10c16646daca0676 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 20 Jul 2024 17:22:24 +0200 Subject: [PATCH 1/3] Convert topologies < 3.0 to have valid node hostnames --- gns3server/controller/project.py | 2 +- gns3server/controller/topology.py | 32 +++++++- gns3server/utils/hostname.py | 53 +++++++++++++ tests/utils/test_hostname.py | 121 ++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 tests/utils/test_hostname.py diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index 5fec4cb8..80b9dd56 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -495,7 +495,7 @@ class Project: if base_name is None: return None - base_name = re.sub(r"[ ]", "", base_name) + base_name = re.sub(r"[ ]", "", base_name) # remove spaces in node name if base_name in self._allocated_node_names: base_name = re.sub(r"[0-9]+$", "{0}", base_name) diff --git a/gns3server/controller/topology.py b/gns3server/controller/topology.py index f6d3b039..318edf62 100644 --- a/gns3server/controller/topology.py +++ b/gns3server/controller/topology.py @@ -35,6 +35,7 @@ from .drawing import Drawing from .node import Node from .link import Link +from gns3server.utils.hostname import is_ios_hostname_valid, is_rfc1123_hostname_valid, to_rfc1123_hostname, to_ios_hostname from gns3server.schemas.controller.topology import Topology from gns3server.schemas.compute.dynamips_nodes import DynamipsCreate @@ -43,7 +44,7 @@ import logging log = logging.getLogger(__name__) -GNS3_FILE_FORMAT_REVISION = 9 +GNS3_FILE_FORMAT_REVISION = 10 class DynamipsNodeValidation(DynamipsCreate): @@ -186,6 +187,10 @@ def load_topology(path): if variables: topo["variables"] = [var for var in variables if var.get("name")] + # Version before GNS3 3.0 + if topo["revision"] < 10: + topo = _convert_2_2_0(topo, path) + try: _check_topology_schema(topo, path) except ControllerError as e: @@ -201,6 +206,31 @@ def load_topology(path): return topo +def _convert_2_2_0(topo, topo_path): + """ + Convert topologies from GNS3 2.2.x to 3.0 + + Changes: + * Removed acpi_shutdown option from Qemu, VMware and VirtualBox + + """ + + topo["revision"] = 10 + + for node in topo.get("topology", {}).get("nodes", []): + # make sure console_type is not None but "none" string + if "properties" in node: + if node["node_type"] in ("qemu", "docker") and not is_rfc1123_hostname_valid(node["name"]): + new_name = to_rfc1123_hostname(node["name"]) + log.info(f"Convert node name {node['name']} to {new_name} (RFC1123)") + node["name"] = new_name + if node["node_type"] in ("dynamips", "iou") and not is_ios_hostname_valid(node["name"] ): + new_name = to_ios_hostname(node["name"]) + log.info(f"Convert node name {node['name']} to {new_name} (IOS)") + node["name"] = new_name + return topo + + def _convert_2_1_0(topo, topo_path): """ Convert topologies from GNS3 2.1.x to 2.2 diff --git a/gns3server/utils/hostname.py b/gns3server/utils/hostname.py index 2e89b685..828acf5e 100644 --- a/gns3server/utils/hostname.py +++ b/gns3server/utils/hostname.py @@ -32,6 +32,28 @@ def is_ios_hostname_valid(hostname: str) -> bool: return False +def to_ios_hostname(name): + """ + Convert name to an IOS hostname + """ + + # Replace invalid characters with hyphens + name = re.sub(r'[^a-zA-Z0-9-]', '-', name) + + # Ensure the hostname starts with a letter + if not re.search(r'^[a-zA-Z]', name): + name = 'a' + name + + # Ensure the hostname ends with a letter or digit + if not re.search(r'[a-zA-Z0-9]$', name): + name = name.rstrip('-') + '0' + + # Truncate the hostname to 63 characters + name = name[:63] + + return name + + def is_rfc1123_hostname_valid(hostname: str) -> bool: """ Check if a hostname is valid according to RFC 1123 @@ -57,3 +79,34 @@ def is_rfc1123_hostname_valid(hostname: str) -> bool: allowed = re.compile(r"(?!-)[a-zA-Z0-9-]{1,63}(? str: + """ + Convert name to RFC 1123 hostname + """ + + # Replace invalid characters with hyphens + name = re.sub(r'[^a-zA-Z0-9-.]', '-', name) + + # Remove trailing dot if it exists + name = name.rstrip('.') + + # Ensure each label is not longer than 63 characters + labels = name.split('.') + labels = [label[:63] for label in labels] + + # Remove leading and trailing hyphens from each label if they exist + labels = [label.strip('-') for label in labels] + + # Check if the TLD is all-numeric and if so, replace it with "invalid" + if re.match(r"[0-9]+$", labels[-1]): + labels[-1] = 'invalid' + + # Join the labels back together + name = '.'.join(labels) + + # Ensure the total length is not longer than 253 characters + name = name[:253] + + return name diff --git a/tests/utils/test_hostname.py b/tests/utils/test_hostname.py new file mode 100644 index 00000000..66904e06 --- /dev/null +++ b/tests/utils/test_hostname.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2024 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 +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from gns3server.utils import hostname + + +def test_ios_hostname_valid_with_valid_hostnames(): + assert hostname.is_ios_hostname_valid("router1") + assert hostname.is_ios_hostname_valid("switch-2") + assert hostname.is_ios_hostname_valid("a1-b2-c3") + + +def test_ios_hostname_valid_with_invalid_hostnames(): + assert not hostname.is_ios_hostname_valid("-router") + assert not hostname.is_ios_hostname_valid("router-") + assert not hostname.is_ios_hostname_valid("123router") + assert not hostname.is_ios_hostname_valid("router@123") + assert not hostname.is_ios_hostname_valid("router.router") + + +def test_ios_hostname_valid_with_long_hostnames(): + assert hostname.is_ios_hostname_valid("a" * 63) + assert not hostname.is_ios_hostname_valid("a" * 64) + + +def test_ios_hostname_conversion_with_valid_characters(): + assert hostname.to_ios_hostname("validHostname123") == "validHostname123" + + +def test_ios_hostname_conversion_starts_with_digit(): + assert hostname.to_ios_hostname("1InvalidStart") == "a1InvalidStart" + + +def test_ios_hostname_conversion_starts_with_special_character(): + assert hostname.to_ios_hostname("@InvalidStart") == "a-InvalidStart" + + +def test_ios_hostname_conversion_ends_with_special_character(): + assert hostname.to_ios_hostname("InvalidEnd-") == "InvalidEnd0" + + +def test_ios_hostname_conversion_contains_special_characters(): + assert hostname.to_ios_hostname("Invalid@Hostname!") == "Invalid-Hostname0" + + +def test_ios_hostname_conversion_exceeds_max_length(): + long_name = "a" * 64 + assert hostname.to_ios_hostname(long_name) == "a" * 63 + + +def test_ios_hostname_conversion_just_right_length(): + exact_length_name = "a" * 63 + assert hostname.to_ios_hostname(exact_length_name) == "a" * 63 + + +def test_rfc1123_hostname_validity_with_valid_hostnames(): + assert hostname.is_rfc1123_hostname_valid("example.com") + assert hostname.is_rfc1123_hostname_valid("subdomain.example.com") + assert hostname.is_rfc1123_hostname_valid("example-hyphen.com") + assert hostname.is_rfc1123_hostname_valid("example.com.") + assert hostname.is_rfc1123_hostname_valid("123.com") + + +def test_rfc1123_hostname_validity_with_invalid_hostnames(): + assert not hostname.is_rfc1123_hostname_valid("-example.com") + assert not hostname.is_rfc1123_hostname_valid("example-.com") + assert not hostname.is_rfc1123_hostname_valid("example..com") + assert not hostname.is_rfc1123_hostname_valid("example_com") + assert not hostname.is_rfc1123_hostname_valid("example.123") + + +def test_rfc1123_hostname_validity_with_long_hostnames(): + long_hostname = "a" * 63 + "." + "b" * 63 + "." + "c" * 63 + "." + "d" * 61 # 253 characters + too_long_hostname = long_hostname + "e" + assert hostname.is_rfc1123_hostname_valid(long_hostname) + assert not hostname.is_rfc1123_hostname_valid(too_long_hostname) + + +def test_rfc1123_conversion_hostname_with_valid_characters(): + assert hostname.to_rfc1123_hostname("valid-hostname.example.com") == "valid-hostname.example.com" + + +def test_rfc1123_conversion_hostname_with_invalid_characters_replaced(): + assert hostname.to_rfc1123_hostname("invalid_hostname!@#$.example") == "invalid-hostname.example" + + +def test_rfc1123_conversion_hostname_with_trailing_dot_removed(): + assert hostname.to_rfc1123_hostname("hostname.example.com.") == "hostname.example.com" + + +def test_rfc1123_conversion_hostname_with_labels_exceeding_63_characters(): + long_label = "a" * 64 + ".example.com" + expected_label = "a" * 63 + ".example.com" + assert hostname.to_rfc1123_hostname(long_label) == expected_label + + +def test_rfc1123_conversion_hostname_with_total_length_exceeding_253_characters(): + long_hostname = "a" * 50 + "." + "b" * 50 + "." + "c" * 50 + "." + "d" * 50 + "." + "e" * 50 + assert len(hostname.to_rfc1123_hostname(long_hostname)) <= 253 + + +def test_rfc1123_conversion_hostname_with_all_numeric_tld_replaced(): + assert hostname.to_rfc1123_hostname("hostname.123") == "hostname.invalid" + + +def rfc1123_hostname_with_multiple_consecutive_invalid_characters(): + assert hostname.to_rfc1123_hostname("hostname!!!.example..com") == "hostname---.example.com" From eefb3d87b258c4f744e578fd7391fd4f667b7ee0 Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 20 Jul 2024 17:47:25 +0200 Subject: [PATCH 2/3] Fix tests and add conversion test --- .../after/1_5_docker_remote.gns3 | 4 +- .../before/1_5_docker_remote.gns3 | 4 +- .../{1_5_vmware.gns3 => 2_0_vmware.gns3} | 0 .../{1_5_vmware.gns3 => 2_0_vmware.gns3} | 0 .../3_0_hostnames/after/3_0_hostnames.gns3 | 222 ++++++++++++++++++ .../3_0_hostnames/before/3_0_hostnames.gns3 | 222 ++++++++++++++++++ 6 files changed, 448 insertions(+), 4 deletions(-) rename tests/topologies/2_0_vmware/after/{1_5_vmware.gns3 => 2_0_vmware.gns3} (100%) rename tests/topologies/2_0_vmware/before/{1_5_vmware.gns3 => 2_0_vmware.gns3} (100%) create mode 100644 tests/topologies/3_0_hostnames/after/3_0_hostnames.gns3 create mode 100644 tests/topologies/3_0_hostnames/before/3_0_hostnames.gns3 diff --git a/tests/topologies/1_5_docker_remote/after/1_5_docker_remote.gns3 b/tests/topologies/1_5_docker_remote/after/1_5_docker_remote.gns3 index 5259d910..41e952ee 100644 --- a/tests/topologies/1_5_docker_remote/after/1_5_docker_remote.gns3 +++ b/tests/topologies/1_5_docker_remote/after/1_5_docker_remote.gns3 @@ -23,11 +23,11 @@ "label": { "rotation": 0, "style": "font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #000000;fill-opacity: 1.0;", - "text": "remote_busybox-1", + "text": "remote-busybox-1", "x": -20, "y": -25 }, - "name": "remote_busybox-1", + "name": "remote-busybox-1", "node_id": "d397ef5a-84f1-4b6b-9d44-671937ec7781", "node_type": "docker", "port_name_format": "Ethernet{0}", diff --git a/tests/topologies/1_5_docker_remote/before/1_5_docker_remote.gns3 b/tests/topologies/1_5_docker_remote/before/1_5_docker_remote.gns3 index 57e835b8..fc832bcb 100644 --- a/tests/topologies/1_5_docker_remote/before/1_5_docker_remote.gns3 +++ b/tests/topologies/1_5_docker_remote/before/1_5_docker_remote.gns3 @@ -11,7 +11,7 @@ "label": { "color": "#ff000000", "font": "TypeWriter,10,-1,5,75,0,0,0,0,0", - "text": "remote_busybox-1", + "text": "remote-busybox-1", "x": -20.4453125, "y": -25.0 }, @@ -32,7 +32,7 @@ "console_resolution": "1024x768", "console_type": "telnet", "image": "busybox:latest", - "name": "remote_busybox-1" + "name": "remote-busybox-1" }, "server_id": 2, "type": "DockerVM", diff --git a/tests/topologies/2_0_vmware/after/1_5_vmware.gns3 b/tests/topologies/2_0_vmware/after/2_0_vmware.gns3 similarity index 100% rename from tests/topologies/2_0_vmware/after/1_5_vmware.gns3 rename to tests/topologies/2_0_vmware/after/2_0_vmware.gns3 diff --git a/tests/topologies/2_0_vmware/before/1_5_vmware.gns3 b/tests/topologies/2_0_vmware/before/2_0_vmware.gns3 similarity index 100% rename from tests/topologies/2_0_vmware/before/1_5_vmware.gns3 rename to tests/topologies/2_0_vmware/before/2_0_vmware.gns3 diff --git a/tests/topologies/3_0_hostnames/after/3_0_hostnames.gns3 b/tests/topologies/3_0_hostnames/after/3_0_hostnames.gns3 new file mode 100644 index 00000000..17fe4245 --- /dev/null +++ b/tests/topologies/3_0_hostnames/after/3_0_hostnames.gns3 @@ -0,0 +1,222 @@ +{ + "auto_close": true, + "auto_open": false, + "auto_start": false, + "drawing_grid_size": 25, + "grid_size": 75, + "name": "test-hostnames", + "project_id": "8b83e3ac-6b6a-4d6b-9938-bd630a6e458e", + "revision": 10, + "scene_height": 1000, + "scene_width": 2000, + "show_grid": false, + "show_interface_labels": false, + "show_layers": false, + "snap_to_grid": false, + "supplier": null, + "topology": { + "computes": [], + "drawings": [], + "links": [], + "nodes": [ + { + "compute_id": "local", + "console": 5000, + "console_auto_start": false, + "console_type": "telnet", + "custom_adapters": [], + "first_port_name": null, + "height": 45, + "label": { + "rotation": 0, + "style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;", + "text": "42Router_A-1", + "x": -20, + "y": -25 + }, + "locked": false, + "name": "a42Router-A-1", + "node_id": "adb89fbb-92ba-419b-96ca-1ad0f03ce3f6", + "node_type": "dynamips", + "port_name_format": "Ethernet{0}", + "port_segment_size": 0, + "properties": { + "auto_delete_disks": false, + "aux": null, + "clock_divisor": 8, + "disk0": 0, + "disk1": 0, + "dynamips_id": 1, + "exec_area": 64, + "idlemax": 500, + "idlepc": "0x60aa1da0", + "idlesleep": 30, + "image": "c3745-adventerprisek9-mz.124-25d.image", + "image_md5sum": "ddbaf74274822b50fa9670e10c75b08f", + "iomem": 5, + "mac_addr": "c401.fff5.0000", + "mmap": true, + "nvram": 256, + "platform": "c3745", + "ram": 256, + "slot0": "GT96100-FE", + "slot1": "NM-1FE-TX", + "slot2": "NM-4T", + "slot3": null, + "slot4": null, + "sparsemem": true, + "system_id": "FTX0945W0MY", + "usage": "", + "wic0": "WIC-1T", + "wic1": "WIC-1T", + "wic2": "WIC-1T" + }, + "symbol": ":/symbols/classic/router.svg", + "template_id": "24f09d1a-64e1-4dc4-ae49-e785c1dbc0c5", + "width": 66, + "x": -130, + "y": -64, + "z": 1 + }, + { + "compute_id": "local", + "console": 5001, + "console_auto_start": false, + "console_type": "telnet", + "custom_adapters": [ + { + "adapter_number": 0, + "adapter_type": "e1000" + }, + { + "adapter_number": 1, + "adapter_type": "e1000" + }, + { + "adapter_number": 2, + "adapter_type": "e1000" + }, + { + "adapter_number": 3, + "adapter_type": "e1000" + }, + { + "adapter_number": 4, + "adapter_type": "e1000" + }, + { + "adapter_number": 5, + "adapter_type": "e1000" + }, + { + "adapter_number": 6, + "adapter_type": "e1000" + }, + { + "adapter_number": 7, + "adapter_type": "e1000" + }, + { + "adapter_number": 8, + "adapter_type": "e1000" + }, + { + "adapter_number": 9, + "adapter_type": "e1000" + }, + { + "adapter_number": 10, + "adapter_type": "e1000" + }, + { + "adapter_number": 11, + "adapter_type": "e1000" + }, + { + "adapter_number": 12, + "adapter_type": "e1000" + }, + { + "adapter_number": 13, + "adapter_type": "e1000" + }, + { + "adapter_number": 14, + "adapter_type": "e1000" + }, + { + "adapter_number": 15, + "adapter_type": "e1000" + } + ], + "first_port_name": "", + "height": 48, + "label": { + "rotation": 0, + "style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;", + "text": "Switch_10.0.0.1", + "x": -36, + "y": -25 + }, + "locked": false, + "name": "Switch-10.0.0.invalid", + "node_id": "ccda4e49-770f-4237-956b-cc7281630468", + "node_type": "qemu", + "port_name_format": "Gi0/{0}", + "port_segment_size": 4, + "properties": { + "adapter_type": "e1000", + "adapters": 16, + "bios_image": "", + "bios_image_md5sum": null, + "boot_priority": "c", + "cdrom_image": "", + "cdrom_image_md5sum": null, + "cpu_throttling": 0, + "cpus": 1, + "create_config_disk": false, + "hda_disk_image": "vios_l2-adventerprisek9-m.03.2017.qcow2", + "hda_disk_image_md5sum": "8f14b50083a14688dec2fc791706bb3e", + "hda_disk_interface": "virtio", + "hdb_disk_image": "", + "hdb_disk_image_md5sum": null, + "hdb_disk_interface": "none", + "hdc_disk_image": "", + "hdc_disk_image_md5sum": null, + "hdc_disk_interface": "none", + "hdd_disk_image": "", + "hdd_disk_image_md5sum": null, + "hdd_disk_interface": "none", + "initrd": "", + "initrd_md5sum": null, + "kernel_command_line": "", + "kernel_image": "", + "kernel_image_md5sum": null, + "legacy_networking": false, + "linked_clone": true, + "mac_address": "0c:da:4e:49:00:00", + "on_close": "power_off", + "options": "", + "platform": "x86_64", + "process_priority": "normal", + "qemu_path": "/bin/qemu-system-x86_64", + "ram": 768, + "replicate_network_connection_state": true, + "tpm": false, + "uefi": false, + "usage": "There is no default password and enable password. There is no default configuration present. SUPER UPDATED!" + }, + "symbol": ":/symbols/classic/multilayer_switch.svg", + "template_id": "9db64790-65f4-4d38-a1ac-2f6ce45b70db", + "width": 51, + "x": -13, + "y": 54, + "z": 1 + } + ] + }, + "type": "topology", + "variables": null, + "version": "2.2.49", + "zoom": 100 +} \ No newline at end of file diff --git a/tests/topologies/3_0_hostnames/before/3_0_hostnames.gns3 b/tests/topologies/3_0_hostnames/before/3_0_hostnames.gns3 new file mode 100644 index 00000000..a11093db --- /dev/null +++ b/tests/topologies/3_0_hostnames/before/3_0_hostnames.gns3 @@ -0,0 +1,222 @@ +{ + "auto_close": true, + "auto_open": false, + "auto_start": false, + "drawing_grid_size": 25, + "grid_size": 75, + "name": "test-hostnames", + "project_id": "8b83e3ac-6b6a-4d6b-9938-bd630a6e458e", + "revision": 9, + "scene_height": 1000, + "scene_width": 2000, + "show_grid": false, + "show_interface_labels": false, + "show_layers": false, + "snap_to_grid": false, + "supplier": null, + "topology": { + "computes": [], + "drawings": [], + "links": [], + "nodes": [ + { + "compute_id": "local", + "console": 5000, + "console_auto_start": false, + "console_type": "telnet", + "custom_adapters": [], + "first_port_name": null, + "height": 45, + "label": { + "rotation": 0, + "style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;", + "text": "42Router_A-1", + "x": -20, + "y": -25 + }, + "locked": false, + "name": "42Router_A-1", + "node_id": "adb89fbb-92ba-419b-96ca-1ad0f03ce3f6", + "node_type": "dynamips", + "port_name_format": "Ethernet{0}", + "port_segment_size": 0, + "properties": { + "auto_delete_disks": false, + "aux": null, + "clock_divisor": 8, + "disk0": 0, + "disk1": 0, + "dynamips_id": 1, + "exec_area": 64, + "idlemax": 500, + "idlepc": "0x60aa1da0", + "idlesleep": 30, + "image": "c3745-adventerprisek9-mz.124-25d.image", + "image_md5sum": "ddbaf74274822b50fa9670e10c75b08f", + "iomem": 5, + "mac_addr": "c401.fff5.0000", + "mmap": true, + "nvram": 256, + "platform": "c3745", + "ram": 256, + "slot0": "GT96100-FE", + "slot1": "NM-1FE-TX", + "slot2": "NM-4T", + "slot3": null, + "slot4": null, + "sparsemem": true, + "system_id": "FTX0945W0MY", + "usage": "", + "wic0": "WIC-1T", + "wic1": "WIC-1T", + "wic2": "WIC-1T" + }, + "symbol": ":/symbols/classic/router.svg", + "template_id": "24f09d1a-64e1-4dc4-ae49-e785c1dbc0c5", + "width": 66, + "x": -130, + "y": -64, + "z": 1 + }, + { + "compute_id": "local", + "console": 5001, + "console_auto_start": false, + "console_type": "telnet", + "custom_adapters": [ + { + "adapter_number": 0, + "adapter_type": "e1000" + }, + { + "adapter_number": 1, + "adapter_type": "e1000" + }, + { + "adapter_number": 2, + "adapter_type": "e1000" + }, + { + "adapter_number": 3, + "adapter_type": "e1000" + }, + { + "adapter_number": 4, + "adapter_type": "e1000" + }, + { + "adapter_number": 5, + "adapter_type": "e1000" + }, + { + "adapter_number": 6, + "adapter_type": "e1000" + }, + { + "adapter_number": 7, + "adapter_type": "e1000" + }, + { + "adapter_number": 8, + "adapter_type": "e1000" + }, + { + "adapter_number": 9, + "adapter_type": "e1000" + }, + { + "adapter_number": 10, + "adapter_type": "e1000" + }, + { + "adapter_number": 11, + "adapter_type": "e1000" + }, + { + "adapter_number": 12, + "adapter_type": "e1000" + }, + { + "adapter_number": 13, + "adapter_type": "e1000" + }, + { + "adapter_number": 14, + "adapter_type": "e1000" + }, + { + "adapter_number": 15, + "adapter_type": "e1000" + } + ], + "first_port_name": "", + "height": 48, + "label": { + "rotation": 0, + "style": "font-family: TypeWriter;font-size: 10.0;font-weight: bold;fill: #000000;fill-opacity: 1.0;", + "text": "Switch_10.0.0.1", + "x": -36, + "y": -25 + }, + "locked": false, + "name": "Switch_10.0.0.1", + "node_id": "ccda4e49-770f-4237-956b-cc7281630468", + "node_type": "qemu", + "port_name_format": "Gi0/{0}", + "port_segment_size": 4, + "properties": { + "adapter_type": "e1000", + "adapters": 16, + "bios_image": "", + "bios_image_md5sum": null, + "boot_priority": "c", + "cdrom_image": "", + "cdrom_image_md5sum": null, + "cpu_throttling": 0, + "cpus": 1, + "create_config_disk": false, + "hda_disk_image": "vios_l2-adventerprisek9-m.03.2017.qcow2", + "hda_disk_image_md5sum": "8f14b50083a14688dec2fc791706bb3e", + "hda_disk_interface": "virtio", + "hdb_disk_image": "", + "hdb_disk_image_md5sum": null, + "hdb_disk_interface": "none", + "hdc_disk_image": "", + "hdc_disk_image_md5sum": null, + "hdc_disk_interface": "none", + "hdd_disk_image": "", + "hdd_disk_image_md5sum": null, + "hdd_disk_interface": "none", + "initrd": "", + "initrd_md5sum": null, + "kernel_command_line": "", + "kernel_image": "", + "kernel_image_md5sum": null, + "legacy_networking": false, + "linked_clone": true, + "mac_address": "0c:da:4e:49:00:00", + "on_close": "power_off", + "options": "", + "platform": "x86_64", + "process_priority": "normal", + "qemu_path": "/bin/qemu-system-x86_64", + "ram": 768, + "replicate_network_connection_state": true, + "tpm": false, + "uefi": false, + "usage": "There is no default password and enable password. There is no default configuration present. SUPER UPDATED!" + }, + "symbol": ":/symbols/classic/multilayer_switch.svg", + "template_id": "9db64790-65f4-4d38-a1ac-2f6ce45b70db", + "width": 51, + "x": -13, + "y": 54, + "z": 1 + } + ] + }, + "type": "topology", + "variables": null, + "version": "2.2.49", + "zoom": 100 +} \ No newline at end of file From 2416069a6ee187a1209837599b3a7ccaa2b90acf Mon Sep 17 00:00:00 2001 From: grossmj Date: Sat, 20 Jul 2024 17:55:38 +0200 Subject: [PATCH 3/3] Update _convert_2.2.0() with correct comments --- gns3server/controller/topology.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gns3server/controller/topology.py b/gns3server/controller/topology.py index 318edf62..a336aee9 100644 --- a/gns3server/controller/topology.py +++ b/gns3server/controller/topology.py @@ -211,14 +211,13 @@ def _convert_2_2_0(topo, topo_path): Convert topologies from GNS3 2.2.x to 3.0 Changes: - * Removed acpi_shutdown option from Qemu, VMware and VirtualBox - + * Convert Qemu and Docker node names to be a valid RFC1123 hostnames. + * Convert Dynamips and IOU node names to be a valid IOS hostnames. """ topo["revision"] = 10 for node in topo.get("topology", {}).get("nodes", []): - # make sure console_type is not None but "none" string if "properties" in node: if node["node_type"] in ("qemu", "docker") and not is_rfc1123_hostname_valid(node["name"]): new_name = to_rfc1123_hostname(node["name"])