Show unbound collect templates as # comments in export.

When a monitoring item has no concrete CLI, export its command_template commented with # instead of omitting it.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-22 11:24:54 +08:00
parent 32deca1687
commit 67930bb348
2 changed files with 56 additions and 10 deletions

View file

@ -1118,6 +1118,18 @@ def plan_task_collect_commands(
) )
except ValueError as exc: except ValueError as exc:
section["notes"].append(str(exc)) section["notes"].append(str(exc))
tmpl = normalize_command(
item.command_override or profile.command_template or ""
)
if tmpl:
section["commands"].append(
{
"command": tmpl,
"role": "template",
"params": {},
"profile_id": profile.profile_id,
}
)
sections.append(section) sections.append(section)
continue continue
@ -1126,14 +1138,15 @@ def plan_task_collect_commands(
section["notes"].append( section["notes"].append(
"expand_all: no bindings; collect will expand discover values" "expand_all: no bindings; collect will expand discover values"
) )
section["commands"].append( if tmpl:
{ section["commands"].append(
"command": tmpl, {
"role": "template", "command": tmpl,
"params": {"__expand_all__": "1"}, "role": "template",
"profile_id": profile.profile_id, "params": {"__expand_all__": "1"},
} "profile_id": profile.profile_id,
) }
)
sections.append(section) sections.append(section)
continue continue
@ -1173,6 +1186,24 @@ def plan_task_collect_commands(
} }
) )
# No concrete primary cmds → still show template as comment
if not any(c.get("role") == "primary" for c in section["commands"]):
tmpl = normalize_command(
item.command_override or profile.command_template or ""
)
if tmpl and not any(
c.get("role") == "template" and c.get("command") == tmpl
for c in section["commands"]
):
section["commands"].append(
{
"command": tmpl,
"role": "template",
"params": {},
"profile_id": profile.profile_id,
}
)
sections.append(section) sections.append(section)
return { return {
@ -1222,11 +1253,17 @@ def export_task_commands_text(
lines.append("# (no commands)") lines.append("# (no commands)")
for c in cmds: for c in cmds:
role = str(c.get("role") or "primary") role = str(c.get("role") or "primary")
cmd = str(c.get("command") or "").strip()
if not cmd:
continue
if role == "aux": if role == "aux":
lines.append(f"# aux:{c.get('aux_key') or ''}") lines.append(f"# aux:{c.get('aux_key') or ''}")
lines.append(cmd)
elif role == "template": elif role == "template":
lines.append("# template (expand_all at collect):") # No concrete CLI — keep template as a # comment line
lines.append(str(c.get("command") or "")) lines.append(f"# {cmd}")
else:
lines.append(cmd)
lines.append("") lines.append("")
# Flat unique list at end for easy copy into scripts # Flat unique list at end for easy copy into scripts
lines.append("# ---- flat unique commands ----") lines.append("# ---- flat unique commands ----")

View file

@ -109,6 +109,15 @@ class BizStateExportCommandsTests(unittest.TestCase):
notes = " ".join(sec.get("notes") or []) notes = " ".join(sec.get("notes") or [])
self.assertIn("requires parameter bindings", notes) self.assertIn("requires parameter bindings", notes)
self.assertEqual(plan["command_count"], 0) self.assertEqual(plan["command_count"], 0)
tmpl_cmds = [c for c in sec.get("commands") or [] if c.get("role") == "template"]
self.assertEqual(len(tmpl_cmds), 1)
self.assertIn("<vrf>", tmpl_cmds[0]["command"])
text = export_task_commands_text(self.db, self.task.id)
self.assertIn("# show bgp vpnv4 unicast vrf <vrf> summary", text)
# Template must not appear in the flat executable list
flat = text.split("# ---- flat unique commands ----", 1)[-1]
self.assertNotIn("<vrf>", flat)
if __name__ == "__main__": if __name__ == "__main__":