copilot: log into devices using the node default credentials

The vendored gns3fy Node model dropped default_username/default_password
from the API response, and the nornir groups hardcoded empty
credentials, so drivers that require authentication (gns3_ruijie_telnet,
stock netmiko SSH/telnet) could not log in.

Carry the per-node credentials through nodes_inventory() into the
nornir hosts data at host level, where they override the group's empty
fallback. Missing or cleared ("") values keep inheriting from the
group, so no-auth drivers are unaffected.
This commit is contained in:
YueGuobin committed 2026-08-21 21:41:42 +08:00
1 parent 38742ad4b6
commit 19f20e8d75
3 files changed
+118 -1

No files matched your search

@@ -1372,6 +1372,8 @@ class Node:
properties: Any | None = None
tags: list[str] | None = None
netmiko_device_type: str | None = None
default_username: str | None = None
default_password: str | None = None
template: str | None = None
links: list[Link] = field(default_factory=list, repr=False)
@@ -2489,6 +2491,8 @@ class Project:
"y": _n.y,
"tags": _n.tags if _n.tags else [],
"netmiko_device_type": _n.netmiko_device_type,
"default_username": _n.default_username,
"default_password": _n.default_password,
}
}
)
@@ -160,7 +160,7 @@ def get_device_ports_from_topology(
# This is the Nornir best practice - each host has its own
# connection configuration (device_type), while sharing common
# settings (hostname, timeout) via group inheritance.
hosts_data[device_name] = {
host_entry = {
"port": node_info["console_port"],
"platform": platform,
"groups": ["network_devices"], # For inheriting hostname, timeout, etc.
@@ -171,6 +171,16 @@ def get_device_ports_from_topology(
},
}
# Per-node default credentials (seeded from the template appliance
# metadata) override the group's empty fallback. Only inject when
# set, so credential-less devices keep inheriting the group values.
if node_info.get("default_username"):
host_entry["username"] = node_info["default_username"]
if node_info.get("default_password"):
host_entry["password"] = node_info["default_password"]
hosts_data[device_name] = host_entry
logger.info("Returning %d device port mappings", len(hosts_data))
return hosts_data