Skip to content

<fix>[storage]: ZSTAC-86038 support typed storage resource stats#4548

Open
zstack-robot-2 wants to merge 1 commit into
5.5.28from
sync/jin.ma/fix/ZSTAC-86038-storage-resource-stats
Open

<fix>[storage]: ZSTAC-86038 support typed storage resource stats#4548
zstack-robot-2 wants to merge 1 commit into
5.5.28from
sync/jin.ma/fix/ZSTAC-86038-storage-resource-stats

Conversation

@zstack-robot-2

Copy link
Copy Markdown
Collaborator

问题

外部主存储的 stats 只能返回 VolumeStats,无法同时表达卷和快照,导致镜像缓存快照缺失时不能通过已有 stats 逻辑正确识别并重建。

修改

  • 直接复用 stats,返回抽象 StorageResource
  • VolumeStatsVolumeSnapshotStats 作为子类,共享 installPath/size/actualSize/parentUri
  • XInfini、Expon、ZBS 根据资源路径返回卷或快照 stats
  • 外部主存储调用不增加 try/catch,由 AsyncSafeAspect 处理 completion 异常
  • 保留 batchStats 的卷批量查询契约
  • 不包含假 case 或 testlib 模拟器改动

验证

  • mvn -Dmaven.test.skip=true clean install:56/56 modules success
  • XinfiniPrimaryStorageCase:1 passed, 0 failed/error/skipped
  • ZbsPrimaryStorageCase:1 passed, 0 failed/error/skipped
  • 已安装 JAR 字节码确认 stats 返回 StorageResource,AJ weaving 生效

Jira: http://jira.zstack.io/browse/ZSTAC-86038

sync from gitlab !10512

@coderabbitai

coderabbitai Bot commented Jul 12, 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: 46 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: 4f338686-56e6-4882-92df-7bcc36389714

📥 Commits

Reviewing files that changed from the base of the PR and between d5c3054 and b808517.

📒 Files selected for processing (11)
  • header/src/main/java/org/zstack/header/storage/addon/StorageResource.java
  • header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java
  • header/src/main/java/org/zstack/header/storage/snapshot/VolumeSnapshotStats.java
  • header/src/main/java/org/zstack/header/volume/VolumeStats.java
  • plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java
  • plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniApiHelper.java
  • plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java
  • plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java
  • storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java
  • test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/xinfini/XinfiniPrimaryStorageCase.groovy
  • test/src/test/groovy/org/zstack/test/unittest/storage/StorageResourceContractTest.groovy

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Could not fetch remote config from http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml: TimeoutError: The operation was aborted due to timeout
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

新增 StorageResource 统一卷与快照统计字段,控制器按安装路径返回不同资源类型;主存储消费方、缓存校验、错误处理和 XInfini 集成测试同步迁移。

Changes

存储资源统计统一化

Layer / File(s) Summary
资源统计契约
header/src/main/java/org/zstack/header/storage/addon/StorageResource.java, header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java, header/src/main/java/org/zstack/header/storage/snapshot/VolumeSnapshotStats.java, header/src/main/java/org/zstack/header/volume/VolumeStats.java
新增 StorageResource 基类,卷和快照统计类继承该基类,服务接口将统计结果改为 StorageResource
卷与快照统计实现
plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java, plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java, plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java
控制器根据安装路径区分卷和快照,并返回 VolumeStatsVolumeSnapshotStats
主存储资源消费与错误处理
storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java, plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniApiHelper.java
主存储使用统一资源统计读取实际大小和父链信息;缓存复用前增加统计校验,并处理资源不存在错误。
卷快照统计集成验证
test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/xinfini/XinfiniPrimaryStorageCase.groovy
新增卷与快照统计查询及断言,验证返回类型、安装路径和大小字段。

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TestCase
  participant PrimaryStorageControllerSvc
  participant XInfiniStorageController
  participant StorageResource
  TestCase->>PrimaryStorageControllerSvc: 查询卷或快照 stats
  PrimaryStorageControllerSvc->>XInfiniStorageController: 转发 installPath
  XInfiniStorageController->>XInfiniStorageController: 判断卷路径或快照路径
  XInfiniStorageController->>StorageResource: 创建对应统计对象
  XInfiniStorageController-->>TestCase: 返回 StorageResource
  TestCase->>TestCase: 校验类型、路径和大小
Loading

Poem

我是小兔,抱来资源新篮,
卷与快照,都有统一名牌。
路径一分,统计便分流,
失效缓存,轻轻清走。
测试萝卜,咔嚓咔嚓全通过!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确概括了将存储资源统计泛化为类型化 StorageResource 的主要改动。
Description check ✅ Passed 描述与变更一致,说明了 stats 泛化、子类复用及相关存储控制器调整。
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/jin.ma/fix/ZSTAC-86038-storage-resource-stats

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.

