Skip to content

<fix>[vm]: filter zbs for encrypted auto ps#4464

Open
zstack-robot-2 wants to merge 1 commit into
feature-zsv-5.1.0-encryptionfrom
sync/zstackio/codex/filter-zhps-encrypted-auto-ps
Open

<fix>[vm]: filter zbs for encrypted auto ps#4464
zstack-robot-2 wants to merge 1 commit into
feature-zsv-5.1.0-encryptionfrom
sync/zstackio/codex/filter-zhps-encrypted-auto-ps

Conversation

@zstack-robot-2

Copy link
Copy Markdown
Collaborator

Summary

Filter ZBS primary storage from encrypted VM disk automatic primary storage allocation.

Changes

  • Add VmAllocatePrimaryStorageExtensionPoint and centralize encrypted auto-PS filtering in EncryptedVolumePrimaryStorageAllocatorExtension.
  • Call the extension from VM creation allocation paths, including host+PS allocation, root/data allocation, other-disk instantiation, and template data volume instantiation.
  • Add a unit test for the extension entry behavior.

Testing

  • git diff --cached --check
  • cbok zsv compile --no-deploy was attempted, but the remote Docker host failed before Java compile with No space left on device.

sync from gitlab !10426

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 25 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: eeed623f-979f-43eb-bde2-6d38b454a9e7

📥 Commits

Reviewing files that changed from the base of the PR and between 0de0ff1 and 6146b1c.

