Commit 791bc3ff7b for frr
commit 791bc3ff7b27adcf793acb751a6115fa1b984792
Author: Rafael Zalamena <rzalamena@opensourcerouting.org>
Date: Fri Oct 9 16:52:30 2026 +0000
tools: fix frr-reload "no" retry inside a context
This commit fixes two issues:
1. `original_cmd` was pointing to `cmd`, so when the loop was entered it
would alter the original command that failed.
2. `lines_to_config()` last command is always "exit" so the loop would
give up on the first try.
Since commit 792ada4738 ("tools: always append "exit" in frr-reload.py")
`lines_to_config()` closes every context it opens with "exit", but the
retry still trimmed the last line (`last_arg` was always "exit" and
`len(["exit"])` was always `<= 2`).
The retry now trims the last line before the "exit" lines. Example, when
vtysh rejects:
```
interface eth0
no ip ospf authentication message-digest 1.1.1.1
exit
```
The next attempt is:
```
interface eth0
no ip ospf authentication message-digest
exit
```
And so on, one word at a time, until vtysh accepts it or only
"no WORD" is left.
Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index d3eedc56c1..f08cadd80b 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -2795,9 +2795,18 @@ def delete_line_with_vtysh(vtysh, ctx_keys, line):
reload.
"""
cmd = lines_to_config(ctx_keys, line, True)
- original_cmd = cmd
vrf_ctx_del = is_vrf_context_delete(ctx_keys, line)
+ # Create a copy of list `cmd` instead of pointing to `cmd`, because
+ # it will be modified later in the loop below.
+ original_cmd = list(cmd)
+
+ # `lines_to_config()` closes every context it opens with "exit", so the
+ # command to trim is the last line that is not an "exit".
+ cmd_index = len(cmd) - 1
+ while cmd_index > 0 and cmd[cmd_index].strip() == "exit":
+ cmd_index -= 1
+
while True:
try:
vtysh(["configure"] + cmd)
@@ -2828,17 +2837,18 @@ def delete_line_with_vtysh(vtysh, ctx_keys, line):
# - Split that last entry by whitespace and drop the last word
log.error("Failed to execute %s", " ".join(cmd))
log.error("%s", e)
- last_arg = cmd[-1].split(" ")
+ no_line = cmd[cmd_index]
+ indent = no_line[: len(no_line) - len(no_line.lstrip())]
+ words = no_line.split()
- if len(last_arg) <= 2:
+ if len(words) <= 2:
log.error(
'"%s" we failed to remove this command',
" -- ".join(original_cmd),
)
return False
- new_last_arg = last_arg[0:-1]
- cmd[-1] = " ".join(new_last_arg)
+ cmd[cmd_index] = indent + " ".join(words[:-1])
else:
# Success is not logged here: lines_to_del is logged upfront before
# deletes run (see reload path), matching ADD's avoid-double-log.