feat: complete phase2 baseline cdr quality rbac
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
# 业务前缀重构第 8 步迁移与发布前验收 Runbook
|
||||
|
||||
## 范围
|
||||
|
||||
本文用于业务前缀、客户网关匹配和落地号码改写重构的发布前准备。当前仍以本地 KVM/Tailscale 环境为准,不进入阿里云生产迁移。
|
||||
|
||||
本步骤覆盖:
|
||||
|
||||
- B 执行新增 Prisma migration 前后的检查。
|
||||
- 旧客户网关单 IP 和旧 `customer_gateway_policies` 到二期模型的安全迁移。
|
||||
- Redis 配置发布检查。
|
||||
- A OpenSIPS/Lua 替换前语法检查和回滚点。
|
||||
- A/B/T 端到端验收清单。
|
||||
|
||||
## 影响、风险与回滚点
|
||||
|
||||
影响范围:
|
||||
|
||||
- MySQL:新增二期表/列后,`customer_gateways.line_group_id`、`customer_gateway_ips`、`customer_gateway_caller_prefixes` 会被迁移脚本写入。
|
||||
- Redis:迁移脚本成功应用后会写 `customer_gateway_config` outbox,config-publisher 会发布新版本配置。
|
||||
- OpenSIPS:后续发布 A 侧 `opensips.cfg` 与 `lisglosips_hotpath.lua` 后,INVITE 鉴权、路由、主被叫改写进入新热路径。
|
||||
- CDR:第 7 步已让 Worker 可写入原始被叫、业务前缀、落地主被叫字段。
|
||||
|
||||
主要风险:
|
||||
|
||||
- 多条旧策略无法自动合并到“一个客户网关一个线路组”,必须人工拆分或确认保留规则。
|
||||
- 旧 `calleeMode=EQUALS/PREFIX` 不能安全推断为业务前缀,必须先在“业务前缀管理”中建立前缀并重新绑定客户网关。
|
||||
- 旧 `callerMode=EQUALS` 在新模型下没有严格等值语义,不能自动迁移为前缀,否则可能扩大匹配范围。
|
||||
- A 侧 OpenSIPS 配置替换会影响现有通话,必须维护窗口或确认可接受。
|
||||
|
||||
回滚点:
|
||||
|
||||
- B 数据库:执行 migration 前必须按 S30 Runbook 备份 MySQL;迁移脚本 apply 前需保存 dry-run 报告。
|
||||
- B release:保留当前 `/opt/lisglosips/current` 指向,可通过 S30 rollback 脚本切回旧 release。
|
||||
- Redis:记录 `cfg:active_version` 与 `cfg:previous_version`,必要时切回上一版本。
|
||||
- A OpenSIPS:替换前备份 `/etc/opensips/opensips.cfg` 与 `/etc/opensips/lisglosips_hotpath.lua`;语法检查失败不得重启;重启后失败则恢复备份并再次 `opensips -C`。
|
||||
|
||||
## 迁移脚本
|
||||
|
||||
本仓库新增:
|
||||
|
||||
```bash
|
||||
scripts/phase2-gateway-migration.mjs
|
||||
```
|
||||
|
||||
默认 dry-run,不写库:
|
||||
|
||||
```bash
|
||||
node scripts/phase2-gateway-migration.mjs --json
|
||||
```
|
||||
|
||||
显式 apply 才写库:
|
||||
|
||||
```bash
|
||||
node scripts/phase2-gateway-migration.mjs --apply --json
|
||||
```
|
||||
|
||||
脚本只自动迁移满足以下条件的客户网关:
|
||||
|
||||
- 每个客户网关恰好一条启用旧策略。
|
||||
- 旧策略 `calleeMode=ANY`。
|
||||
- 旧策略 `callerMode=ANY`,或 `callerMode=PREFIX` 且 `callerValue` 非空。
|
||||
|
||||
脚本会拒绝自动迁移以下情况:
|
||||
|
||||
- 多条启用旧策略。
|
||||
- 没有启用旧策略。
|
||||
- 旧被叫等值或前缀匹配。
|
||||
- 旧主叫等值匹配。
|
||||
- 新旧线路组字段冲突。
|
||||
|
||||
apply 成功后,脚本会写入一个 `customer_gateway_config` outbox,用于触发配置发布。
|
||||
|
||||
## B 侧发布前步骤
|
||||
|
||||
1. 记录状态:
|
||||
|
||||
```bash
|
||||
readlink -f /opt/lisglosips/current
|
||||
mysql -NBe "SELECT migration_name, finished_at FROM _prisma_migrations ORDER BY finished_at DESC LIMIT 5;"
|
||||
redis-cli --no-auth-warning GET cfg:active_version
|
||||
```
|
||||
|
||||
2. 执行 S30 备份:
|
||||
|
||||
```bash
|
||||
sudo /opt/lisglosips/current/infra/server-b/s30/lisglosips-release-preflight.sh
|
||||
sudo /usr/local/sbin/lisglosips-mysql-backup
|
||||
sudo /usr/local/sbin/lisglosips-redis-backup
|
||||
```
|
||||
|
||||
3. 部署新 release 到独立目录,不在线修改 current。
|
||||
|
||||
4. 执行数据库 migration:
|
||||
|
||||
```bash
|
||||
export DATABASE_URL='mysql://<MIGRATE_USER>@127.0.0.1:3306/lisglosips'
|
||||
pnpm exec prisma migrate deploy
|
||||
pnpm exec prisma migrate status
|
||||
```
|
||||
|
||||
5. 迁移脚本 dry-run:
|
||||
|
||||
```bash
|
||||
export DATABASE_URL='mysql://<MIGRATE_USER>@127.0.0.1:3306/lisglosips'
|
||||
node scripts/phase2-gateway-migration.mjs --json > /tmp/phase2-gateway-migration.dry-run.json
|
||||
```
|
||||
|
||||
6. 若 `blockers` 非空,先人工处理,不执行 apply。
|
||||
|
||||
7. 确认 dry-run 后执行 apply:
|
||||
|
||||
```bash
|
||||
node scripts/phase2-gateway-migration.mjs --apply --json > /tmp/phase2-gateway-migration.apply.json
|
||||
```
|
||||
|
||||
8. 等待或触发 config-publisher,检查新配置发布:
|
||||
|
||||
```bash
|
||||
systemctl status lisglosips@config-publisher --no-pager
|
||||
redis-cli --no-auth-warning GET cfg:active_version
|
||||
```
|
||||
|
||||
## A 侧 OpenSIPS 发布前步骤
|
||||
|
||||
1. 备份:
|
||||
|
||||
```bash
|
||||
sudo install -d -m 0750 /var/backups/lisglosips-phase2
|
||||
sudo cp -a /etc/opensips/opensips.cfg /var/backups/lisglosips-phase2/opensips.cfg.$(date +%Y%m%d%H%M%S)
|
||||
sudo cp -a /etc/opensips/lisglosips_hotpath.lua /var/backups/lisglosips-phase2/lisglosips_hotpath.lua.$(date +%Y%m%d%H%M%S)
|
||||
```
|
||||
|
||||
2. 替换候选文件后,加载 Lua 并确认 SHA 与 `opensips.cfg` 中 `EVALSHA` 一致。
|
||||
|
||||
3. 必须先执行语法检查:
|
||||
|
||||
```bash
|
||||
sudo opensips -C -f /etc/opensips/opensips.cfg
|
||||
```
|
||||
|
||||
4. 语法检查通过后才可重启:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart opensips
|
||||
sudo systemctl is-active opensips
|
||||
```
|
||||
|
||||
## A/B/T 验收清单
|
||||
|
||||
至少验证以下呼叫:
|
||||
|
||||
- 命中业务前缀:例如客户送 `67118822190000`,话单 `callee=18822190000`,`raw_callee=67118822190000`,`business_prefix=671`。
|
||||
- 任意被叫规则:客户网关 `calleeMatchMode=ANY` 时,旧无业务前缀呼叫仍可路由。
|
||||
- 主叫前缀命中:配置 `callerPrefixes` 后,命中前缀允许呼叫。
|
||||
- 主叫前缀不命中:返回 `CALLER_PREFIX_NOT_MATCHED`。
|
||||
- 业务前缀不命中:返回 `BUSINESS_PREFIX_NOT_MATCHED`。
|
||||
- 落地被叫前缀:落地侧实际 Request-URI 被叫包含 `landingCalleePrefix`。
|
||||
- 落地指定主叫:落地侧 From 主叫按权重池选择,话单 `landing_caller` 有值。
|
||||
- 屏蔽地区跳过:命中落地网关屏蔽地区时尝试同线路组下一网关。
|
||||
- 当前通话页:呼叫过程中可看到当前通话,强制挂断可用。
|
||||
- 话单详情:可看到原始被叫、业务前缀、落地主叫、落地被叫、地级市、运营商。
|
||||
|
||||
## 回滚
|
||||
|
||||
B 应用回滚:
|
||||
|
||||
```bash
|
||||
sudo infra/server-b/s30/lisglosips-release-rollback.sh /opt/lisglosips/releases/<previous-release>
|
||||
```
|
||||
|
||||
Redis 配置回滚:
|
||||
|
||||
```bash
|
||||
# 使用当前系统已验证的 Redis 运维方式切回 cfg:previous_version
|
||||
```
|
||||
|
||||
A OpenSIPS 回滚:
|
||||
|
||||
```bash
|
||||
sudo cp -a /var/backups/lisglosips-phase2/<opensips.cfg.backup> /etc/opensips/opensips.cfg
|
||||
sudo cp -a /var/backups/lisglosips-phase2/<lisglosips_hotpath.lua.backup> /etc/opensips/lisglosips_hotpath.lua
|
||||
sudo opensips -C -f /etc/opensips/opensips.cfg
|
||||
sudo systemctl restart opensips
|
||||
```
|
||||
|
||||
数据库回滚原则:
|
||||
|
||||
- 本次 migration 为向前兼容新增表/列,不做破坏性 down migration。
|
||||
- 若 apply 后发现业务规则错误,优先通过客户网关页面/API 修正 `lineGroupId`、主叫规则和业务前缀绑定,再重新发布 Redis 配置。
|
||||
- 若必须恢复数据,使用执行前 MySQL 备份在隔离环境验证后再恢复。
|
||||
Reference in New Issue
Block a user