marker: drop deleted marker from port NIO cache to stop empty pcap on restart

Deleting a marker while its node was stopped, then starting the node, recreated
an empty pcap. Root cause: delete_marker_capture removed the uBridge filter and
the pcap file but not the marker spec cached on the port NIO (nio.markers) —
the data source _ubridge_apply_markers reads on node start. The stale spec
reinstalled the marker when uBridge came up.

This was a regression from switching stop_marker off update() (which re-sent
the NIO and implicitly refreshed nio.markers) to the fine-grained
node.delete(/markers/{name}) path.

Fix: make the delete port-aware so the compute can locate the NIO. The DELETE
marker route becomes /adapters/{a}/ports/{p}/markers/{name} across all six
node types; the handler resolves the NIO via get_nio and passes it to
delete_marker_capture, which now pops the marker from nio.markers. get_nio
works regardless of uBridge state, so the stopped-node case is covered. The
controller's stop_marker targets the capture side's adapter/port.
This commit is contained in:
YueGuobin committed 2026-08-05 00:08:12 +08:00
1 parent 1a0ce51f38
commit 75f278228b
10 files changed
+80 -21

No files matched your search

+9 -3
View File
@@ -297,20 +297,26 @@ async def resume_cloud_markers(node: Cloud = Depends(dep_node)) -> None:
@router.delete(
"/{node_id}/markers/{marker_name}",
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/markers/{marker_name}",
status_code=status.HTTP_204_NO_CONTENT
)
async def delete_cloud_marker_capture(
*,
marker_name: str,
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
link_id: str = "",
node: Cloud = Depends(dep_node)
) -> None:
"""
Delete a marker's capture pcap (called by the controller when the marker is
removed) so the file is cleaned up even with the node stopped.
removed) so the file is cleaned up even with the node stopped. Also drops
the marker from the port NIO's cached spec so a node restart won't reinstall
it (and recreate an empty pcap).
"""
await node.delete_marker_capture(marker_name, link_id)
nio = node.get_nio(port_number)
await node.delete_marker_capture(marker_name, link_id, nio)
@router.put("/{node_id}/markers/{marker_name}/rebuild")
@@ -453,21 +453,26 @@ async def resume_docker_markers(node: DockerVM = Depends(dep_node)) -> None:
@router.delete(
"/{node_id}/markers/{marker_name}",
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/markers/{marker_name}",
status_code=status.HTTP_204_NO_CONTENT,
dependencies=[Depends(compute_authentication)]
)
async def delete_docker_marker_capture(
marker_name: str,
adapter_number: int,
port_number: int,
link_id: str = "",
node: DockerVM = Depends(dep_node)
) -> None:
"""
Delete a marker's capture pcap (called by the controller when the marker is
removed) so the file is cleaned up even with the node stopped.
removed) so the file is cleaned up even with the node stopped. Also drops
the marker from the port NIO's cached spec so a node restart won't reinstall
it (and recreate an empty pcap).
"""
await node.delete_marker_capture(marker_name, link_id)
nio = node.get_nio(adapter_number)
await node.delete_marker_capture(marker_name, link_id, nio)
@router.put(
@@ -412,21 +412,26 @@ async def resume_dynamips_markers(node: Router = Depends(dep_node)) -> None:
@router.delete(
"/{node_id}/markers/{marker_name}",
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/markers/{marker_name}",
status_code=status.HTTP_204_NO_CONTENT,
dependencies=[Depends(compute_authentication)]
)
async def delete_dynamips_marker_capture(
marker_name: str,
adapter_number: int,
port_number: int,
link_id: str = "",
node: Router = Depends(dep_node)
) -> None:
"""
Delete a marker's capture pcap (called by the controller when the marker is
removed) so the file is cleaned up even with the node stopped.
removed) so the file is cleaned up even with the node stopped. Also drops
the marker from the port NIO's cached spec so a node restart won't reinstall
it (and recreate an empty pcap).
"""
await node.delete_marker_capture(marker_name, link_id)
nio = node.get_nio(adapter_number, port_number)
await node.delete_marker_capture(marker_name, link_id, nio)
@router.put(
+8 -3
View File
@@ -391,21 +391,26 @@ async def resume_iou_markers(node: IOUVM = Depends(dep_node)) -> None:
@router.delete(
"/{node_id}/markers/{marker_name}",
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/markers/{marker_name}",
status_code=status.HTTP_204_NO_CONTENT,
dependencies=[Depends(compute_authentication)]
)
async def delete_iou_marker_capture(
marker_name: str,
adapter_number: int,
port_number: int,
link_id: str = "",
node: IOUVM = Depends(dep_node)
) -> None:
"""
Delete a marker's capture pcap (called by the controller when the marker is
removed) so the file is cleaned up even with the node stopped.
removed) so the file is cleaned up even with the node stopped. Also drops
the marker from the port NIO's cached spec so a node restart won't reinstall
it (and recreate an empty pcap).
"""
await node.delete_marker_capture(marker_name, link_id)
nio = node.get_nio(adapter_number, port_number)
await node.delete_marker_capture(marker_name, link_id, nio)
@router.put(
+8 -3
View File
@@ -483,21 +483,26 @@ async def resume_qemu_markers(node: QemuVM = Depends(dep_node)) -> None:
@router.delete(
"/{node_id}/markers/{marker_name}",
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/markers/{marker_name}",
status_code=status.HTTP_204_NO_CONTENT,
dependencies=[Depends(compute_authentication)]
)
async def delete_qemu_marker_capture(
marker_name: str,
adapter_number: int,
port_number: int = Path(..., ge=0, le=0),
link_id: str = "",
node: QemuVM = Depends(dep_node)
) -> None:
"""
Delete a marker's capture pcap (called by the controller when the marker is
removed) so the file is cleaned up even with the node stopped.
removed) so the file is cleaned up even with the node stopped. Also drops
the marker from the port NIO's cached spec so a node restart won't reinstall
it (and recreate an empty pcap).
"""
await node.delete_marker_capture(marker_name, link_id)
nio = node.get_nio(adapter_number)
await node.delete_marker_capture(marker_name, link_id, nio)
@router.put(
+9 -3
View File
@@ -390,21 +390,27 @@ async def resume_vpcs_markers(node: VPCSVM = Depends(dep_node)) -> None:
@router.delete(
"/{node_id}/markers/{marker_name}",
"/{node_id}/adapters/{adapter_number}/ports/{port_number}/markers/{marker_name}",
status_code=status.HTTP_204_NO_CONTENT,
dependencies=[Depends(compute_authentication)]
)
async def delete_vpcs_marker_capture(
*,
marker_name: str,
adapter_number: int = Path(..., ge=0, le=0),
port_number: int,
link_id: str = "",
node: VPCSVM = Depends(dep_node)
) -> None:
"""
Delete a marker's capture pcap (called by the controller when the marker is
removed) so the file is cleaned up even with the node stopped.
removed) so the file is cleaned up even with the node stopped. Also drops
the marker from the port NIO's cached spec so a node restart won't reinstall
it (and recreate an empty pcap).
"""
await node.delete_marker_capture(marker_name, link_id)
nio = node.get_nio(port_number)
await node.delete_marker_capture(marker_name, link_id, nio)
@router.put(