Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions test/case/system/factory_config/test.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ usable, i.e. it does not fall back to the fail-secure failure-config.
Clearing the startup-config makes confd bootstrap running from the
factory-config on the next boot, as on a factory-fresh device.

A factory-config may bridge the management port with the links to the
other devices, so every non-management port of every device in the
physical topology is disabled first, leaving the device alone on the
host's management port.

==== Topology

image::topology.svg[Boot From Factory Config topology, align=center, scaledwidth=75%]
Expand All @@ -17,6 +22,7 @@ image::topology.svg[Boot From Factory Config topology, align=center, scaledwidth

. Set up topology and attach to target DUT
. Determine factory-config hostname
. Disable all non-management ports on every DUT in the physical topology
. Clear startup-config so the device boots from factory
. Reboot onto the factory config
. Verify device is usable and not in failure-config
Expand Down
26 changes: 26 additions & 0 deletions test/case/system/factory_config/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
usable, i.e. it does not fall back to the fail-secure failure-config.
Clearing the startup-config makes confd bootstrap running from the
factory-config on the next boot, as on a factory-fresh device.

A factory-config may bridge the management port with the links to the
other devices, so every non-management port of every device in the
physical topology is disabled first, leaving the device alone on the
host's management port.
"""

import infamy
Expand All @@ -18,6 +23,24 @@ def factory_hostname(target):
factory = target.get_factory("/ietf-system:system/hostname")
return factory.print_dict().get("system", {}).get("hostname")

def isolate(env):
"""Disable every non-management port of every DUT in the physical topology."""
ptop = env.ptop
ctrl = ptop.get_ctrl()

def down(node):
_, mgmt = ptop.get_mgmt_link(ctrl, node)
ports = {e[node] for _, _, e in ptop.g.edges(node, data=True)} - {mgmt}
dev = env.attach(node, test_reset=False)
ifaces = dev.get_config_dict("/ietf-interfaces:interfaces")
ports &= {i["name"] for i in ifaces["interfaces"]["interface"]}
dev.put_config_dicts({"ietf-interfaces": {"interfaces": {
"interface": [{"name": p, "enabled": False} for p in sorted(ports)]
}}})

nodes = sorted(ptop.get_infixen())
parallel(*(lambda n=n: down(n) for n in nodes))

def cleanup(env):
"""Restore the rig to the clean per-test baseline for the next test."""
print("Restoring device to clean test baseline")
Expand All @@ -37,6 +60,9 @@ def cleanup(env):
assert expected, "Could not read hostname from factory-config"
print(f"Factory config hostname is {expected!r}")

with test.step("Disable all non-management ports on every DUT in the physical topology"):
isolate(env)

with test.step("Clear startup-config so the device boots from factory"):
# No startup-config on the startup boot path -> confd bootstraps
# running from the factory-config.
Expand Down
5 changes: 2 additions & 3 deletions test/infamy/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,10 @@ def attach(self, node, port="mgmt", protocol=None, test_reset=True, username=Non
"""Attach to node on port using protocol."""

name = node
if self.ltop:
mapping = None
if self.ltop and node in self.ltop.mapping:
mapping = self.ltop.mapping[node]
node, port = self.ltop.xlate(node, port)
else:
mapping = None

# Precedence:
# 1. Caller specifies `protocol`
Expand Down
Loading