remove move api
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
This commit is contained in:
@@ -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)
|
||||||
Reference in New Issue
Block a user