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")
|
||||
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)
|
||||
Reference in New Issue
Block a user