remove move api
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s

This commit is contained in:
2026-02-28 15:36:44 +01:00
parent 60fd926fc6
commit 6fcff2d042

View File

@@ -824,144 +824,4 @@ def exec_raw(req: RawCmdRequest):
logger.exception("exec_raw failed") logger.exception("exec_raw failed")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
# ---------- New endpoints: move rules ----------
@router.post("/rules/{handle}/move", response_model=MoveResult, summary="Move rule to a new position within the same chain")
def move_rule(handle: int, req: MoveRequest):
"""
Move a rule identified by its handle to a new position in the same chain.
Strategy:
- read JSON ruleset to find the rule with given handle and its expr
- render expr -> textual fragment with expr_to_text
- add rule at desired position with 'add rule <family> <table> <chain> position <n> <expr>'
- delete the original rule by handle
Notes:
- If expr_to_text cannot deterministically render the expr, the endpoint returns 400.
- position is zero-based; position equal to number of rules appends.
"""
try:
# validate chain identity
family = req.family
table = req.table
chain = req.chain
# load ruleset JSON
try:
nft_json = mgr.list_rules_json()
except NftError as e:
logger.warning("move_rule: cannot read nft JSON: %s", e)
raise HTTPException(status_code=500, detail="Could not read nft JSON ruleset")
custom = build_predictable_ruleset(nft_json)
# find chain rules
chain_rules: List[Dict[str, Any]] = []
for t in custom.get("tables", []):
if t.get("family") == family and t.get("name") == table:
for ch in t.get("chains", []):
if ch.get("name") == chain:
chain_rules = ch.get("rules", [])
break
if chain_rules is None or len(chain_rules) == 0:
raise HTTPException(status_code=404, detail="Chain not found or chain contains no rules")
# find the rule by handle
source_rule = None
for r in chain_rules:
# handle may be int or convertible; do tolerant compare
try:
if r.get("handle") is not None and int(r.get("handle")) == int(handle):
source_rule = r
break
except Exception:
continue
if source_rule is None:
raise HTTPException(status_code=404, detail=f"Rule with handle {handle} not found in chain")
# render textual fragment
expr = source_rule.get("expr")
rendered = expr_to_text(expr)
if rendered is None:
raise HTTPException(status_code=400, detail="Cannot deterministically render rule expr to textual nft; move not possible via this endpoint")
# compute target position
target_pos: Optional[int] = None
if req.to_top:
target_pos = 0
elif req.to_bottom:
target_pos = len(chain_rules) # append
elif req.before_handle is not None:
# find index of before_handle
idx = next((i for i, rr in enumerate(chain_rules) if rr.get("handle") is not None and int(rr.get("handle")) == int(req.before_handle)), None)
if idx is None:
raise HTTPException(status_code=404, detail=f"before_handle {req.before_handle} not found in chain")
target_pos = idx
elif req.position is not None:
# clamp to [0, len]
target_pos = max(0, min(len(chain_rules), int(req.position)))
else:
raise HTTPException(status_code=400, detail="No target position specified (provide position, before_handle, to_top or to_bottom)")
# If the position corresponds to the same location as original and moving a later->earlier or vice versa might shift indices,
# we proceed anyway: simplest reliable approach is add at target_pos then delete original handle.
add_cmd = f"add rule {family} {table} {chain} position {target_pos} {rendered}"
logger.info("move_rule: add_cmd=%s (moving handle %s to pos %s)", add_cmd, handle, target_pos)
# Execute add
add_res_raw = mgr.cmd(add_cmd)
add_rc = int(add_res_raw.get("rc") or -1)
add_stdout = add_res_raw.get("stdout") or ""
add_stderr = add_res_raw.get("stderr") or ""
add_exec = MoveSubResult(
cmd=add_cmd,
out=ExecResult(rc=add_rc, stdout=add_stdout or None, stderr=add_stderr or None)
if add_res_raw is not None
else None,
err=None,
)
# If add failed decisively (non-zero rc and stderr present) -> return error without deleting original
if add_rc != 0 and add_stderr.strip() != "":
add_exec.err = f"add failed: rc={add_rc}, stderr={add_stderr}"
logger.warning("move_rule: add failed: %s", add_exec.err)
raise HTTPException(status_code=400, detail=add_exec.err)
# If add produced rc !=0 but stderr empty, attempt to detect presence like you do elsewhere
if add_rc != 0 and add_stderr.strip() == "":
try:
chain_text = mgr.list_chain_text(family, table, chain) or ""
if rendered not in chain_text:
add_exec.err = f"add reported rc={add_rc} and rule not found in chain text"
logger.warning("move_rule: add ambiguous: %s", add_exec.err)
raise HTTPException(status_code=400, detail=add_exec.err)
# otherwise treat as success
add_exec.out = ExecResult(rc=0, stdout=add_stdout or None, stderr=add_stderr or None)
except Exception:
add_exec.err = f"add reported rc={add_rc}, and verification failed"
raise HTTPException(status_code=400, detail=add_exec.err)
# Now delete the original rule by handle
try:
mgr.delete_rule_by_handle_text(family=family, table=table, chain=chain, handle=int(handle))
del_exec = MoveSubResult(cmd=f"delete rule {family} {table} {chain} handle {handle}", out=ExecResult(rc=0, stdout="", stderr=""), err=None)
except Exception as e:
# We succeeded adding but failed deleting - report both
err_msg = f"added new rule but deleting original handle {handle} failed: {e}"
logger.exception(err_msg)
del_exec = MoveSubResult(cmd=f"delete rule {family} {table} {chain} handle {handle}", out=None, err=str(e))
# Return a 500 (partial success)
raise HTTPException(status_code=500, detail={"added": add_exec, "deleted": del_exec})
# success
return MoveResult(added=add_exec, deleted=del_exec)
except HTTPException:
# re-raise so FastAPI handles it
raise
except Exception as e:
logger.exception("move_rule internal error")
raise HTTPException(status_code=500, detail=str(e))
app.include_router(router) app.include_router(router)