全量复核 4676 项出现 4 失败 6 错误,全是集成时翻为默认开启的 严格快照校验(设计 §2.2)的连锁反应——旧测试用未登记/未标记 快照走 legacy 放行路径。按新语义逐项适配,不改生产校验本身: - test_chv_opt_stage1.CrossTenantRestoreTest:跨租户拒绝的审计 事件改断言 vm_restore_denied(严格路径的设计事件; vm_restore_tenant_denied 只在显式关闭严格校验时出现); legacy 警告放行测试改走显式 CHV_SNAPSHOT_STRICT_TENANT=0。 - test_chv_v3_fixes(5 个 restore 测试):登记带匹配 tenant (proj1)的快照,意图不变(盘预检 / source_url / 清旧 VMM 仍由各自断言覆盖)。 - test_cloud_hypervisor.LifecycleTest:登记 file:///snap/1 (tenant proj1),restore/resume 顺序断言不变。 - 长函数:B 轨合入把 _run_with_persistent_vm 推到 53 行,超 50 行架构上限;finally 收尾块抽为 _suspend_persistent_after_task。 针对性 12 项全部通过;全量待重跑。
This commit is contained in:
1 parent
04a208a98b
commit
6c03ac9b0f
4 files changed
+38
-6
No files matched your search
@@ -3322,15 +3322,19 @@ class CloudHypervisorExecutor(Executor):
|
||||
result["resume_seconds"] = resume_seconds
|
||||
return result
|
||||
finally:
|
||||
self._suspend_persistent_after_task(vm, tenant)
|
||||
|
||||
def _suspend_persistent_after_task(self, vm, tenant):
|
||||
"""持久任务收尾(_run_with_persistent_vm 的 finally 段,
|
||||
拆出只为满足 50 行函数上限):VM 已死即清登记(免得
|
||||
下次 acquire 把死 VM 当可用预热机),否则暂停回池;
|
||||
收尾失败不掩盖任务本身的结果。"""
|
||||
try:
|
||||
if self._vm_proc_dead({"id": vm}):
|
||||
# VM 已死:暂停无意义,清登记,免得下次
|
||||
# acquire 把死 VM 当可用预热机。
|
||||
if tenant:
|
||||
clear_persistent_vm(self.state_dir, tenant)
|
||||
else:
|
||||
self.suspend_after_task({"id": vm},
|
||||
tenant_id=tenant)
|
||||
self.suspend_after_task({"id": vm}, tenant_id=tenant)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@@ -412,8 +412,11 @@ class CrossTenantRestoreTest(ChvOpt1Case):
|
||||
ex._validate_restore(task_b, url)
|
||||
self.assertEqual(ctx.exception.kind,
|
||||
"snapshot_tenant_mismatch")
|
||||
# 严格校验默认开启(设计 §2.2):跨租户拒绝走设计事件
|
||||
# vm_restore_denied;legacy 的 vm_restore_tenant_denied
|
||||
# 只在显式关闭严格校验时才出现。
|
||||
self.assertTrue(any(
|
||||
e == "vm_restore_tenant_denied" for e, _ in events))
|
||||
e == "vm_restore_denied" for e, _ in events))
|
||||
|
||||
def test_same_tenant_restore_passes_validation(self):
|
||||
url = self._snap_url("chv-a")
|
||||
@@ -426,7 +429,11 @@ class CrossTenantRestoreTest(ChvOpt1Case):
|
||||
def test_legacy_unmarked_snapshot_warns_but_passes(self):
|
||||
url = self._snap_url("chv-a", "old")
|
||||
self._record_snapshot("chv-a", url, None)
|
||||
ex = self.make_exec()
|
||||
# legacy 警告放行只在显式关闭严格校验时保留
|
||||
# (CHV_SNAPSHOT_STRICT_TENANT=0;默认开启时未标记
|
||||
# 快照即拒绝,见 test_unmarked_snapshot_denied_in_hybrid_mode)。
|
||||
ex = self.make_exec(env_extra={
|
||||
"CHV_SNAPSHOT_STRICT_TENANT": "0"})
|
||||
events = []
|
||||
ex.audit_callback = lambda e, t, d, k: events.append((e, k))
|
||||
snapshot_url, _net = ex._validate_restore(
|
||||
|
||||
@@ -38,12 +38,14 @@ from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
try:
|
||||
from cloud.chv.disk import record_snapshot
|
||||
from cloud.chv.executor import CloudHypervisorExecutor
|
||||
from cloud.chv.hostkeys import write_seed
|
||||
from cloud.chv.ssh_transport import remote_command
|
||||
from cloud.sandbox import ChvFailure
|
||||
except ImportError:
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from cloud.chv.disk import record_snapshot
|
||||
from cloud.chv.executor import CloudHypervisorExecutor
|
||||
from cloud.chv.hostkeys import write_seed
|
||||
from cloud.chv.ssh_transport import remote_command
|
||||
@@ -195,6 +197,14 @@ class V3Case(unittest.TestCase):
|
||||
fh.write(content)
|
||||
return "file://" + path, path
|
||||
|
||||
def _register_snapshot(self, url, tenant="proj1"):
|
||||
# 严格快照校验(设计 §2.2,默认开启):restore 测试的
|
||||
# 快照须登记带 tenant 且与 _task() 的 project_id 一致;
|
||||
# 本 helper 只登记,不改变测试本身的意图(盘预检 /
|
||||
# source_url / 清旧 VMM 仍由各自断言覆盖)。
|
||||
record_snapshot(self.state_dir, "chv-abc123", url, 20.0,
|
||||
tenant_id=tenant)
|
||||
|
||||
def _spawn_fake_vmm(self, sock_path, argv0="cloud-hypervisor"):
|
||||
"""真实 spawn 一个长眠进程,argv[0] 伪装成 VMM,
|
||||
命令行带 --api-socket <sock>(F2/V-3③ 的扫描目标)。"""
|
||||
@@ -223,6 +233,7 @@ class SnapshotV3Test(V3Case):
|
||||
|
||||
def test_restore_still_passes_source_url(self):
|
||||
url, _ = self._snap_dir()
|
||||
self._register_snapshot(url)
|
||||
ex = self.make_exec()
|
||||
out = ex.restore_vm(self._task(), url)
|
||||
self.assertEqual(out["mode"], "restored")
|
||||
@@ -248,6 +259,7 @@ class SnapshotV3Test(V3Case):
|
||||
class RestorePrepareV3Test(V3Case):
|
||||
def test_restore_kills_registered_old_vmm_and_socket(self):
|
||||
url, _ = self._snap_dir()
|
||||
self._register_snapshot(url)
|
||||
ex = self.make_exec()
|
||||
ex.wake_vm(self._task())
|
||||
old_proc = self.proc
|
||||
@@ -265,6 +277,7 @@ class RestorePrepareV3Test(V3Case):
|
||||
|
||||
def test_restore_kills_unregistered_vmm_by_socket(self):
|
||||
url, _ = self._snap_dir()
|
||||
self._register_snapshot(url)
|
||||
ex = self.make_exec()
|
||||
sock = os.path.join(self.state_dir, "chv-abc123.sock")
|
||||
os.makedirs(self.state_dir, exist_ok=True)
|
||||
@@ -314,6 +327,7 @@ class HibernateDiskV3Test(V3Case):
|
||||
"config.json": json.dumps(
|
||||
{"disks": [{"path": missing_disk}]}).encode(),
|
||||
"state.json": b"{}"})
|
||||
self._register_snapshot(url)
|
||||
with self.assertRaises(ChvFailure) as ctx:
|
||||
ex.restore_vm(self._task(), url)
|
||||
self.assertEqual(ctx.exception.kind, "snapshot_disk_missing")
|
||||
@@ -327,6 +341,7 @@ class HibernateDiskV3Test(V3Case):
|
||||
"config.json": json.dumps(
|
||||
{"disks": [{"path": disk}]}).encode(),
|
||||
"state.json": b"{}"})
|
||||
self._register_snapshot(url)
|
||||
out = ex.restore_vm(self._task(), url)
|
||||
self.assertEqual(out["mode"], "restored")
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
try:
|
||||
from cloud.chv.disk import record_snapshot
|
||||
from cloud.chv.experimental_pool import WarmPool
|
||||
from cloud.sandbox import (
|
||||
ChvFailure,
|
||||
@@ -28,6 +29,7 @@ try:
|
||||
)
|
||||
except ImportError: # discover -s cloud/tests 时把项目根目录补进 sys.path
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from cloud.chv.disk import record_snapshot
|
||||
from cloud.chv.experimental_pool import WarmPool
|
||||
from cloud.sandbox import (
|
||||
ChvFailure,
|
||||
@@ -406,6 +408,10 @@ class LifecycleTest(ChvCase):
|
||||
# 路径 + 声明快照目录(生产默认 provisioned + 白名单
|
||||
# 目录,旧 file:///snap/1 不再直通)。
|
||||
ex = self.make_exec(env_extra={"CHV_SNAPSHOT_DIR": "/snap"})
|
||||
# 严格快照校验(设计 §2.2,默认开启):恢复须登记带
|
||||
# tenant 且与 _task() 的 project_id(proj1)一致。
|
||||
record_snapshot(self.state_dir, "chv-abc123",
|
||||
"file:///snap/1", 20.0, tenant_id="proj1")
|
||||
out = ex.restore_vm(self._task(), "file:///snap/1")
|
||||
self.assertEqual(out["mode"], "restored")
|
||||
self.assertTrue(out["ready"])
|
||||
|
||||
Reference in new issue
Block a user