mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-10-27 02:32:23 +02:00
Merge pull request #3026 from tikD1337/fix/node-names-adapter-type
fix: node names from templates with "+" and custom adapters with a null type
This commit is contained in:
commit
2c10782635
@ -1561,5 +1561,7 @@ class BaseNode:
|
||||
if self.custom_adapters:
|
||||
for custom_adapter in self.custom_adapters:
|
||||
if custom_adapter["adapter_number"] == adapter_number:
|
||||
return custom_adapter
|
||||
# settings left unset are null (e.g. "adapter_type" when only the
|
||||
# port is renamed): drop them so callers fall back to the node's own
|
||||
return {key: value for key, value in custom_adapter.items() if value is not None}
|
||||
return {}
|
||||
|
||||
@ -38,6 +38,7 @@ from ..config import Config
|
||||
from ..utils.application_id import get_next_application_id, is_iol_runner_environment
|
||||
from ..utils.asyncio import aiozipstream, locking, wait_run_in_executor
|
||||
from ..utils.asyncio.pool import Pool
|
||||
from ..utils.hostname import template_name_to_node_name
|
||||
from ..utils.packet_filter_validation import validate_bpf_syntax
|
||||
from ..utils.path import check_path_allowed, get_default_project_directory
|
||||
from .compute import ComputeError
|
||||
@ -622,7 +623,7 @@ class Project:
|
||||
log.info(f'Creating node from template "{template_name}" on compute "{compute.name}" [{compute.id}]')
|
||||
default_name_format = template.pop("default_name_format", "{name}-{0}")
|
||||
if name is None:
|
||||
name = default_name_format.replace("{name}", template_name)
|
||||
name = default_name_format.replace("{name}", template_name_to_node_name(template_name, node_type))
|
||||
# the appliance metadata stays template level: only the default
|
||||
# credentials are seeded on the node (where they can be overridden)
|
||||
appliance_metadata = template.pop("appliance_metadata", None) or {}
|
||||
|
||||
@ -110,3 +110,22 @@ def to_rfc1123_hostname(name: str) -> str:
|
||||
name = name[:253]
|
||||
|
||||
return name
|
||||
|
||||
|
||||
def template_name_to_node_name(name: str, node_type: str) -> str:
|
||||
"""
|
||||
Convert a template name to the base of the names of the nodes created from it.
|
||||
|
||||
Spaces are removed. For the node types whose names the compute validates as
|
||||
hostnames, the other invalid characters (e.g. "+" in a model name) are replaced
|
||||
by hyphens: RFC 1123 for Qemu and Docker, IOS for Dynamips and IOU.
|
||||
"""
|
||||
|
||||
name = name.replace(" ", "")
|
||||
if node_type in ("qemu", "docker"):
|
||||
name = re.sub(r"[^a-zA-Z0-9.-]", "-", name)
|
||||
elif node_type in ("dynamips", "iou"):
|
||||
name = re.sub(r"[^a-zA-Z0-9-]", "-", name)
|
||||
else:
|
||||
return name
|
||||
return name.strip("-.") or node_type
|
||||
|
||||
@ -798,6 +798,21 @@ async def test_build_command_with_virtio_net_pci_adapter(vm):
|
||||
assert "virtio-net-pci,mac=00:00:ab:0e:0f:09,speed=10000,duplex=full,bus=pci-bridge1,addr=0x00,netdev=gns3-0" in cmd
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_command_custom_adapter_without_type(vm):
|
||||
"""
|
||||
A custom adapter that only renames a port is saved with "adapter_type": null:
|
||||
the node's adapter type applies instead of "-device None", which QEMU rejects.
|
||||
"""
|
||||
|
||||
vm.adapters = 1
|
||||
vm.mac_address = "00:00:ab:0e:0f:09"
|
||||
vm.custom_adapters = [{"adapter_number": 0, "port_name": "sfp1", "adapter_type": None, "mac_address": None}]
|
||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
|
||||
cmd = await vm._build_command()
|
||||
assert "e1000,mac=00:00:ab:0e:0f:09,bus=pci-bridge1,addr=0x00,netdev=gns3-0" in cmd
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_build_command_with_invalid_options(vm):
|
||||
|
||||
|
||||
@ -253,6 +253,35 @@ async def test_add_node_from_template_seeds_default_credentials(controller):
|
||||
assert "default_password" not in node.properties
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_node_from_template_name_invalid_in_hostname(controller):
|
||||
"""
|
||||
A template name with characters invalid in a hostname (e.g. "+" in a model name)
|
||||
gives node names the compute accepts.
|
||||
"""
|
||||
|
||||
compute = MagicMock()
|
||||
compute.id = "local"
|
||||
controller._computes["local"] = compute
|
||||
project = Project(controller=controller, name="Test")
|
||||
project.emit_notification = MagicMock()
|
||||
|
||||
response = MagicMock()
|
||||
response.json = {"console": 2048}
|
||||
compute.post = AsyncioMagicMock(return_value=response)
|
||||
|
||||
template = {
|
||||
"name": "MikroTik CCR1072-1G-8S+",
|
||||
"template_type": "qemu",
|
||||
"compute_id": "local",
|
||||
"default_name_format": "{name}-{0}",
|
||||
"properties": {},
|
||||
}
|
||||
|
||||
node = await project.add_node_from_template(template)
|
||||
assert node.name == "MikroTikCCR1072-1G-8S-1"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_node_non_local(controller):
|
||||
"""
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
# 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 pytest
|
||||
|
||||
from gns3server.utils import hostname
|
||||
|
||||
|
||||
@ -118,3 +120,20 @@ def test_rfc1123_conversion_hostname_with_all_numeric_tld_replaced():
|
||||
|
||||
def rfc1123_hostname_with_multiple_consecutive_invalid_characters():
|
||||
assert hostname.to_rfc1123_hostname("hostname!!!.example..com") == "hostname---.example.com"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"name,node_type,expected",
|
||||
[
|
||||
("MikroTik CCR1072-1G-8S+", "qemu", "MikroTikCCR1072-1G-8S"),
|
||||
("MikroTik RB450G", "qemu", "MikroTikRB450G"),
|
||||
("Cisco IOSv 15.9", "qemu", "CiscoIOSv15.9"),
|
||||
("ubuntu:22.04", "docker", "ubuntu-22.04"),
|
||||
("IOU L2 15.2", "iou", "IOUL215-2"),
|
||||
("c7200+", "dynamips", "c7200"),
|
||||
("PC 1+", "vpcs", "PC1+"),
|
||||
("+++", "qemu", "qemu"),
|
||||
],
|
||||
)
|
||||
def test_template_name_to_node_name(name, node_type, expected):
|
||||
assert hostname.template_name_to_node_name(name, node_type) == expected
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user