⛔ Files ignored due to path filters (1)
  • conf/springConfigXml/VolumeManager.xml is excluded by !**/*.xml
📒 Files selected for processing (16)
  • compute/src/main/java/org/zstack/compute/vm/VmAllocateHostAndPrimaryStorageFlow.java
  • compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java
  • compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageForAttachingDiskFlow.java
  • compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java
  • compute/src/main/java/org/zstack/compute/vm/VmInstantiateOtherDiskFlow.java
  • header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageMsg.java
  • header/src/main/java/org/zstack/header/storage/primary/PrimaryStorageAllocationSpec.java
  • header/src/main/java/org/zstack/header/vm/VmAllocatePrimaryStorageExtensionPoint.java
  • storage/src/main/java/org/zstack/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtension.java
  • storage/src/main/java/org/zstack/storage/primary/PrimaryStorageMainAllocatorFlow.java
  • storage/src/main/java/org/zstack/storage/primary/PrimaryStorageManagerImpl.java
  • storage/src/main/java/org/zstack/storage/volume/InstantiateVolumeForNewCreatedVmExtension.java
  • storage/src/main/java/org/zstack/storage/volume/VolumeApiInterceptor.java
  • storage/src/main/java/org/zstack/storage/volume/VolumeBase.java
  • storage/src/main/java/org/zstack/storage/volume/VolumeManagerImpl.java
  • test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java

Walkthrough

新增 VmAllocatePrimaryStorageExtensionPoint 扩展点接口,接入 VmAllocateHostAndPrimaryStorageFlow 与 PrimaryStorageMainAllocatorFlow 的候选过滤链路;新增 encryptedVolumeAutoAllocation 标记字段贯穿多个消息/规格类;新增 EncryptedVolumePrimaryStorageAllocatorExtension 实现按类型剔除不支持加密卷的候选主存储,并补充单元测试。

Changes

主存储分配候选过滤扩展点

Layer / File(s) Summary
扩展点接口定义
header/.../vm/VmAllocatePrimaryStorageExtensionPoint.java
新增接口,提供针对 PrimaryStorageAllocationSpec 与 VmInstanceSpec 的 filterPrimaryStorageCandidates 默认方法。
加密卷自动分配标记字段
header/.../AllocatePrimaryStorageMsg.java, header/.../PrimaryStorageAllocationSpec.java, storage/.../PrimaryStorageManagerImpl.java
新增 encryptedVolumeAutoAllocation 字段及 getter/setter,并在构建 spec 时从消息透传该字段。
各分配流程设置加密意图
compute/.../VmAllocatePrimaryStorageFlow.java, VmAllocatePrimaryStorageForAttachingDiskFlow.java, VmInstantiateOtherDiskFlow.java
构造 AllocatePrimaryStorageSpaceMsg 时根据磁盘加密与是否已指定主存储设置该标记。
VmAllocateHostAndPrimaryStorageFlow 候选过滤
compute/.../VmAllocateHostAndPrimaryStorageFlow.java
候选查询改为完整 PrimaryStorageVO 列表,分组前调用扩展点过滤方法。
PrimaryStorageMainAllocatorFlow 候选过滤
storage/.../PrimaryStorageMainAllocatorFlow.java
注入 PluginRegistry,新增遍历扩展点过滤候选的方法并在分配流程中调用。
加密卷主存储类型过滤扩展及测试
storage/.../EncryptedVolumePrimaryStorageAllocatorExtension.java, test/.../EncryptedVolumePrimaryStorageAllocatorExtensionTest.java
新增实现类查询 expon/vhost 类型外部主存储并剔除不支持候选,附带多场景单元测试。

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Allocator as PrimaryStorageMainAllocatorFlow/VmAllocateHostAndPrimaryStorageFlow
  participant Extension as EncryptedVolumePrimaryStorageAllocatorExtension
  participant DB as ExternalPrimaryStorageVO

  Allocator->>Extension: filterPrimaryStorageCandidates(spec, candidates)
  Extension->>Extension: 判断是否需要加密卷自动过滤
  Extension->>DB: 查询 identity=expon, protocol=vhost 的主存储 UUID
  DB-->>Extension: 返回不支持的 UUID 列表
  Extension->>Extension: removeIf 剔除不支持的候选
  Extension-->>Allocator: 返回过滤后的候选列表
Loading

Poem

兔子挖洞查主存,
加密卷儿要小心,
expon 类型不适配,
过滤一遍更放心。
🐰💾✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 标题与本次变更一致,明确指向加密自动分配主存储时过滤 ZBS。
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/zstackio/codex/filter-zhps-encrypted-auto-ps

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (5)
test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java (1)

15-36: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

建议补充 filterPrimaryStorageCandidatesshouldAllocatePrimaryStorageForTemplateDataVolume 的用例。

当前仅覆盖 beforeAllocatePrimaryStorage。另外两个 override 方法涉及 DB 查询分支与短路逻辑,是本次过滤行为的核心路径,建议补充测试(可考虑 mock Q)以覆盖候选过滤与模板数据卷分配判定。

🤖 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
`@test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java`
around lines 15 - 36, Current tests only cover beforeAllocatePrimaryStorage, but
the core filtering logic also lives in filterPrimaryStorageCandidates and
shouldAllocatePrimaryStorageForTemplateDataVolume. Add test cases for these two
methods in EncryptedVolumePrimaryStorageAllocatorExtensionTest, including the
DB-query branch in filterPrimaryStorageCandidates and the short-circuit behavior
in shouldAllocatePrimaryStorageForTemplateDataVolume; use mocking for Q where
needed so both candidate filtering and template data volume allocation decisions
are verified.
compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java (1)

258-264: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

扩展点调用循环在多个 Flow 中重复。

相同的 pluginRgty.getExtensionList(VmAllocatePrimaryStorageExtensionPoint.class) 遍历回调逻辑在 VmAllocatePrimaryStorageFlowVmInstantiateOtherDiskFlowbeforeAllocatePrimaryStorage)以及 VmAllocateHostAndPrimaryStorageFlowfilterPrimaryStorageCandidates)中重复出现。可考虑参照 ZStack 既有的 *ExtensionPointEmitter 模式抽出统一的 emitter,减少重复并集中管理契约。

🤖 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
`@compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java`
around lines 258 - 264, The extension-point iteration logic for
VmAllocatePrimaryStorageExtensionPoint is duplicated across multiple flows, so
extract it into a shared emitter following the existing *ExtensionPointEmitter
pattern. Create a centralized emitter for the
pluginRgty.getExtensionList(VmAllocatePrimaryStorageExtensionPoint.class)
callback sequence and use it from
VmAllocatePrimaryStorageFlow.beforeAllocatePrimaryStorage,
VmInstantiateOtherDiskFlow.beforeAllocatePrimaryStorage, and
VmAllocateHostAndPrimaryStorageFlow.filterPrimaryStorageCandidates to keep the
contract in one place and remove repeated loops.
header/src/main/java/org/zstack/header/vm/VmAllocatePrimaryStorageExtensionPoint.java (1)

8-18: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

建议在扩展点接口上明确 spec/disk 的可空契约。

当前多个调用方会传入 null:VmInstantiateOtherDiskFlow 传入 spec=null,而 VmAllocatePrimaryStorageFlow/VmAllocateHostAndPrimaryStorageFlow 在自动分配分支可能传入 disk=nullgetRootDisk() 可能为 null)。默认实现不解引用这些参数因而安全,但后续新增的实现容易在未察觉的情况下触发 NPE。建议在 Javadoc 中说明各参数何时可能为 null,提示实现方做空值防护。

🤖 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
`@header/src/main/java/org/zstack/header/vm/VmAllocatePrimaryStorageExtensionPoint.java`
around lines 8 - 18, Clarify the nullable contract for the
VmAllocatePrimaryStorageExtensionPoint methods so implementers know that spec
and disk may be null in some call paths. Update the interface Javadoc around
beforeAllocatePrimaryStorage, filterPrimaryStorageCandidates, and
shouldAllocatePrimaryStorageForTemplateDataVolume to state when VmInstanceSpec
or DiskAO can be absent, referencing the extension point methods directly so
future implementations add null checks and avoid NPEs.
storage/src/main/java/org/zstack/storage/volume/InstantiateVolumeForNewCreatedVmExtension.java (2)

307-315: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

可用 Stream anyMatch 替代显式循环。

该判断逻辑适合用 Stream 表达。As per coding guidelines:“使用 Java Stream 或 Lambda 表达式代替冗长的循环与条件判断”。

♻️ 建议的写法
-    private boolean shouldAllocatePrimaryStorageForTemplateDataVolume(VmInstanceSpec spec, DiskAO diskAO, String defaultPsUuid) {
-        for (VmAllocatePrimaryStorageExtensionPoint ext :
-                pluginRgty.getExtensionList(VmAllocatePrimaryStorageExtensionPoint.class)) {
-            if (ext.shouldAllocatePrimaryStorageForTemplateDataVolume(spec, diskAO, defaultPsUuid)) {
-                return true;
-            }
-        }
-        return false;
-    }
+    private boolean shouldAllocatePrimaryStorageForTemplateDataVolume(VmInstanceSpec spec, DiskAO diskAO, String defaultPsUuid) {
+        return pluginRgty.getExtensionList(VmAllocatePrimaryStorageExtensionPoint.class).stream()
+                .anyMatch(ext -> ext.shouldAllocatePrimaryStorageForTemplateDataVolume(spec, diskAO, defaultPsUuid));
+    }
🤖 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/volume/InstantiateVolumeForNewCreatedVmExtension.java`
around lines 307 - 315, Replace the explicit loop in
shouldAllocatePrimaryStorageForTemplateDataVolume with a Stream anyMatch chain
over pluginRgty.getExtensionList(VmAllocatePrimaryStorageExtensionPoint.class),
using the same predicate
ext.shouldAllocatePrimaryStorageForTemplateDataVolume(spec, diskAO,
defaultPsUuid) to preserve behavior while following the Stream/Lambda guideline.

Source: Path instructions


276-278: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

建议简化嵌套三元表达式以提升可读性。

psUuid 使用了嵌套三元,语义不直观。可改用早返回或普通条件赋值表达清楚意图。As per coding guidelines:“if 条件表达不宜过长或过于复杂,必要时可以将条件抽成 boolean 变量描述”,并尽量减少难以阅读的分支结构。

♻️ 建议的写法
-                boolean allocatePrimaryStorage = shouldAllocatePrimaryStorageForTemplateDataVolume(spec, diskAO, defaultPsUuid);
-                String psUuid = diskAO.getPrimaryStorageUuid() != null ? diskAO.getPrimaryStorageUuid() :
-                        allocatePrimaryStorage ? null : defaultPsUuid;
+                boolean allocatePrimaryStorage = shouldAllocatePrimaryStorageForTemplateDataVolume(spec, diskAO, defaultPsUuid);
+                String psUuid;
+                if (diskAO.getPrimaryStorageUuid() != null) {
+                    psUuid = diskAO.getPrimaryStorageUuid();
+                } else {
+                    psUuid = allocatePrimaryStorage ? null : defaultPsUuid;
+                }
🤖 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/volume/InstantiateVolumeForNewCreatedVmExtension.java`
around lines 276 - 278, The psUuid assignment in
InstantiateVolumeForNewCreatedVmExtension uses a nested ternary that is hard to
read; replace it with clearer conditional logic, such as an explicit if/else or
early-return style, while preserving the same behavior based on
diskAO.getPrimaryStorageUuid(), allocatePrimaryStorage, and defaultPsUuid. Keep
the boolean from shouldAllocatePrimaryStorageForTemplateDataVolume() as the
descriptive condition and use it to make the storage selection flow obvious.

Source: Path instructions

🤖 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.

Nitpick comments:
In
`@compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java`:
- Around line 258-264: The extension-point iteration logic for
VmAllocatePrimaryStorageExtensionPoint is duplicated across multiple flows, so
extract it into a shared emitter following the existing *ExtensionPointEmitter
pattern. Create a centralized emitter for the
pluginRgty.getExtensionList(VmAllocatePrimaryStorageExtensionPoint.class)
callback sequence and use it from
VmAllocatePrimaryStorageFlow.beforeAllocatePrimaryStorage,
VmInstantiateOtherDiskFlow.beforeAllocatePrimaryStorage, and
VmAllocateHostAndPrimaryStorageFlow.filterPrimaryStorageCandidates to keep the
contract in one place and remove repeated loops.

In
`@header/src/main/java/org/zstack/header/vm/VmAllocatePrimaryStorageExtensionPoint.java`:
- Around line 8-18: Clarify the nullable contract for the
VmAllocatePrimaryStorageExtensionPoint methods so implementers know that spec
and disk may be null in some call paths. Update the interface Javadoc around
beforeAllocatePrimaryStorage, filterPrimaryStorageCandidates, and
shouldAllocatePrimaryStorageForTemplateDataVolume to state when VmInstanceSpec
or DiskAO can be absent, referencing the extension point methods directly so
future implementations add null checks and avoid NPEs.

In
`@storage/src/main/java/org/zstack/storage/volume/InstantiateVolumeForNewCreatedVmExtension.java`:
- Around line 307-315: Replace the explicit loop in
shouldAllocatePrimaryStorageForTemplateDataVolume with a Stream anyMatch chain
over pluginRgty.getExtensionList(VmAllocatePrimaryStorageExtensionPoint.class),
using the same predicate
ext.shouldAllocatePrimaryStorageForTemplateDataVolume(spec, diskAO,
defaultPsUuid) to preserve behavior while following the Stream/Lambda guideline.
- Around line 276-278: The psUuid assignment in
InstantiateVolumeForNewCreatedVmExtension uses a nested ternary that is hard to
read; replace it with clearer conditional logic, such as an explicit if/else or
early-return style, while preserving the same behavior based on
diskAO.getPrimaryStorageUuid(), allocatePrimaryStorage, and defaultPsUuid. Keep
the boolean from shouldAllocatePrimaryStorageForTemplateDataVolume() as the
descriptive condition and use it to make the storage selection flow obvious.

In
`@test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java`:
- Around line 15-36: Current tests only cover beforeAllocatePrimaryStorage, but
the core filtering logic also lives in filterPrimaryStorageCandidates and
shouldAllocatePrimaryStorageForTemplateDataVolume. Add test cases for these two
methods in EncryptedVolumePrimaryStorageAllocatorExtensionTest, including the
DB-query branch in filterPrimaryStorageCandidates and the short-circuit behavior
in shouldAllocatePrimaryStorageForTemplateDataVolume; use mocking for Q where
needed so both candidate filtering and template data volume allocation decisions
are verified.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ecc85355-2f22-4d1d-8987-4cf43115be05

📥 Commits

Reviewing files that changed from the base of the PR and between 45e799e and cb00422.

⛔ Files ignored due to path filters (1)
  • conf/springConfigXml/VolumeManager.xml is excluded by !**/*.xml
