Skip to content

Commit b1cc2da

Browse files
committed
Add 'debug at startup' capability
This is a proof-of-concept (for Cisco IOS) of a capability that enables debugging at the very beginning of initial device configuration to ensure no relevant events are lost. It introduces a new node attribute (debug), an extra flag to 'must_be_list' function that can split lines of a string value when netlab expects a list of values, and a sample initial config template. Also, I added a whole document explaning how one could do debugging based on my lovely recent experience with Cisco IOS and Aruba CX (more about those coming soon from the usual soapbox).
1 parent 78fec5f commit b1cc2da

File tree

7 files changed

+77
-3
lines changed

7 files changed

+77
-3
lines changed

docs/node/debug.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
(node-debug)=
2+
# Debugging Network Devices
3+
4+
It's usually trivial to enable debugging on devices running in a virtual lab:
5+
6+
1. Log in to the affected devices
7+
2. Enable debugging
8+
3. Monitor debugging outputs in log files or an SSH session
9+
10+
However, you might want to enable specific debugging printouts every time you start a lab topology. That's pretty easy to do on most devices that allow you to execute regular commands (for example, the **debug** command) within the configuration mode:
11+
12+
1. Create a [custom configuration template](custom-config) that enables debugging, for example:
13+
14+
```
15+
do debug ipv6 routing
16+
do debug bgp ipv6 unicast import events
17+
do debug bgp ipv6 unicast import updates
18+
do debug bgp ipv6 unicast updates out
19+
```
20+
21+
2. Add the name of the custom configuration template to a node **config** list.
22+
23+
```{tip}
24+
This approach allows you to automate debugging in a [multi-vendor environment](custom-config-multivendor)
25+
```
26+
27+
Unfortunately (for debugging purposes), _netlab_ executes the custom configuration templates after configuring the network devices, which means you might lose the interesting part of the debugging information: what happens when the control-plane protocols start.
28+
29+
You can enable debugging *before* configuring network devices with this simple trick:
30+
31+
1. Execute **netlab up --no-config**
32+
2. If needed, execute **netlab initial --ready** to ensure the network devices are fully operational
33+
3. Log into the network devices and enable debugging, or use a custom configuration template and execute it with **netlab config _debugging_template_** (this approach yet again gives you multi-vendor capabilities).
34+
4. Start device configuration with **netlab initial**
35+
36+
Finally, you might be worried that the symptoms you're experiencing depend on the time after the device boots, so you want to enable debugging as soon as possible. In that case, you can use the node **debug** attribute (on devices for which we implemented it), which is a list of device-specific debugging parameters that will be executed at the very beginning of the initial device configuration.
37+
38+
**Caveats:**
39+
40+
* The contents of the **debug** attribute are device-specific. *netlab* currently does not have multi-vendor **debug** capabilites. The values of the **debug** attribute must be relevant to the underlying network device, or you'll get configuration errors during the initial configuration
41+
* The initial device configuration template supplies the mandatory prefix (for example, **do debug**). You only have to list the debugging conditions, for example:
42+
43+
```
44+
nodes:
45+
dut:
46+
module: [ bgp, ospf, routing ]
47+
bgp.as: 65000
48+
device: iol
49+
debug:
50+
- ip routing
51+
- ipv6 routing
52+
- bgp ipv4 unicast updates
53+
- bgp ipv6 unicast updates
54+
```
File renamed without changes.

docs/nodes.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ nodes:
6767
* **config** -- extra [configuration templates](custom-config) applied to this device.
6868
* **cpu** -- virtual CPU cores allocated to the VM lab device. It does not apply to container-based devices.
6969
* **device** -- device type (see [supported platforms](platforms.md)). [Default device type](default-device-type) is specified in **defaults.device**.
70+
* **debug** -- device-specific [debugging settings](node-debug) enabled at the very beginning of the initial device configuration.
7071
* **group** -- list of [groups](topo-groups) this node belongs to.
7172
* **id** -- static node identifier[^id] (see below)
7273
* **image** or **box** -- specifies the Vagrant box or Docker container used by the lab device. Default images for individual device types are defined in system defaults and can be changed with **defaults.devices...** settings ([more details](default-device-image)).
@@ -321,5 +322,6 @@ $ netlab inspect --node all id
321322
.. toctree::
322323
:maxdepth: 1
323324
324-
node-roles.md
325+
node/roles.md
326+
node/debug.md
325327
```

docs/tutorials.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Once you want to know more, check out these lab topology tutorials:
3131
* [Mix Containers and VMs in the Same Lab Topology](https://blog.ipspace.net/2023/02/netlab-vm-containers/)
3232
* [Using VLAN and VRF Links](https://blog.ipspace.net/2023/04/netlab-vrf-vlan-links/)
3333
* [](example-bridge)
34+
* [](node-debug)
3435

3536
## User Interface Tutorials
3637

netsim/ansible/templates/initial/ios.j2

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
hostname {{ inventory_hostname }}
22
!
33
no ip domain lookup
4+
logging buffered 256000
5+
{% for dbg in debug|default([]) %}
6+
{% if loop.first %}
7+
!
8+
! Enable debugging
9+
{% endif %}
10+
do debug {{ dbg }}
11+
{% endfor %}
412
!
513
lldp run
614
!

netsim/data/types.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,15 +438,23 @@ def register_type(tname: str, validator: typing.Callable) -> None:
438438
"""
439439

440440
@type_test(false_value=[],empty_value=[])
441-
def must_be_list(value: typing.Any, make_list: bool = False) -> dict:
441+
def must_be_list(value: typing.Any, make_list: bool = False, split_lines: bool = False) -> dict:
442442

443443
def transform_to_list(value: typing.Any) -> list:
444+
if isinstance(value,str) and split_lines:
445+
return value.rstrip().split("\n")
446+
444447
return [ value ]
445448

446449
if isinstance(value,list): # A list is what we want to have ;)
447450
return { '_valid': True }
448451

449-
if isinstance(value,(str,int,float,bool)): # Handle scalar-to-list transformations with a callback function
452+
# Handle scalar-to-list transformations with a callback function
453+
# Please note that the 'split_lines' value used in that callback function
454+
# is tied to the argument value passed to this function (it's a magic
455+
# transfer of hidden variables)
456+
#
457+
if isinstance(value,(str,int,float,bool)):
450458
return { '_valid': True, '_transform': transform_to_list }
451459

452460
if make_list: # Optional: force any other value to become a list

netsim/defaults/attributes.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ node:
9191
box: str
9292
id: { type: int, min_value: 1, max_value: 150 }
9393
config: list
94+
debug: { type: list, split_lines: True }
9495
group: list
9596
role: { type: str, valid_values: [ router, host, bridge, gateway ] }
9697
mgmt:

0 commit comments

Comments
 (0)