Actionable comments posted: 4

🧹 Nitpick comments (1)
plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java (1)

1149-1172: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚖️ Poor tradeoff

补齐 Expon 统计结果的 parentUriplugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java:1149-1172 的卷/快照统计分支都没有可回填祖先链的字段,而 VolumeModule/VolumeSnapshotModule 也没有等价于 bsSnapId/bsVolumeId 的引用;如果上层会走通用父链解析,这里会断链。可补一个父资源标识,或明确声明 Expon 不支持祖先链。

🤖 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/expon/src/main/java/org/zstack/expon/ExponStorageController.java`
around lines 1149 - 1172, 补齐 Expon 的统计结果父资源信息:更新 ExponStorageController.stats 及其
getVolumeStats 分支,为卷和快照统计结果设置可供通用父链解析的 parentUri 或等价父资源标识;若 Expon 的 VolumeModule
和 VolumeSnapshotModule 无法提供该标识,则在相关统计结果处理路径中明确声明不支持祖先链,避免返回看似可解析但实际断链的数据。
🤖 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 `@header/src/main/java/org/zstack/header/storage/addon/StorageResource.java`:
- Around line 4-44: 更新 VolumeStats.getActualSize(),在 actualSize 未设置时返回
0L,保留已设置值的返回行为,使 ExternalPrimaryStorage 中的 Collectors.toMap 能安全处理所有
VolumeStats;可参考 VolumeSnapshotStats 的空值兜底方式。

In
`@plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java`:
- Around line 854-868: Update the snapshot branch of
XInfiniStorageController.stats so parentUri points directly to the backing
volume identified by snapshot.getSpec().getBsVolumeId(), rather than passing
that volume through getParentUri. Preserve the existing size and installPath
handling.

In
`@storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java`:
- Around line 1432-1436: 修正 ExternalPrimaryStorage 中该 completion.fail 的 operr
调用,补上本模块现有的全局错误码常量作为首个参数,并保持后续提示文本及 imageUuid、primaryStorageUuid
参数顺序不变,确保错误码和格式化信息正确对应。
- Around line 1402-1454: 统一 ExternalPrimaryStorage 中 statsCompletion.fail
的资源缺失判断,不要只匹配 SysErrors.RESOURCE_NOT_FOUND;让 ZbsStorageController.httpCall 和
ExponStorageController.stats/errorOut 将底层资源不存在统一归类为可触发缓存删除重建的错误,同时保留瞬时失败直接返回给
completion 的处理。

---

Nitpick comments:
In `@plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java`:
- Around line 1149-1172: 补齐 Expon 的统计结果父资源信息:更新 ExponStorageController.stats 及其
getVolumeStats 分支,为卷和快照统计结果设置可供通用父链解析的 parentUri 或等价父资源标识;若 Expon 的 VolumeModule
和 VolumeSnapshotModule 无法提供该标识,则在相关统计结果处理路径中明确声明不支持祖先链,避免返回看似可解析但实际断链的数据。
🪄 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: 92a82b00-c5f9-4f41-8382-38198fb667af

📥 Commits

Reviewing files that changed from the base of the PR and between 6e0a2ea and d5c3054.

📒 Files selected for processing (10)
  • header/src/main/java/org/zstack/header/storage/addon/StorageResource.java
  • header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java
  • header/src/main/java/org/zstack/header/storage/snapshot/VolumeSnapshotStats.java
  • header/src/main/java/org/zstack/header/volume/VolumeStats.java
  • plugin/expon/src/main/java/org/zstack/expon/ExponStorageController.java
  • plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniApiHelper.java
  • plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java
  • plugin/zbs/src/main/java/org/zstack/storage/zbs/ZbsStorageController.java
  • storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java
  • test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/xinfini/XinfiniPrimaryStorageCase.groovy

Comment on lines +854 to +868
public void stats(String installPath, ReturnValueCompletion<StorageResource> comp) {
if (installPath.contains("@")) {
VolumeSnapshotModule snapshot = apiHelper.getVolumeSnapshot(getSnapIdFromPath(installPath));
VolumeSnapshotStats stats = new VolumeSnapshotStats();
long size = SizeUnit.MEGABYTE.toByte(snapshot.getSpec().getSizeMb());
stats.setInstallPath(installPath);
stats.setSize(size);
stats.setActualSize(size);
stats.setParentUri(getParentUri(apiHelper.getVolume(snapshot.getSpec().getBsVolumeId())));
comp.success(stats);
return;
}

comp.success(getVolumeStats(installPath));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n 'class VolumeSnapshotModule|class VolumeSnapshotSpec' plugin/xinfini/src/main/java/org/zstack/xinfini
rg -n 'getDataSize|getAllocatedSize|DataSize' plugin/xinfini/src/main/java/org/zstack/xinfini

Repository: MatheMatrix/zstack

Length of output: 1490


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant methods and surrounding context
sed -n '840,900p' plugin/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java

echo '--- getParentUri / buildXInfiniPath / getParentChain ---'
rg -n 'getParentUri\\(|buildXInfiniPath\\(|getParentChain\\(' plugin/xinfini/src/main/java/org/zstack/xinfini -A 12 -B 6

echo '--- VolumeSnapshotModule / VolumeSnapshotSpec ---'
sed -n '1,180p' plugin/xinfini/src/main/java/org/zstack/xinfini/sdk/volume/VolumeSnapshotModule.java

Repository: MatheMatrix/zstack

Length of output: 3134


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n 'buildXInfiniSnapshotPath|getParentChain|parentUri' plugin/xinfini/src/main/java/org/zstack/xinfini -A 6 -B 6

echo '--- VolumeSnapshotStats definition ---'
sed -n '1,220p' plugin/xinfini/src/main/java/org/zstack/xinfini/sdk/volume/VolumeSnapshotStats.java

Repository: MatheMatrix/zstack

Length of output: 5606


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find every consumer of parentUri and the stats classes involved.
rg -n 'getParentUri\\(|setParentUri\\(|parentUri' plugin/xinfini/src/main/java -A 4 -B 4

echo '--- stats interfaces / models ---'
rg -n 'class .*Stats|interface .*Stats|extends .*Stats|implements .*Stats' plugin/xinfini/src/main/java/org/zstack/xinfini -A 3 -B 3

Repository: MatheMatrix/zstack

Length of output: 279


快照统计的 parentUri 需要直接指向 backing volume
stats() 这里把 snapshot.getSpec().getBsVolumeId() 对应的 volume 再传给 getParentUri(),拿到的是该 volume 的父快照路径,结果会跳过当前快照的直接父节点。这里应改为返回 backing volume 自身的路径。

🤖 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/xinfini/src/main/java/org/zstack/xinfini/XInfiniStorageController.java`
around lines 854 - 868, Update the snapshot branch of
XInfiniStorageController.stats so parentUri points directly to the backing
volume identified by snapshot.getSpec().getBsVolumeId(), rather than passing
that volume through getParentUri. Preserve the existing size and installPath
handling.