📒 Files selected for processing (7)
  • compute/src/main/java/org/zstack/compute/vm/VmAllocateHostAndPrimaryStorageFlow.java
  • compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java
  • compute/src/main/java/org/zstack/compute/vm/VmInstantiateOtherDiskFlow.java
  • header/src/main/java/org/zstack/header/vm/VmAllocatePrimaryStorageExtensionPoint.java
  • storage/src/main/java/org/zstack/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtension.java
  • storage/src/main/java/org/zstack/storage/volume/InstantiateVolumeForNewCreatedVmExtension.java
  • test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java

@MatheMatrix MatheMatrix force-pushed the sync/zstackio/codex/filter-zhps-encrypted-auto-ps branch 7 times, most recently from 29fed71 to 478e59b Compare July 7, 2026 14:00
@MatheMatrix

Copy link
Copy Markdown
Owner

Comment from yaohua.wu:

Review: MR !10426 — ZSV-12607

Background (preserved across rounds)

  • Jira: ZSV-12607 — 【硬盘加密】硬盘使用数据存储未zhps时 禁止开启硬盘加密
  • Bug summary: ZHPS 后端不支持加密硬盘,Jira 评论要求创建 VM / 新增硬盘时,硬盘存储位置为“自动选择”且开启加密时不能调度到 ZHPS;同时提到迁移更改数据存储、主机+数据存储时也不能选择 ZHPS。
  • Intent & scope: 本 MR 新增 encryptedVolumeAutoAllocation 标志,将其从 VM 磁盘自动分配路径传到 primary storage allocator,并通过 EncryptedVolumePrimaryStorageAllocatorExtension 过滤 identity=expon、protocol=Vhost 的 ZHPS 候选。
  • Round 1 initial findings: 2 × Critical,集中在模板数据盘创建与挂载未实例化加密云盘的自动主存储分配路径。
  • Suggested fix direction: 把“加密 + 自动选择主存储”的语义贯穿所有会创建 AllocatePrimaryStorage(Space)Msg 的入口,并对显式指定 ZHPS 的加密硬盘做后端拒绝或共享校验。

