fix[zbs]: fail attach when host deploy failure ratio reaches threshold (ZSTAC-86222)#4473
fix[zbs]: fail attach when host deploy failure ratio reaches threshold (ZSTAC-86222)#4473ZStack-Robot wants to merge 1 commit into
Conversation
|
Warning
|
| Layer / File(s) | Summary |
|---|---|
Vhost 部署流程失败传播修正 plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java, utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java |
prepare-vhost-target-env 和 deploy-vhost-target 的失败回调改为直接终止 flow,并补充相关公开错误码常量。 |
新增失败比例阈值全局配置 storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageGlobalConfig.java, storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java |
新增 ATTACH_HOST_DEPLOY_FAILURE_RATIO_THRESHOLD 配置及其取值校验,限制阈值范围在 0 到 1 之间。 |
ExternalPrimaryStorage 挂载阈值容错 storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java |
attachHook() 记录成功部署主机、失败计数和阈值判断,并在成功分支使用成功主机激活心跳卷拓扑。 |
新增挂载失败阈值集成测试 test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostAttachDeployFailureCase.groovy, test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostVolumeCase.groovy |
新增测试类覆盖阈值触发失败、低于阈值成功和失败主机后续自愈流程,并调整现有回退测试的阈值配置。 |
Estimated code review effort: 4 (Complex) | ~45 minutes
Sequence Diagram(s)
sequenceDiagram
participant ExternalPrimaryStorage
participant DeployClient
participant GlobalConfig
participant HeartbeatVolume
ExternalPrimaryStorage->>GlobalConfig: 读取 ATTACH_HOST_DEPLOY_FAILURE_RATIO_THRESHOLD
loop 每台主机
ExternalPrimaryStorage->>DeployClient: deployClient
DeployClient-->>ExternalPrimaryStorage: 成功或失败回调
alt 成功
ExternalPrimaryStorage->>ExternalPrimaryStorage: 记录 deployedHosts
else 失败
ExternalPrimaryStorage->>ExternalPrimaryStorage: 更新状态为 Disconnected 并递增 failedCount
ExternalPrimaryStorage->>ExternalPrimaryStorage: 比较 failedCount / totalHosts 与 threshold
end
end
ExternalPrimaryStorage->>HeartbeatVolume: 用 deployedHosts.peek() 激活心跳卷拓扑
Poem
小兔蹦蹦看阈值,
一半成败各有期。
失败不再悄悄过,
成功主机领心脉。
🐇
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | 标题准确概括了当主机部署失败比例达到阈值时阻止 attach 的核心改动。 |
| Description check | ✅ Passed | 描述与实际改动一致,涵盖了失败处理、阈值控制、新配置和相关测试。 |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
sync/jin.ma/fix/ZSTAC-86222-attach-deploy-threshold@@2
Warning
There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
🔧 ast-grep (0.44.1)
utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java
ast-grep timed out on this file
Comment @coderabbitai help to get the list of available commands.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java (1)
423-428: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
deploy-vhost-target的 host 缺失分支应直接失败同一条 vhost 流程里,
activate/deactivate在getKvmHost(h) == null时都会返回错误;这里却只是warn后trigger.next(),会把“实际没部署成功”当成成功继续走下去。建议同样改为失败中断。🐛 建议修复
KVMHostVO host = getKvmHost(h); if (host == null) { - logger.warn(String.format("cannot find kvm host[uuid:%s], skip vhost target deploy", h.getUuid())); - trigger.next(); - return; + trigger.fail(operr(ORG_ZSTACK_STORAGE_ZBS_10010, "cannot find kvm host[uuid:%s], unable to deploy vhost target", h.getUuid())); + return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java` around lines 423 - 428, The deploy-vhost-target path in ZbsStorageController should not continue when getKvmHost(h) returns null, since that means the target host is missing and the operation did not actually succeed. Update this branch to fail the flow instead of only logging a warning and calling trigger.next(), matching the existing activate/deactivate handling in the same class by returning an error through the current trigger/error path and stopping further execution.storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java (1)
140-190: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win避免始终使用
hostInventories.get(0)激活心跳卷。
storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java:190这里在失败比例低于阈值时会继续放行,但第一个 host 可能正是deployClient失败的那个,activateHeartbeatVolumeForAttach仍会在收尾阶段失败,抵消这次容错。应从成功部署的 host 中选一个,或在没有成功 host 时直接失败。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java` around lines 140 - 190, The attach flow in ExternalPrimaryStorage currently always calls activateHeartbeatVolumeForAttach with hostInventories.get(0), which can pick a host whose deployClient failed and cause a late attach failure. Update the completion path in the WhileDoneCompletion for the attach/reconnect loop to choose a host that successfully completed deployClient and updateHostProtocolStatus, and pass that host to activateHeartbeatVolumeForAttach; if no host succeeded, fail the operation instead of defaulting to the first entry.
🧹 Nitpick comments (1)
plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java (1)
408-408: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
prepare-vhost-target-env失败复用了update-host-client-dependency的错误码Line 408 新增的失败路径复用了
ORG_ZSTACK_STORAGE_ZBS_10011(该错误码在 Line 374 已用于update-host-client-dependency步骤失败)。两处语义不同(依赖更新 vs vhost 环境准备),复用同一错误码会降低问题定位和日志可追溯性。建议为prepare-vhost-target-env失败分配独立的错误码常量。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java` at line 408, The prepare-vhost-target-env failure path in ZbsStorageController is reusing the same error code as update-host-client-dependency, so assign a separate error code constant for the vhost environment preparation failure and update the trigger.fail(operr(...)) call to use that new symbol instead of ORG_ZSTACK_STORAGE_ZBS_10011.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java`:
- Around line 423-428: The deploy-vhost-target path in ZbsStorageController
should not continue when getKvmHost(h) returns null, since that means the target
host is missing and the operation did not actually succeed. Update this branch
to fail the flow instead of only logging a warning and calling trigger.next(),
matching the existing activate/deactivate handling in the same class by
returning an error through the current trigger/error path and stopping further
execution.
In
`@storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java`:
- Around line 140-190: The attach flow in ExternalPrimaryStorage currently
always calls activateHeartbeatVolumeForAttach with hostInventories.get(0), which
can pick a host whose deployClient failed and cause a late attach failure.
Update the completion path in the WhileDoneCompletion for the attach/reconnect
loop to choose a host that successfully completed deployClient and
updateHostProtocolStatus, and pass that host to
activateHeartbeatVolumeForAttach; if no host succeeded, fail the operation
instead of defaulting to the first entry.
---
Nitpick comments:
In `@plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java`:
- Line 408: The prepare-vhost-target-env failure path in ZbsStorageController is
reusing the same error code as update-host-client-dependency, so assign a
separate error code constant for the vhost environment preparation failure and
update the trigger.fail(operr(...)) call to use that new symbol instead of
ORG_ZSTACK_STORAGE_ZBS_10011.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 30bc2223-925d-47f7-9a9c-74d8726cefc7
📒 Files selected for processing (5)
plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageGlobalConfig.javatest/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostAttachDeployFailureCase.groovytest/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostVolumeCase.groovy
484fdec to
31960a4
Compare
|
Comment from jin.ma: 感谢 review,已处理 CodeRabbit 意见并重推(amend,复用 Change-Id): ✅ 已修(Major)— ✅ 已修(Nitpick)— ⏭️ 暂不改(Major)— 验证:全量 build SUCCESS; |
31960a4 to
0763c5d
Compare
|
Comment from jin.ma: 按 review 意见进一步简化了 attach 收尾逻辑(amend,复用 Change-Id):
验证:全量 build SUCCESS; |
|
Comment from gitlab: 自上次添加REVIEWED标签(2026-07-07 14:13:04.000Z)后, 有新的COMMIT更新(2026-07-07 14:16:55.366Z), 所以移除了REVIEWED标签 |
11ba6a6 to
8c9b4c5
Compare
|
Comment from gitlab: 自上次添加REVIEWED标签(2026-07-07 14:25:27.000Z)后, 有新的COMMIT更新(2026-07-08 18:36:12.186Z), 所以移除了REVIEWED标签 |
8c9b4c5 to
d060442
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java (1)
181-190: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win阈值为 1 时先判空再激活心跳卷
当attach.hostDeployFailureRatioThreshold=1且所有主机都部署失败时,deployedHosts为空,peek()会返回null,随后会把空主机传给activateHeartbeatVolume(...)。这里应在激活前显式失败,避免 attach 流程直接走到 NPE。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java` around lines 181 - 190, In ExternalPrimaryStorage’s WhileDoneCompletion.done path, add an explicit empty-check for deployedHosts before calling activateHeartbeatVolumeForAttach, since when attach.hostDeployFailureRatioThreshold is 1 and all deployments fail, deployedHosts.peek() can be null and the attach flow may pass a null host into heartbeat activation. If deployedHosts is empty, fail the provided completion immediately with a clear error instead of continuing; otherwise proceed to activateHeartbeatVolumeForAttach with the selected host.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java`:
- Around line 177-183: In ExternalPrimaryStorageFactory’s
ATTACH_HOST_DEPLOY_FAILURE_RATIO_THRESHOLD validation callback, normalize all
invalid-value failures to GlobalConfigException instead of letting
Double.parseDouble throw NumberFormatException or using
OperationFailureException for range checks. Update the installValidateExtension
lambda so both parsing and bounds validation report a consistent
GlobalConfigException with the existing config identifiers and message context,
keeping the global config update path handling validation failures uniformly.
---
Outside diff comments:
In
`@storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java`:
- Around line 181-190: In ExternalPrimaryStorage’s WhileDoneCompletion.done
path, add an explicit empty-check for deployedHosts before calling
activateHeartbeatVolumeForAttach, since when
attach.hostDeployFailureRatioThreshold is 1 and all deployments fail,
deployedHosts.peek() can be null and the attach flow may pass a null host into
heartbeat activation. If deployedHosts is empty, fail the provided completion
immediately with a clear error instead of continuing; otherwise proceed to
activateHeartbeatVolumeForAttach with the selected host.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: ddd79905-e161-4fad-b5e4-5d40915cc314
📒 Files selected for processing (7)
plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageGlobalConfig.javatest/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostAttachDeployFailureCase.groovytest/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostVolumeCase.groovyutils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java
✅ Files skipped from review due to trivial changes (1)
- utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java
🚧 Files skipped from review as they are similar to previous changes (4)
- test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostVolumeCase.groovy
- storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageGlobalConfig.java
- test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostAttachDeployFailureCase.groovy
- plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java
When attaching an external primary storage to a cluster, ZbsStorageController.deployClient swallowed vhost target deploy and prepare-env failures (only logger.warn then trigger.next), so a host was marked Connected even though vhost was not actually deployed (e.g. free hugepage: 0, docker not installed). The attach then reported success while the storage was unusable, and VM creation failed later. Make prepare-vhost-target-env and deploy-vhost-target failures fail deployClient. In ExternalPrimaryStorage.attachHook, fail the attach only when the ratio of failed hosts reaches the configurable threshold externalPrimaryStorage.attach.hostDeployFailureRatioThreshold (default 0.3); below the threshold the attach succeeds and the failed hosts are marked Disconnected and recovered by the periodic ping self-heal. Resolves: ZSTAC-86222 Change-Id: I2aee53c1f997d5a1e0c546e1329b83c1d81c9c48
d060442 to
6ef6d94
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java`:
- Around line 178-190: The validation for
ExternalPrimaryStorageGlobalConfig.ATTACH_HOST_DEPLOY_FAILURE_RATIO_THRESHOLD
currently allows threshold == 1, which conflicts with the intended open interval
(0, 1). Update the installValidateExtension logic in
ExternalPrimaryStorageFactory so the bound check rejects 1 as well (use v >= 1),
and adjust the GlobalConfigException message to say the value must be greater
than 0 and less than 1.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9793b2e7-15fc-4070-965c-80e40d727e69
📒 Files selected for processing (7)
plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.javastorage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageGlobalConfig.javatest/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostAttachDeployFailureCase.groovytest/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostVolumeCase.groovyutils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java
🚧 Files skipped from review as they are similar to previous changes (6)
- test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostVolumeCase.groovy
- utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java
- storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageGlobalConfig.java
- test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsVhostAttachDeployFailureCase.groovy
- storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java
- plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java
| ExternalPrimaryStorageGlobalConfig.ATTACH_HOST_DEPLOY_FAILURE_RATIO_THRESHOLD.installValidateExtension((category, name, oldValue, newValue) -> { | ||
| double v; | ||
| try { | ||
| v = Double.parseDouble(newValue); | ||
| } catch (NumberFormatException e) { | ||
| throw new GlobalConfigException(String.format( | ||
| "the value[%s] of %s.%s is not a valid number", newValue, category, name), e); | ||
| } | ||
| if (v <= 0 || v > 1) { | ||
| throw new GlobalConfigException(String.format( | ||
| "the value[%s] of %s.%s must be greater than 0 and not greater than 1", newValue, category, name)); | ||
| } | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
校验边界与设计意图不一致,threshold=1 会使阈值保护完全失效。
PR 目标中明确指出该配置应仅接受开区间 (0, 1) 的取值(即 0 和 1 都应被拒绝),但当前代码 v <= 0 || v > 1 允许 v == 1 通过校验。
结合 ExternalPrimaryStorage.attachHook 中的判断逻辑 if ((double) failedCount.incrementAndGet() / totalHosts > threshold):当 threshold == 1 时,failedCount / totalHosts 永远不会大于 1(因为失败数不会超过总数),导致即使所有主机部署失败,attach 也不会因阈值判断而失败——阈值保护机制被静默禁用。
建议将上边界改为 v >= 1,与设计意图(开区间)保持一致。
🐛 建议修复
- if (v <= 0 || v > 1) {
+ if (v <= 0 || v >= 1) {
throw new GlobalConfigException(String.format(
"the value[%s] of %s.%s must be greater than 0 and not greater than 1", newValue, category, name));
}(同时应同步更新错误提示文案,例如改为 "must be greater than 0 and less than 1"。)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ExternalPrimaryStorageGlobalConfig.ATTACH_HOST_DEPLOY_FAILURE_RATIO_THRESHOLD.installValidateExtension((category, name, oldValue, newValue) -> { | |
| double v; | |
| try { | |
| v = Double.parseDouble(newValue); | |
| } catch (NumberFormatException e) { | |
| throw new GlobalConfigException(String.format( | |
| "the value[%s] of %s.%s is not a valid number", newValue, category, name), e); | |
| } | |
| if (v <= 0 || v > 1) { | |
| throw new GlobalConfigException(String.format( | |
| "the value[%s] of %s.%s must be greater than 0 and not greater than 1", newValue, category, name)); | |
| } | |
| }); | |
| ExternalPrimaryStorageGlobalConfig.ATTACH_HOST_DEPLOY_FAILURE_RATIO_THRESHOLD.installValidateExtension((category, name, oldValue, newValue) -> { | |
| double v; | |
| try { | |
| v = Double.parseDouble(newValue); | |
| } catch (NumberFormatException e) { | |
| throw new GlobalConfigException(String.format( | |
| "the value[%s] of %s.%s is not a valid number", newValue, category, name), e); | |
| } | |
| if (v <= 0 || v >= 1) { | |
| throw new GlobalConfigException(String.format( | |
| "the value[%s] of %s.%s must be greater than 0 and not greater than 1", newValue, category, name)); | |
| } | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorageFactory.java`
around lines 178 - 190, The validation for
ExternalPrimaryStorageGlobalConfig.ATTACH_HOST_DEPLOY_FAILURE_RATIO_THRESHOLD
currently allows threshold == 1, which conflicts with the intended open interval
(0, 1). Update the installValidateExtension logic in
ExternalPrimaryStorageFactory so the bound check rejects 1 as well (use v >= 1),
and adjust the GlobalConfigException message to say the value must be greater
than 0 and less than 1.
问题(ZSTAC-86222)
vhost-zbs 云主机创建失败。真正根因是
AttachPrimaryStorageToCluster时 vhost target/client deploy 失败(如free hugepage: 0、docker not installed),但ZbsStorageController.deployClient把失败吞掉(只logger.warn后trigger.next()),导致 host 被标 Connected、attach 成功,而 vhost 实际没起来——后续创建 VM 才失败。修复
ZbsStorageController.deployClient:prepare-vhost-target-env 和 deploy-vhost-target 失败时改为trigger.fail(原来吞错误)。ExternalPrimaryStorage.attachHook:串行遍历累计失败数,一旦 失败 host 比例 ≥ 阈值 立即allDone提前退出并判 attach 失败;未达阈值则继续,失败 host 记 Disconnected 由 periodic ping 自愈。externalPrimaryStorage.attach.hostDeployFailureRatioThreshold(默认 0.3)。测试
ZbsVhostAttachDeployFailureCase(达阈值 fail / 未达阈值 success+自愈)。ZbsVhostVolumeCase.testProtocolRecoveryBackoff(1 host 环境,deploy 一直失败测自愈,调高阈值使 attach 不被新逻辑阻断)。关联
premium 侧
@@2同名分支补 GlobalConfig markdown 文档(GenerateGlobalConfigTemplateAndMarkDownCase)。Resolves: ZSTAC-86222
sync from gitlab !10434