瀏覽代碼

docs(acl): 添加高级 ACL 接口设计说明文档

- 新增 ADVANCED_ACL.md 文件,描述高级 ACL 接口的设计目标与实现逻辑
- 详细说明了如何在不改动现有低级接口的前提下实现高级功能
- 定义了三个高级操作接口:查询、添加、删除 IP 的功能与行为
- 描述了配置项、数据契约、接口签名及实现步骤
- 讨论了并发处理、幂等性、权限认证及日志监控等实现细节
mcbaiyun 2 月之前
父節點
當前提交
6f71dc3aec
共有 1 個文件被更改,包括 101 次插入0 次删除
  1. 101 0
      ADVANCED_ACL.md

+ 101 - 0
ADVANCED_ACL.md

@@ -0,0 +1,101 @@
+# 高级 ACL 接口设计说明
+
+本文档描述如何在不改动现有低级接口(`login_post`, `acl_post.get_acl_rules`, `add_acl_post.add_acl_rule`, `edit_acl_post.edit_acl_rule`, `del_acl_post.del_acl_rule`)的前提下,设计并实现一组高级接口,用于集中管理以备注前缀(例如 `Test_`)分组的 ACL 目的地址集合。
+
+## 目标
+- 从所有 ACL 规则中筛选出备注以 `Test_`(可在 `config.json` 中配置)为前缀的规则(例如 `Test_1`, `Test_2` 等)。
+- 提取这些规则中 `dst_addr` 字段的所有 IP(逗号分隔),合并为一个全局去重的文本数组(字符串列表)。
+- 基于该集合提供三个高级操作接口:
+  1. 查询所有 IP 集合(返回去重列表)
+  2. 添加一个 IP 到集合:如果新 IP 导致某个分组规则(如 `Test_1`)超过容量限制(例如 1000),则创建或选用下一个编号的 `Test_n` 规则;必要时使用添加或编辑低级接口来写回。重复 IP 不执行任何操作。
+  3. 删除一个 IP:从对应规则中删除该 IP(若规则变为空可选择删除规则或保留空规则),并更新/编辑/删除低级规则。
+
+## 配置项
+- 在 `config.json` 中新增或使用字段:
+  - `test_prefix`(string, 默认 `"Test_"`) — 用来匹配规则备注前缀。
+  - `rule_ip_limit`(int, 默认 1000) — 单条 ACL 规则允许的最大 IP 数量。
+
+示例:
+```json
+{
+  "base_url": "http://103.236.55.143:8080/",
+  "test_prefix": "Test_",
+  "rule_ip_limit": 1000
+}
+```
+
+## 数据契约
+- IP 集合类型:List[str](去重,保留字符串格式的IP或IP段,按原样存储)
+- 内部表示:Python set 用于去重,返回时转换为 list(可选按字典序排序)
+
+## 高级接口签名(伪 API)
+- get_all_test_ips() -> List[str]
+  - 描述:返回合并后的去重 IP 列表
+- add_ip(ip: str) -> dict
+  - 描述:向集合添加单个 IP,返回操作结果 {"added": True/False, "rule": "Test_1", "row_id": 123, "message": "..."}
+- del_ip(ip: str) -> dict
+  - 描述:从集合删除单个 IP,返回操作结果 {"deleted": True/False, "rule": "Test_1", "message": "..."}
+
+## 实现逻辑(详细步骤)
+
+### A. 获取并构建全局 IP 集合(get_all_test_ips)
+1. 使用现有低级接口 `acl_post.get_acl_rules()` 获取全部规则(`Data.data` 列表)。
+2. 从配置读取 `test_prefix`。
+3. 遍历规则列表,筛选 `comment` 字段以 `test_prefix` 开头的规则(例如 `Test_1`, `Test_2`)。
+4. 对每条匹配规则,读取 `dst_addr` 字段;如果 `dst_addr` 为空则跳过。否则:
+   - 以逗号拆分字符串,去除前后空白,保留原样(IP 或 IP 范围)。
+   - 将拆分出的元素加入一个 Python set 用于去重。
+5. 返回去重后的 sorted(list(set)) 或者原顺序 list(实现可配置)。
+
+注意点:
+- `dst_addr` 可能包含 IP 段(例如 `1.2.3.4-1.2.3.10`)或单个IP,当前实现策略是直接作为字符串项存储,不做IP范围展开。
+- 若需要支持范围展开(拆分多个IP),这是一个可选扩展(成本高,谨慎)。
+
+### B. 添加 IP(add_ip)
+输入:单个字符串 `ip`(例如 `8.8.8.8` 或 `1.2.3.4`)。
+输出:操作结果字典,含是否添加成功、目标规则名/ID 等。
+
+步骤:
+1. 调用 get_all_test_ips() 获取当前去重集合(set)。如果 `ip` 已存在,直接返回 {"added": False, "message": "already exists"}。
+2. 否则需要把 `ip` 放入某个 `Test_n` 规则中:
+  - 首先通过 `acl_post.get_acl_rules()` 获取所有匹配 `test_prefix` 的规则,并按 `comment` 中的编号从小到大排序(例如 `Test_1`, `Test_2`)。同时记录每个规则的 `dst_addr` 列表与 `id`(rule id)。
+  - 遍历这些规则(从编号最小的开始),对于每个规则计算当前 IP 数量,如果加入新 IP 后满足 `current_count + 1 <= rule_ip_limit`,则向该规则进行编辑(使用 `edit_acl_post.edit_acl_rule(rule_id=..., dst_addr=new_dst_str, comment=...)`),将新的 IP 附加到 `dst_addr`(注意去重),并返回该规则的信息(rule id/comment)。
+  - 如果所有已有规则都已满(或没有规则),则创建新的规则:
+    - 若没有任何匹配的 `Test_*` 规则,则创建 `Test_1`(使用 `add_acl_post.add_acl_rule(dst_addr=ip, comment=f"{test_prefix}1")`);
+    - 否则创建 `Test_{k+1}`(k 为当前最大的编号),使用 `add_acl_post.add_acl_rule(dst_addr=ip, comment=f"{test_prefix}{k+1}")`。创建成功后返回新创建的 RowId。
+3. 成功写回后,返回 {"added": True, "rule": "Test_k or Test_{k+1}", "row_id": <id>, "message": "ok"}
+
+错误与回滚考虑:
+- 在编辑时,如果低级接口返回失败(HTTP非200或Result不为Success),应记录错误并返回失败,不应丢失客户端数据。
+- 可选的回滚:如果添加操作分为多步(例如先创建然后编辑),在部分失败情况下尝试回滚(例如删除新创建的规则)。为降低复杂度,初版可以不做复杂回滚,而是保持幂等性并记录失败信息供人工干预。
+
+并发处理:
+- 多个并发添加请求可能导致竞态(例如同时检测到 Test_k 未满并同时写入,超出 limit)。解决策略:
+  1. 在服务端加分布式锁(最佳,但超出本地实现范围);
+  2. 在客户端(高级接口实现处)使用本地文件锁或线程锁,尽量序列化对 ACL 更新的操作;
+  3. 在写回后再次验证规则大小:编辑后重新读取规则并验证数量如超限则将多出的IP移到下一个规则或提示人工处理。
+
+### C. 删除 IP(del_ip)
+输入:单个字符串 `ip`。
+步骤:
+1. 通过 `acl_post.get_acl_rules()` 获取所有匹配 `test_prefix` 的规则,并解析每条规则的 `dst_addr` 到列表形式。
+  - 找到包含目标 `ip` 的所有规则(即支持在多个规则中删除)。对于每个匹配的规则:
+    - 从该规则的 `dst_addr` 列表中移除该 `ip`。
+    - 如果移除后列表不为空,调用 `edit_acl_post.edit_acl_rule(rule_id=..., dst_addr=new_dst_str, comment=...)` 更新该规则;
+    - 如果移除后列表为空,默认应删除该规则(调用 `del_acl_post.del_acl_rule(rule_id=...)`),不保留空规则,以保持规则集合整洁并避免无用占位。
+3. 返回操作结果,包含受影响规则的列表(每个元素包含 `rule_id`、`comment`、`action`:`edited` 或 `deleted`),以及整体操作状态。
+
+边缘情况:
+  - IP 在多个规则中存在:默认行为为删除所有出现的地方,并返回受影响规则列表(而非只删除第一次出现)。
+- 删除导致 hole(例如 Test_2 删除后 Test_1、Test_3 可能不连续),可以不强制重编号,保持 comment 名称不变以减少对外影响。
+
+## 幂等性与幂等操作
+- `add_ip` 对已存在的 IP 操作应当是幂等的(不重复添加)。
+- `del_ip` 对不存在的 IP 操作也应当返回成功/无操作结果。
+
+## 权限与认证
+- 所有高级接口在内部依赖已有的登录与 `sess_key` 管理,不需要额外的认证步骤;但调用者应确保先执行登录流程并设置好全局 sess_key。
+
+## 日志与监控
+- 使用现有 `log_util.log_request` 记录每次低级请求及响应。
+- 在高级接口处记录高层动作(add/del),包括原始IP、目标规则、操作结果与错误信息。