🔴 Critical

# File:Line Issue Fix Reviewer(s) Conf Route
1 storage/src/main/java/org/zstack/storage/volume/InstantiateVolumeForNewCreatedVmExtension.java:248; storage/src/main/java/org/zstack/storage/volume/VolumeManagerImpl.java:350 模板数据盘路径仍会绕过新过滤。InstantiateVolumeForNewCreatedVmExtension 在加密数据盘未指定 PS 时直接落到 defaultPsUuid,随后 VolumeManagerImplsetRequiredPrimaryStorageUuid(msg.getPrimaryStorageUuid()) 分配;若默认 PS 是 ZHPS,allocator 扩展没有机会过滤。独立 CreateDataVolumeFromVolumeTemplateMsg encrypted=true 且未指定 PS 时也没有设置 encryptedVolumeAutoAllocation Boolean.TRUE.equals(diskAO.getEncrypted()) && diskAO.getPrimaryStorageUuid() == null 的模板数据盘不要直接继承 defaultPsUuid;先用带 setEncryptedVolumeAutoAllocation(true) 的 dry-run/allocate 选择非 ZHPS,或在 CreateDataVolumeFromVolumeTemplateMsgAllocatePrimaryStorageSpaceMsg 的链路中传递该标志。同时对加密场景显式指定 ZHPS 的请求 fail-fast。补充覆盖“root 未加密但 template data disk 加密且自动选择”的测试。 correctness, robustness 0.91 gated_auto → downstream-resolver
2 compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageForAttachingDiskFlow.java:53 挂载一个尚未实例化的加密云盘时仍可能自动分配到 ZHPS。该 flow 为 attach 路径创建 AllocatePrimaryStorageSpaceMsg,但没有根据 volume.getEncrypted() 设置本 MR 新增的标志,因此 PrimaryStorageAllocationSpec.isEncryptedVolumeAutoAllocation() 为 false,新增过滤扩展不会执行。 在该 flow 中设置 amsg.setEncryptedVolumeAutoAllocation(Boolean.TRUE.equals(volume.getEncrypted()) && volume.getPrimaryStorageUuid() == null),并增加“先创建 encrypted data volume、不指定 PS、再 attach 到 VM”时不会选择 ZHPS 的回归测试。 correctness, adversarial 0.88 gated_auto → downstream-resolver

