fix: retire legacy sip-only units and record fixed deployment evidence
This commit is contained in:
@@ -81,7 +81,7 @@
|
||||
|
||||
- **当前预生产目标授权(`muzr4gzv-jzx8pg`)**:先核验、合入 main 并推送,再完善一键部署脚本,在登记测试机 `server.sip` 使用根目录 `saas.env`、`rabbitmq.env`、`aliyun-oss.env` 和真实 SaaS 配置,以现有 `nonprod-real` 启动固定的 `go-sip-agent.service`、`go-sip-dispatcher.service`;原生 `go-sip-asterisk.service` 保留。配置固定在 `~/.config/go-sip/`,业务数据固定在 `~/.local/share/go-sip/`,制品在 `~/.local/opt/go-sip/releases/`,不再用每次试验的新业务目录或 Mock 代替预生产验证。下方日期记录是历史事实,其旧授权限制不覆盖本条新授权。
|
||||
- **本轮外呼授权**:真实 SaaS 下发的全部获批外呼任务允许按正式规则执行,不再逐通询问;仍核对归属、号码、时段、额度、并发、有效授权与幂等,不自行生成外呼消息、不盲重拨或换线重拨。独立工具试拨及超出上述真实 SaaS 任务范围的操作仍需另行确认。没有任务或未接通时如实标记未验证,不以 Mock 代签真实通话或生产。
|
||||
- **部署与数据重置**:普通重部署不清数据;仅显式 `--reset-state` 可处理本项目非生产数据。本次首次部署已获准,后续重置须再次确认;必须先停止相关服务、核实零活动通话、完成私密备份与清单,再重置,不把重置当成代码问题修复,不伪造旧通话终结或结果,不清外部 SaaS/MQ/OSS。清理限于两端确认退役的部署制品、临时文件及自有 Mock 设施;不得直接删仍用凭据、SSH 登记、原始证据、录音或恢复,不删除整个用户 `~/.local` 或 Asterisk/其他项目依赖。退役数据按确认范围保留或备份后处理。SaaS 尚未启动不阻断部署:严格保留输入校验与关新准入,允许 Dispatcher 由 systemd 明确等待/重试,不用 Mock 或旧快照;SaaS/依赖业务队列/会话/SIP加载及通话验证延期,独立配置、MQ登录、证书或Asterisk故障仍须修复。部署说明见 [`deploys/preprod/README.md`](deploys/preprod/README.md)。
|
||||
- **部署与数据重置**:普通重部署不清数据;仅显式 `--reset-state` 可处理本项目非生产数据。本次首次部署已获准,后续重置须再次确认;必须先停止相关服务、核实零活动通话、完成私密备份与清单,再重置,不把重置当成代码问题修复,不伪造旧通话终结或结果,不清外部 SaaS/MQ/OSS。清理限于两端确认退役的部署制品、临时文件及自有 Mock 设施;不得直接删仍用凭据、SSH 登记、原始证据、录音或恢复,不删除整个用户 `~/.local` 或 Asterisk/其他项目依赖。退役数据按确认范围保留或备份后处理。SaaS 尚未启动不阻断部署:严格保留输入校验与关新准入,允许 Dispatcher 由 systemd 明确等待/重试,不用 Mock 或旧快照;SaaS/依赖业务队列/会话/SIP加载及通话验证延期,独立配置、MQ登录、证书或Asterisk故障仍须修复。2026-10-08 固定环境首次部署 `e5f46ba` 已完成:Asterisk/Agent enabled+active,Dispatcher enabled且因SaaS业务拓扑尚未供给而auto-restart,业务未ready。旧20个临时服务及自有本地RabbitMQ已私密归档退役;12份配置/证书0600,固定目录0700、linger已开启,但未实际重启验收。历史数据库/恢复事实保留于受控备份,不伪造旧终结;首次固定目录为空,已显式执行本次获批reset,之后普通重部署不reset。部署说明见 [`deploys/preprod/README.md`](deploys/preprod/README.md),证据见 [`docs/evidence/fixed-preprod-systemd-20261008.md`](docs/evidence/fixed-preprod-systemd-20261008.md)。
|
||||
|
||||
- P01–P08 及 K01–K16 已完成**项目内隔离 Mock** 核验;本轮把分散的人类可读契约、文档与第三方对接合为唯一当前规范,不重审已确认规则。若未来另获启动开发/审查子 Agent 授权,必须按使用者指定的 `gpt-5.6-luna`、`max` 思考和 `fast: true` 逐项核验并显式配置,不静默换模型、降档或关闭 fast。
|
||||
- 唯一现行 SaaS↔Dispatcher 业务规范、Schema、拓扑和正常示例由共享仓库统一管理;现行合同只由 Git submodule 提交号固定,不维护重复逐文件或整包 hash;历史来源证据、验证脚本及错误示例放在 `contracts/`,不提交到共享仓库或嵌入运行契约。在本项目的共享入口为 [`contracts/schema/`](contracts/schema/README.md);[`docs/thirds/saas-dispatcher.md`](docs/thirds/saas-dispatcher.md) 只保留导航,不维护另一份规范。内部 Agent RPC 仍在 [`proto/agent/agent.proto`](proto/agent/agent.proto)。本地验收与外部缺口见 [`docs/evidence/saas-dispatcher-p08-acceptance.md`](docs/evidence/saas-dispatcher-p08-acceptance.md)。Markdown 不代替机器合同或外部签收,也不另外维护一份平行字段定义。
|
||||
|
||||
@@ -150,7 +150,7 @@ def ari(home, endpoint='channels'):
|
||||
def stop_for_change(p, legacy=False):
|
||||
if legacy:
|
||||
text = run(['systemctl', '--user', 'list-unit-files', '--type=service', '--no-legend'])
|
||||
units = [line.split()[0] for line in text.splitlines() if line.split()[0].startswith('go-sip-nonprod-') and any(s in line.split()[0] for s in ('dispatcher', 'agent', 'saas'))]
|
||||
units = [line.split()[0] for line in text.splitlines() if line.split()[0].startswith('go-sip-nonprod-') and any(s in line.split()[0] for s in ('dispatcher', 'agent', 'saas', 'sip-only', 'siponly'))]
|
||||
else:
|
||||
units = ['go-sip-dispatcher.service', 'go-sip-agent.service']
|
||||
dispatchers = [u for u in units if 'dispatcher' in u or 'saas' in u]
|
||||
@@ -160,7 +160,7 @@ def stop_for_change(p, legacy=False):
|
||||
if ari(p['home']):
|
||||
raise ValueError('active calls: Agent remains running; no data changes allowed')
|
||||
for unit in units:
|
||||
if 'agent' in unit and unit_properties(unit).get('FragmentPath'):
|
||||
if any(s in unit for s in ('agent', 'sip-only', 'siponly')) and unit_properties(unit).get('FragmentPath'):
|
||||
run(['systemctl', '--user', 'stop', unit])
|
||||
return units
|
||||
|
||||
|
||||
@@ -106,6 +106,21 @@ class SafetyTest(unittest.TestCase):
|
||||
with self.assertRaises(ValueError):
|
||||
self.m.unit_properties('broken.service')
|
||||
|
||||
def test_legacy_sip_only_is_stopped_but_native_asterisk_preserved(self):
|
||||
from unittest.mock import patch
|
||||
calls = []
|
||||
def run(args, **kwargs):
|
||||
calls.append(args)
|
||||
if 'list-unit-files' in args:
|
||||
return 'go-sip-nonprod-sip-only-test.service disabled\ngo-sip-nonprod-siponly-test.service disabled\ngo-sip-asterisk.service enabled'
|
||||
return ''
|
||||
with patch.object(self.m, 'run', side_effect=run), patch.object(self.m, 'ari', return_value=[]), patch.object(self.m, 'unit_properties', return_value={'FragmentPath': '/owned/unit'}):
|
||||
units = self.m.stop_for_change(self.m.paths(Path('/home/synthetic')), legacy=True)
|
||||
self.assertEqual(len(units), 2)
|
||||
self.assertTrue(any('go-sip-nonprod-sip-only-test.service' in a and 'stop' in a for a in calls))
|
||||
self.assertTrue(any('go-sip-nonprod-siponly-test.service' in a and 'stop' in a for a in calls))
|
||||
self.assertFalse(any('go-sip-asterisk.service' in a for a in calls))
|
||||
|
||||
def test_normal_deployment_never_selects_reset(self):
|
||||
self.assertFalse(self.m.reset_requested({}))
|
||||
self.assertFalse(self.m.reset_requested({'reset_state': False}))
|
||||
|
||||
@@ -14,7 +14,7 @@ SaaS 尚未启动,三个正式入口当前均为 HTTP 404;部署不等待 Sa
|
||||
|
||||
## 已完成的退役与保留
|
||||
|
||||
- 18 个旧项目用户服务停止、停用并保留原文件;移除 5 个旧程序。
|
||||
- 20 个旧项目用户服务停止、停用并保留原文件(18 个业务/Mock 服务及另外 2 个已停的 SIP-only 临时服务);移除 5 个旧程序。
|
||||
- 7 个旧项目运行/配置目录先停写、确认零通话、私密冷归档、逐份记录 SHA-256,再删除旧运行副本。数据库、未交付记录、恢复事实不改写为成功。
|
||||
- 本机自有 RabbitMQ 仅有默认空 vhost 和旧 Dispatcher 归属 vhost(19 队列),无其他连接。采用实际配置打开带唯一标识的连接,检查本机连接清单,确认正式 RabbitMQ **不是**该本机服务,而不是仅按地址判断。随后停旧服务,备份数据/配置,停用和移除旧 RabbitMQ;外部服务未改动。
|
||||
- 开发机 6 个确认无进程使用的旧 ELF 程序先逐文件备份和核对 SHA-256,再删除;不删除整个 `.local`。
|
||||
@@ -26,6 +26,10 @@ SaaS 尚未启动,三个正式入口当前均为 HTTP 404;部署不等待 Sa
|
||||
|
||||
部署测试覆盖字面 env 解析、权限/缺字段、OSS 实际格式、固定目录、关准入、独立 MQ 失败、重复部署保留数据、重置确认/冷备份顺序及活动通话保护。Go 诊断只输出阶段、状态、错误类型,不输出原始错误内容。格式、合同/Proto、vet、race、构建、隔离真实 RabbitMQ/HTTPS/mTLS 集成、业务覆盖率与本地发布检查通过;这些不是生产或真实通话签收。
|
||||
|
||||
首次部署 `e5f46ba` 已实测:Asterisk/Agent enabled+active,Dispatcher enabled、auto-restart,最新应用错误为 SaaS 尚未供给业务拓扑;hash 匹配、Agent 监听正常、原生通道/bridge 均 0。12 份私有文件为 0600,5 个受控目录为 0700,linger=yes。首次显式 reset 已执行,固定运行目录原为空;历史状态已另行私密冷归档,没有改写历史结果。后续部署不再携带 reset 参数。
|
||||
|
||||
正式服务版本/hash、私有权限、systemd 状态、Agent 监听和原生 Asterisk 状态由脚本实测。Dispatcher 等待 SaaS 时必须由最新应用日志说明 HTTP 不可用或 SaaS 未供给业务拓扑,不能把其他启动错误算作正常。自动重试不是业务 ready。停/启和重复部署检查不得重新使用首次重置授权。
|
||||
|
||||
测试机已实际执行脚本 stop/start:原固定目录中的现存状态文件 SHA-256 不变,Asterisk/Agent 恢复 enabled+active,Dispatcher 保持明确的 SaaS 拓扑等待状态、零活动通话。普通重复部署同样不传 reset 参数,并按私有 before-repeat-deployment 清单核对原文件保留;最终结果存私有 last-deployment/repeat-deployment-verification 清单,不公开其中原始数据。
|
||||
|
||||
已确认 SSH pin 的沿用不等于经云控制台独立认证;启用 lingering 不等于实际重启测试通过。最终交付需同时核对远程 main、发布清单和服务状态,并明确上述延期项。
|
||||
|
||||
Reference in New Issue
Block a user