Comment on lines +1432 to +1436
if (cache.getInstallUrl().startsWith(ImageConstant.SNAPSHOT_REUSE_IMAGE_SCHEMA)) {
completion.fail(operr("image cache[imageUuid:%s, primaryStorageUuid:%s] refers to a missing reused volume snapshot",
cache.getImageUuid(), cache.getPrimaryStorageUuid()));
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n 'public static ErrorCode operr' core/src/main/java/org/zstack/core/Platform.java

Repository: MatheMatrix/zstack

Length of output: 357


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== ExternalPrimaryStorage excerpt ==="
sed -n '1418,1442p' storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java

echo
echo "=== operr implementation ==="
sed -n '1738,1760p' core/src/main/java/org/zstack/core/Platform.java

echo
echo "=== nearby operr usages in ExternalPrimaryStorage ==="
rg -n 'operr\(' storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java

Repository: MatheMatrix/zstack

Length of output: 4107


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n 'ORG_ZSTACK_STORAGE_ADDON_PRIMARY_10041|ORG_ZSTACK_STORAGE_ADDON_PRIMARY_1004[0-9]|ORG_ZSTACK_STORAGE_ADDON_PRIMARY_100[0-9]+' storage/src/main/java/org/zstack/storage/addon/primary/ExternalPrimaryStorage.java

Repository: MatheMatrix/zstack

Length of output: 1466


operr(...) 少传了全局错误码参数。
这里把提示文本当成了 globalErrorCode,后面的 %s 也不会按预期格式化;最终错误码和错误信息都会错位。按本类其它调用补上一个模块内错误码常量即可。

🤖 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 1432 - 1436, 修正 ExternalPrimaryStorage 中该 completion.fail 的 operr
调用,补上本模块现有的全局错误码常量作为首个参数,并保持后续提示文本及 imageUuid、primaryStorageUuid
参数顺序不变,确保错误码和格式化信息正确对应。

@MatheMatrix MatheMatrix force-pushed the sync/jin.ma/fix/ZSTAC-86038-storage-resource-stats branch from d5c3054 to 5b28e20 Compare July 13, 2026 11:02
Generalize stats for volume and snapshot resources and rely on AsyncSafeAspect for completion errors.

Resolves: ZSTAC-86038

Change-Id: I8660e9884c76cac94aedc8736f99b488779b7897
@MatheMatrix MatheMatrix force-pushed the sync/jin.ma/fix/ZSTAC-86038-storage-resource-stats branch from 5b28e20 to b808517 Compare July 15, 2026 06:10
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.

2 participants