🟡 Warning

# File:Line Issue Fix Reviewer(s) Conf Route
- - 未发现通过质量门槛的 Warning。 - - - -

🟢 Suggestion

# File:Line Issue Fix Reviewer(s) Conf Route
- - 未发现需要发布的 Suggestion。 - - - -

Coverage

  • Diff source: local git diff authoritative;MCP 与本地文件数一致,kept 10 / total 10,generated-file filter skipped 0。
  • Upstream freshness: target 分支在 merge-base 后新增 2 个 Ceph 相关提交,未改动本 MR 同文件;MR merge_status=can_be_merged
  • Verification: git diff --check 45e799eca5f9ee49ee064ba01dce35d613bff549..478e59b8e0b703de5b52ba797d03c29443206255 passed。未运行完整编译或集成测试。
  • Testing gaps: 当前新增单测只验证 extension 自身过滤,未覆盖模板数据盘、attach 未实例化加密盘、以及显式 ZHPS + encrypted 的端到端入口。
  • Residual risks: Jira 还要求迁移更改数据存储/主机+数据存储、以及前端候选项隐藏;本 MR diff 未覆盖这些入口。若已有其它 MR 负责,需要在描述中拆分 scope;否则该 Jira 不能仅靠本 MR close。

Verdict: REVISION_REQUIRED

