fix(chv): restore 路径补 H7 net 校验+登记,seed 暂存文件走 atomic_file
restore_vm 此前既不校验 net 冲突、也不登记 net.json: 已登记 VM 的 tap/mac/ip 会被恢复出的 VM 静默复用,且 恢复出的 VM 自身不登记、后来的 wake 也看不到它,两边 都漏判。现与 wake 同款:_validate_restore 在起 VMM 前 校验冲突(net_tap_conflict + vm_failed 审计), _restore_boot 在 restore 成功后登记 net.json,登记失败 审计 net_registry_write_failed + 拒绝恢复(P2-19 语义, stop_vm 清半恢复 VM)。 hostkeys.write_seed/_apply_seed_extras 的 meta-data、 user-data、network-config 改走 atomic_file(mkstemp 0600 → 写 → fsync → rename):user-data 含 host 私钥明文, 直接写 + 事后 chmod 会在 chmod 前以 umask 权限短暂可读; 半截文件本身到不了 ISO(唯一消费者 genisoimage 只在 write_seed 返回后跑),原子写同时堵住权限窗口与半截残留。 回归测试 6 个:restore 冲突拒起/恢复后登记/登记失败 拒起/无 net_json 不登记;seed 走原子写(0600、无 tmp 残留)/写失败不留半截文件。CHV 全套件 395 测试通过。
This commit is contained in:
1 parent
f448ecb74b
commit
06c3e172fe
5 files changed
+211
-18
No files matched your search
+42
-7
@@ -1695,14 +1695,22 @@ class CloudHypervisorExecutor(Executor):
|
||||
return snapshot_url
|
||||
|
||||
def _validate_restore(self, task, snapshot_url):
|
||||
"""restore 前置校验:返回归一化后的 snapshot_url。
|
||||
"""restore 前置校验:返回(归一化后的 snapshot_url,
|
||||
归一化后的 net 条目)。
|
||||
|
||||
restore 不走 vm.create、没有 VmConfig 可挂 seed:
|
||||
快照内已固化原 VM host key,重预置反而破坏钉死,
|
||||
故 provisioned 下复用已钉死的 known_hosts、缺失
|
||||
fail-fast、绝不 keyscan、绝不重生成。restore 时不
|
||||
重复验快照文件存在(远端/对象存储源合法,ch-remote
|
||||
本身会在源缺失时失败)。"""
|
||||
本身会在源缺失时失败)。
|
||||
feat-chv-cover100:restore 也走 H7 net 隔离——此前
|
||||
restore 路径既不校验冲突、也不登记 net.json:已登
|
||||
记 VM 的 tap/mac/ip 会被恢复出的 VM 静默复用,且
|
||||
恢复出的 VM 自身不登记、后来的 wake 也看不到它,
|
||||
两边都漏判。与 wake 的 _wake_prechecks 同款:冲突
|
||||
在起 VMM 前拒绝(net_tap_conflict),登记失败见
|
||||
_restore_boot(P2-19 语义)。"""
|
||||
if not isinstance(task, dict) or task.get("id") is None:
|
||||
raise ValueError("任务缺少 id")
|
||||
if not snapshot_url:
|
||||
@@ -1720,9 +1728,23 @@ class CloudHypervisorExecutor(Executor):
|
||||
"host_key_not_pinned",
|
||||
"provisioned 模式下 restore 缺 known_hosts,拒绝 "
|
||||
"keyscan 回落:VM %s" % self.vm_name(task))
|
||||
return snapshot_url
|
||||
net_entries = []
|
||||
if not self.net_json:
|
||||
return snapshot_url, net_entries
|
||||
try:
|
||||
net_entries = validate_net_entries(
|
||||
parse_net_entries(self.net_json),
|
||||
self._registered_net_entries(
|
||||
exclude_vm=self.vm_name(task)))
|
||||
except ChvFailure as exc:
|
||||
self._emit("vm_failed", task,
|
||||
"vm=%s restore 前置失败 kind=%s"
|
||||
% (self.vm_name(task), exc.kind),
|
||||
exc.kind)
|
||||
raise
|
||||
return snapshot_url, net_entries
|
||||
|
||||
def _restore_boot(self, task, snapshot_url):
|
||||
def _restore_boot(self, task, snapshot_url, net_entries):
|
||||
"""restore 的启动段:起 VMM → 等 ping → restore →
|
||||
显式 resume → 等 SSH 就绪(恢复后默认 paused,不
|
||||
resume 就不算醒)。"""
|
||||
@@ -1732,6 +1754,16 @@ class CloudHypervisorExecutor(Executor):
|
||||
self._check_api_socket_permissions(self.api_socket(task))
|
||||
self._ch_remote(task, "restore",
|
||||
"source_url=%s" % snapshot_url)
|
||||
# feat-chv-cover100:与 _boot_vm 同款——恢复成功后登记
|
||||
# net.json,登记失败即拒恢复(P2-19 语义:审计 +
|
||||
# 返回 False + 调用方 ChvFailure);restore_vm 的
|
||||
# except 会 stop_vm 清掉半恢复 VM。
|
||||
if net_entries and not self._record_net_entries(
|
||||
name, net_entries):
|
||||
raise ChvFailure(
|
||||
"net_registry_write_failed",
|
||||
"vm=%s net 登记写失败,拒绝恢复(缺登记会"
|
||||
"漏判 tap/mac/ip 冲突)" % name)
|
||||
self._emit("vm_restore", task,
|
||||
"vm=%s snapshot=%s" % (name, snapshot_url))
|
||||
self.resume_vm(task)
|
||||
@@ -1742,12 +1774,15 @@ class CloudHypervisorExecutor(Executor):
|
||||
resume → 等 SSH 就绪。恢复后默认 paused,不 resume
|
||||
就不算醒。任一步失败都关 VM 再抛;成功返回
|
||||
{vm, api_socket, state: "running", ready: True,
|
||||
mode: "restored"}。"""
|
||||
snapshot_url = self._validate_restore(task, snapshot_url)
|
||||
mode: "restored"}。恢复前校验 net 冲突、恢复成功后
|
||||
登记 net.json(与 wake 的 H7/P2-19 同款,见
|
||||
_validate_restore/_restore_boot)。"""
|
||||
snapshot_url, net_entries = self._validate_restore(
|
||||
task, snapshot_url)
|
||||
name = self.vm_name(task)
|
||||
self._check_capacity(exclude=name)
|
||||
try:
|
||||
self._restore_boot(task, snapshot_url)
|
||||
self._restore_boot(task, snapshot_url, net_entries)
|
||||
except Exception:
|
||||
try:
|
||||
self.stop_vm(task)
|
||||
|
||||
Reference in new issue
Block a user