2 条 Critical 都是修复不完整路径,可能让 encrypted=true + 自动选择主存储 继续落到 ZHPS。


🤖 Robot Reviewer

@ZStack-Robot

Copy link
Copy Markdown
Collaborator

Comment from 周众:

已修复:attach 未实例化加密盘补充 encryptedVolumeAutoAllocation;模板数据盘加密且自动选择时不再继承 defaultPsUuid,改为先通过 allocator dry-run 选择非 ZHPS,再继续原创建流程。过滤逻辑仍集中在 PrimaryStorageMainAllocatorFlow 的 filterPrimaryStorageCandidates 扩展点。

@MatheMatrix MatheMatrix force-pushed the sync/zstackio/codex/filter-zhps-encrypted-auto-ps branch 5 times, most recently from 2baeca6 to 0de0ff1 Compare July 8, 2026 05:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java (1)

149-149: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

加密自动分配判断逻辑在多个文件中重复。

Boolean.TRUE.equals(x.getEncrypted()) && x.getPrimaryStorageUuid() == null 这一表达式在本文件(根卷/数据卷)、VmAllocatePrimaryStorageForAttachingDiskFlowVmInstantiateOtherDiskFlow(两处)共出现 5 次。本 PR 的迭代历史本身就说明了这种重复的风险——review 过程中曾遗漏了附加磁盘与模板数据卷两处,需要额外补丁修复。建议抽取为统一的静态工具方法(例如 EncryptedVolumeAllocationUtils.isEncryptedAutoAllocation(Boolean encrypted, String primaryStorageUuid)),避免未来新增分配入口再次遗漏。

♻️ 建议的重构方向
+public class EncryptedVolumeAllocationUtils {
+    public static boolean isEncryptedAutoAllocation(Boolean encrypted, String primaryStorageUuid) {
+        return Boolean.TRUE.equals(encrypted) && primaryStorageUuid == null;
+    }
+}
-            rmsg.setEncryptedVolumeAutoAllocation(disk != null && Boolean.TRUE.equals(disk.getEncrypted()));
+            rmsg.setEncryptedVolumeAutoAllocation(disk != null
+                    && EncryptedVolumeAllocationUtils.isEncryptedAutoAllocation(disk.getEncrypted(), disk.getPrimaryStorageUuid()));

As per path instructions(## 6. 设计原则和模块划分 中的"单一职责原则"),应避免重复逻辑分散在多处、造成后续维护和一致性风险。

Also applies to: 184-186

🤖 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
`@compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java`
at line 149, The encrypted auto-allocation check is duplicated across multiple
VM primary-storage flows, so refactor it into one shared helper and reuse it
everywhere. Extract the repeated Boolean.TRUE.equals(encrypted) &&
primaryStorageUuid == null logic into a static utility such as
EncryptedVolumeAllocationUtils.isEncryptedAutoAllocation, then update
VmAllocatePrimaryStorageFlow, VmAllocatePrimaryStorageForAttachingDiskFlow, and
VmInstantiateOtherDiskFlow to call that helper instead of inlining the
condition. Keep the existing behavior identical while centralizing the rule to
prevent future misses in new allocation paths.

Source: Path instructions

test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java (1)

16-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

缺少"加密根卷 + 自动分配主存储"场景的用例。

现有 4 个测试仅覆盖了 PrimaryStorageAllocationSpec 直接标记及 VmInstanceSpec 中非根盘(DiskAO.nonRootDisk() + 模板盘)两类场景,EncryptedVolumePrimaryStorageAllocatorExtension.isEncryptedAutoAllocatedRootVolume(根卷加密且 getCandidatePrimaryStorageUuidsForRootVolume() 为空)这条分支未被任何用例触发。考虑到根卷是加密自动分配最常见的入口之一,建议补充一个设置 spec.getRootDisk() 为加密盘、且未指定候选主存储的用例,以覆盖该分支并验证 getCandidatePrimaryStorageUuidsForRootVolume() 默认值的空安全性。

✅ 建议补充的测试用例示例
`@Test`
public void testFilterZhpsForEncryptedRootDiskWithAutoPrimaryStorage() {
    VmInstanceSpec spec = new VmInstanceSpec();
    DiskAO rootDisk = DiskAO.rootDisk(); // 视实际工厂方法调整
    rootDisk.setEncrypted(true);
    spec.setRootDisk(rootDisk);
    List<PrimaryStorageVO> candidates = new ArrayList<>(Arrays.asList(primaryStorage("normal-ps-uuid"), primaryStorage(ZHPS_PS_UUID)));

    extension.filterPrimaryStorageCandidates(spec, candidates);

    Assert.assertEquals(1, candidates.size());
    Assert.assertEquals("normal-ps-uuid", candidates.get(0).getUuid());
}
🤖 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
`@test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java`
around lines 16 - 92, Add a test for the missing “encrypted root volume + auto
primary storage” path in EncryptedVolumePrimaryStorageAllocatorExtensionTest.
Introduce a case using VmInstanceSpec with an encrypted root disk via
DiskAO.rootDisk() (or the equivalent root-disk factory in this test) and no
explicit candidate primary storage, then call filterPrimaryStorageCandidates and
assert ZHPS_PS_UUID is filtered out. This should directly exercise
EncryptedVolumePrimaryStorageAllocatorExtension.isEncryptedAutoAllocatedRootVolume
and verify getCandidatePrimaryStorageUuidsForRootVolume() is safely handled when
unset.
🤖 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/encrypt/EncryptedVolumePrimaryStorageAllocatorExtension.java`:
- Around line 56-65: `hasEncryptedAutoAllocatedVolume(VmInstanceSpec)` is using
the VM-wide `candidatePrimaryStorageUuidsForDataVolume` field inside a per-disk
check, which can incorrectly skip ZBS filtering in multi-disk cases. Refactor
the logic in `hasEncryptedAutoAllocatedVolume` so each deprecated disk is
evaluated independently: keep checking `isEncrypted(disk)` and
`disk.getPrimaryStorageUuid() == null`, but move the candidate-primary-storage
condition to disk-specific handling instead of relying on
`spec.getCandidatePrimaryStorageUuidsForDataVolume()` globally. Ensure the
helper still correctly detects auto-allocated encrypted root volumes via
`isEncryptedAutoAllocatedRootVolume` and only lets disks through when that
specific disk’s primary-storage selection warrants it.

---

Nitpick comments:
In
`@compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java`:
- Line 149: The encrypted auto-allocation check is duplicated across multiple VM
primary-storage flows, so refactor it into one shared helper and reuse it
everywhere. Extract the repeated Boolean.TRUE.equals(encrypted) &&
primaryStorageUuid == null logic into a static utility such as
EncryptedVolumeAllocationUtils.isEncryptedAutoAllocation, then update
VmAllocatePrimaryStorageFlow, VmAllocatePrimaryStorageForAttachingDiskFlow, and
VmInstantiateOtherDiskFlow to call that helper instead of inlining the
condition. Keep the existing behavior identical while centralizing the rule to
prevent future misses in new allocation paths.

In
`@test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java`:
- Around line 16-92: Add a test for the missing “encrypted root volume + auto
primary storage” path in EncryptedVolumePrimaryStorageAllocatorExtensionTest.
Introduce a case using VmInstanceSpec with an encrypted root disk via
DiskAO.rootDisk() (or the equivalent root-disk factory in this test) and no
explicit candidate primary storage, then call filterPrimaryStorageCandidates and
assert ZHPS_PS_UUID is filtered out. This should directly exercise
EncryptedVolumePrimaryStorageAllocatorExtension.isEncryptedAutoAllocatedRootVolume
and verify getCandidatePrimaryStorageUuidsForRootVolume() is safely handled when
unset.
🪄 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: 052ff466-0332-4f2a-b612-3063562652a8

📥 Commits

Reviewing files that changed from the base of the PR and between cb00422 and 0de0ff1.

⛔ Files ignored due to path filters (1)
  • conf/springConfigXml/VolumeManager.xml is excluded by !**/*.xml
📒 Files selected for processing (11)
  • compute/src/main/java/org/zstack/compute/vm/VmAllocateHostAndPrimaryStorageFlow.java
  • compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java
  • compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageForAttachingDiskFlow.java
  • compute/src/main/java/org/zstack/compute/vm/VmInstantiateOtherDiskFlow.java
  • header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageMsg.java
  • header/src/main/java/org/zstack/header/storage/primary/PrimaryStorageAllocationSpec.java
  • header/src/main/java/org/zstack/header/vm/VmAllocatePrimaryStorageExtensionPoint.java
  • storage/src/main/java/org/zstack/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtension.java
  • storage/src/main/java/org/zstack/storage/primary/PrimaryStorageMainAllocatorFlow.java
  • storage/src/main/java/org/zstack/storage/primary/PrimaryStorageManagerImpl.java
  • test/src/test/java/org/zstack/test/unittest/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtensionTest.java

@MatheMatrix MatheMatrix force-pushed the sync/zstackio/codex/filter-zhps-encrypted-auto-ps branch 2 times, most recently from dd70533 to 0af5fe5 Compare July 8, 2026 05:57
@MatheMatrix

Copy link
Copy Markdown
Owner

Comment from yaohua.wu:

Review: MR !10426 — ZSV-12607

Background

  • Jira: ZSV-12607 — 【硬盘加密】硬盘使用数据存储未zhps时 禁止开启硬盘加密
  • Bug summary: Jira 要求开启硬盘加密时不能把相关硬盘调度到 ZHPS,并特别提到创建/新增硬盘自动选择、迁移 VM 更改数据存储、迁移 VM 更改主机与数据存储等入口。
  • Intent & scope: 本 MR 通过 VmAllocatePrimaryStorageExtensionPointencryptedVolumeAutoAllocation 标记,在 VM 创建、attach、other disk/template disk 的自动主存储分配路径中过滤 ZHPS。
  • Round 1 initial findings: 1 × Critical,集中在 VM host+primary-storage 联合分配时 root/data 候选池被全局过滤的问题。
  • Suggested fix direction: 把 ZHPS 过滤从 VM 级全局候选池改成按卷角色/按卷粒度过滤,避免加密数据盘的自动分配约束误伤非加密根盘或显式选择的其他卷。

🔴 Critical

# File:Line Issue Fix Conf
1 storage/src/main/java/org/zstack/storage/encrypt/EncryptedVolumePrimaryStorageAllocatorExtension.java:40 hasEncryptedAutoAllocatedVolume(spec) 只要发现任一加密盘需要自动分配,就在 filterPrimaryStorageCandidates(VmInstanceSpec...) 里把 ZHPS 从 available/local/nonLocal 三个 VM 级共享列表全部删除。随后 VmAllocateHostAndPrimaryStorageFlow 会用这个已过滤的 availablePsUuids 校验 root/data 的显式候选,并用同一批 local/nonLocal 生成 root/data 组合。因此“非加密 root 显式在 ZHPS + 加密 data 自动分配到普通 PS”这类可达组合会被错误拒绝:root 候选 ZHPS 在进入组合前已经被删掉,但只有加密数据盘才需要避开 ZHPS。 不要在 VM 级共享列表上一次性删除 ZHPS。将过滤改为按角色/按卷粒度:先区分 rootNeedsEncryptedAutoPsFilterdataNeedsEncryptedAutoPsFilter,再分别过滤 root 候选池和 data 候选池;或者调整扩展点签名,让调用方传入 root/data 两套候选列表。补一个用例覆盖:root 非加密且指定 ZHPS、data 加密且自动分配时,仍能生成 root=ZHPS, data=non-ZHPS 的组合;同时保留加密 root 自动分配时过滤 ZHPS 的用例。 0.91

Coverage

  • 本地 diff 与 MCP diff 交叉校验:12/12 个文件一致,未发现空 diff;generated-file filter 跳过 0 个文件。
  • Upstream freshness:feature-zsv-5.1.0-encryption 相对源分支无新增未合入提交,MR 状态 can_be_merged
  • Verification:已跑 git diff --check,无输出。
  • Residual risk:Jira 还提到前端候选列表/迁移入口禁止选择 ZHPS;当前后端候选查询 API 没有加密开关参数,本轮未把它作为当前 Java diff 的确定性 finding。

Verdict: REVISION_REQUIRED

当前实现会在混合 root/data 场景中过度过滤 ZHPS,导致合法的非加密卷放置被拒绝,需要按卷粒度修正后再合入。


🤖 Robot Reviewer

@MatheMatrix MatheMatrix force-pushed the sync/zstackio/codex/filter-zhps-encrypted-auto-ps branch 10 times, most recently from 2a98582 to 62968b9 Compare July 8, 2026 08:42
Filter zhps in the allocator extension point.

Only applies to encrypted auto primary storage allocation.

Test: git diff --check

Test: cbok zsv compile --no-deploy passed

Resolves: ZSV-12607

Change-Id: If4078641c7a42c67552373fcc9d7581cf4f97b1a
@MatheMatrix MatheMatrix force-pushed the sync/zstackio/codex/filter-zhps-encrypted-auto-ps branch from 62968b9 to 6146b1c Compare July 8, 2026 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants