<fix>[vm]: add MetadataImpact#3612
<fix>[vm]: add MetadataImpact#3612MatheMatrix wants to merge 1 commit intofeature-zsv-5.0.0-vm-registrationfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Walkthrough引入完整的 VM 实例元数据管理功能:新增元数据清理/获取/扫描/注册/更新 API、消息类型、数据库表、扩展点与本地/NFS 存储实现,并在大量现有 API 上添加元数据影响注解与 SDK/测试支持。 Changes
Sequence Diagram(s)sequenceDiagram
participant Flow as VmExpungeMetadataFlow
participant Ext as VmMetadataPathBuildExtensionPoint
participant Bus as CloudBus/PrimaryStorageService
participant PS as PrimaryStorageBackend
participant Host as HostAgent
participant GC as CleanupVmInstanceMetadataOnPrimaryStorageGC
rect rgba(200,200,255,0.5)
Flow->>Ext: buildVmMetadataPath(primaryStorageUuid, vmUuid)
end
rect rgba(200,255,200,0.5)
Flow->>Bus: send CleanupVmInstanceMetadataOnPrimaryStorageMsg
Bus->>PS: deliver msg to primary storage service
PS->>Host: http/agent call (cleanup metadata path)
Host-->>PS: agent response (success/failure)
PS-->>Bus: reply (success/failure)
Bus-->>Flow: callback with reply
end
alt reply.success == false
Flow->>GC: submitGC(...) (deduplicated)
end
估计代码审查工作量🎯 5 (Critical) | ⏱️ ~120 minutes 诗韵
✨ Finishing Touches🧪 Generate unit tests (beta)
|
|
Comment from yaohua.wu: Review: MR !9472 — ZSV-11559 (zstackio/zstack)
本 MR(149 files)引入
注意:由于 GitLab API 限制,149 个文件中有 49 个 diff 为空(含关键实现文件如 LocalStorageKvmBackend、NfsPrimaryStorageKVMBackend、PrimaryStorageBase、VmInstanceState 等),以下 review 仅覆盖可见 diff 部分。建议本地 🟡 Warning1. [VmMetadataFingerprintVO.java] 缺少
建议: @PreUpdate
private void preUpdate() {
lastOpDate = null;
}2. [VmMetadataDirtyVO.java / VmMetadataFingerprintVO.java] 两个 VO 的 3. [APIConvertTemplatedVmInstanceToVmInstanceMsg.java] 注解 4. [VmExpungeMetadataFlow.java] GC 提交缺少错误类型区分 cleanup 消息失败时统一提交 GC 重试,未区分瞬态错误(host 不可达,可重试)和永久错误(PS 已删除、metadata 路径无效)。永久错误会导致无限 GC 重试。建议检查错误码,对永久错误跳过 GC 提交,或在 GC 5. [APICleanupVmInstanceMetadataMsg / APIUpdateVmInstanceMetadataMsg]
🟢 Suggestion1. [VmMetadataErrors.java] 错误码 1300-1311 建议确认无冲突 错误码以 2. [VmMetadataCategory.java] 枚举值缺少文档
3. [VmInstanceMetadataConstants.java / 多个 Groovy doc 文件] 文件末尾缺少换行符
4. [APIGetVmInstanceMetadataFromPrimaryStorageMsg.java] GET 请求使用 作为读操作的 GET API 使用了 ✅ 正面评价
Verdict: COMMENT
🤖 Robot Reviewer |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (24)
header/src/main/java/org/zstack/header/vm/VmInstanceState.java (1)
194-198: 建议为Registering增加unknown/noState兜底转换,避免状态机抛异常。当前 Line 194-198 仅覆盖 3 个事件;若收到未映射事件,Line 240-245 会直接抛
CloudRuntimeException。建议补充与其他过渡态一致的兜底分支以提升韧性。建议补丁
Registering.transactions( new Transaction(VmInstanceStateEvent.stopped, VmInstanceState.Stopped), new Transaction(VmInstanceStateEvent.destroying, VmInstanceState.Destroying), - new Transaction(VmInstanceStateEvent.destroyed, VmInstanceState.Destroyed) + new Transaction(VmInstanceStateEvent.destroyed, VmInstanceState.Destroyed), + new Transaction(VmInstanceStateEvent.noState, VmInstanceState.NoState), + new Transaction(VmInstanceStateEvent.unknown, VmInstanceState.Unknown) );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/VmInstanceState.java` around lines 194 - 198, The Registering state transition block currently registers only three specific events (using Registering and new Transaction(...) with VmInstanceStateEvent.stopped/destroying/destroyed -> VmInstanceState.Stopped/Destroying/Destroyed) and lacks a fallback for unmapped events which leads to a CloudRuntimeException; add a default/unknown mapping for Registering (e.g., mapping an UNKNOWN or NoState transition to a safe target such as VmInstanceState.Unknown or VmInstanceState.NoState consistent with other states' fallback handling) so that any unexpected VmInstanceStateEvent falling into Registering is handled gracefully instead of throwing; locate the Registering.transactions(...) call and add the extra Transaction(...) entry for the unknown/noState fallback using the same pattern as the other Transaction registrations.header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java (1)
3-16: 建议添加 Javadoc 文档说明枚举类及其常量缺少 Javadoc 文档注释。作为位于 header 包中的公共 API 元素,应当为枚举类和每个错误常量添加文档说明,解释各错误码的含义、触发场景和使用时机,以提高代码的自解释性和可维护性。
例如:
/** * VM 元数据操作相关错误码定义 */ public enum VmMetadataErrors { /** 元数据格式无效 */ METADATA_INVALID_FORMAT(1300), /** 元数据架构版本不匹配 */ METADATA_SCHEMA_VERSION_MISMATCH(1301), // ... }根据编码规范:"代码应尽量做到自解释",对于公共 API 应提供充分的文档说明。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java` around lines 3 - 16, Add Javadoc to the public enum VmMetadataErrors and each enum constant to document meaning and usage; update the VmMetadataErrors type-level comment to explain this enum is for VM metadata operation error codes and for each constant (e.g., METADATA_INVALID_FORMAT, METADATA_SCHEMA_VERSION_MISMATCH, METADATA_UUID_CONFLICT, METADATA_STORAGE_NOT_SUPPORTED, METADATA_CROSS_STORAGE_FORBIDDEN, METADATA_INSTALL_PATH_NOT_FOUND, METADATA_CACHE_VM_NOT_REGISTERABLE, METADATA_VM_REGISTERING, METADATA_READ_CORRUPTED, METADATA_PAYLOAD_TOO_LARGE, METADATA_PS_UNREACHABLE, METADATA_FEATURE_DISABLED) add a brief Javadoc describing the error condition and typical trigger/handling guidance so the public API is self-documenting.header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy (2)
12-21: 建议:为请求添加描述文本。第20行的请求描述为空(
desc """""")。虽然顶层的desc已经提供了接口说明,但建议在请求部分也添加简短的描述,以提高API文档的完整性和可读性。📝 建议的改进
request { url "GET /v1/primary-storage/vm-instances/metadata" header (Authorization: 'OAuth the-session-uuid') clz APIGetVmInstanceMetadataFromPrimaryStorageMsg.class - desc """""" + desc """通过云主机UUID从主存储获取元数据信息""" params {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy` around lines 12 - 21, The request block in APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy currently has an empty request description (desc """""") — add a short, meaningful description string to the request's desc field inside the rest.request block (for the APIGetVmInstanceMetadataFromPrimaryStorageMsg documentation) to improve API docs completeness and readability; keep it concise and aligned with the top-level desc content.
33-41: 可选改进:考虑为List类型参数指定元素类型。
systemTags和userTags参数都定义为type "List",但未指定列表元素类型。如果框架支持,建议明确指定元素类型(例如List<String>),以提高API文档的清晰度。不过,如果这是ZStack框架的标准约定,则当前定义是可以接受的。
Also applies to: 42-50
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy` around lines 33 - 41, The API doc column entries for the List-typed fields (the "systemTags" and "userTags" column blocks in APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy) should declare the list element type if the doc framework supports it; update the two column definitions to use a typed list (e.g., List<String> or equivalent syntax supported by the doc generator) for the "type" attribute so the generated API docs show element types rather than an untyped List, keeping the rest of the column attributes unchanged.header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java (1)
5-14: 字段命名与同类 Reply 不一致。此类使用
vmMetadata字段,而GetVmInstanceMetadataFromPrimaryStorageReply使用metadata字段。建议统一命名以减少混淆,提高代码一致性。♻️ 建议统一字段命名
public class ReadVmInstanceMetadataReply extends MessageReply { - private String vmMetadata; + private String metadata; - public String getVmMetadata() { - return vmMetadata; + public String getMetadata() { + return metadata; } - public void setVmMetadata(String vmMetadata) { - this.vmMetadata = vmMetadata; + public void setMetadata(String metadata) { + this.metadata = metadata; } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java` around lines 5 - 14, Rename the vmMetadata field in ReadVmInstanceMetadataReply to match the other reply class for consistency: change the field name vmMetadata, its getter getVmMetadata(), and setter setVmMetadata(String) to metadata, getMetadata(), and setMetadata(String) respectively; ensure the class ReadVmInstanceMetadataReply and its usages are updated to reference metadata so it aligns with GetVmInstanceMetadataFromPrimaryStorageReply.header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java (1)
3-7: 字段命名vo使用了缩写,含义不明确。根据编码规范,应避免使用不必要的缩写。
vo可能代表 "Value Object",但作为字段名不够自解释。建议使用更具描述性的命名,如voData、valueObjectJson或根据实际存储内容使用更具体的名称。♻️ 建议改进字段命名
public class ResourceMetadata { private String resourceUuid; - private String vo; + private String voData; private String systemTags; private String resourceConfigs;同时更新对应的 getter/setter 方法。
根据编码规范:"不允许使用不必要的缩写,如:
AbsSchedulerJob、condi、Fu等。应使用完整单词提升可读性。"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java` around lines 3 - 7, The field name "vo" is an unclear abbreviation; rename the field (e.g., change ResourceMetadata.vo to valueObjectJson or voData) and update all corresponding accessor methods (getVo/setVo → getValueObjectJson/setValueObjectJson or getVoData/setVoData) and any usages in the class or callers (constructors, builders, serialization/deserialization code) to use the new name so the intent is explicit and compilation remains clean; ensure any JSON mapping annotations or reflection-based references are updated accordingly.header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java (1)
26-29: 建议在__example__()中设置示例 metadata 值。当前
__example__()方法返回的事件对象未设置metadata字段的示例值,这会影响 API 文档的示例展示效果。♻️ 建议的改进
public static APIGetVmInstanceMetadataFromPrimaryStorageEvent __example__() { APIGetVmInstanceMetadataFromPrimaryStorageEvent evt = new APIGetVmInstanceMetadataFromPrimaryStorageEvent(); + evt.setMetadata("{\"uuid\":\"example-uuid\",\"name\":\"example-vm\"}"); return evt; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java` around lines 26 - 29, The __example__() in class APIGetVmInstanceMetadataFromPrimaryStorageEvent returns an empty event; populate its metadata field with a realistic example so API docs show sample data. Update APIGetVmInstanceMetadataFromPrimaryStorageEvent.__example__() to call the class's metadata setter (e.g., evt.setMetadata(...)) and provide a representative map/collection of entries (for example keys like "user-data", "meta-data", or a cloud-init payload and corresponding values) or a small JSON-like map to illustrate structure and types.header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java (1)
11-13: 考虑快照相关字段的类型一致性
snapshots、snapshotGroups和snapshotGroupRefs字段使用List<String>类型,而volumes和nics使用了类型化的元数据类(VolumeResourceMetadata、ResourceMetadata)。这种不一致可能是有意为之(例如仅存储 UUID 引用),但建议在类注释中说明设计意图,以便后续维护者理解。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java` around lines 11 - 13, VmInstanceMetadataDTO has inconsistent types: snapshots, snapshotGroups, snapshotGroupRefs are List<String> while volumes and nics use typed metadata classes (VolumeResourceMetadata, ResourceMetadata); update the class to either (A) change snapshots/snapshotGroups/snapshotGroupRefs to use a dedicated metadata type consistent with VolumeResourceMetadata/ResourceMetadata, or (B) add a clear class-level JavaDoc on VmInstanceMetadataDTO explaining that those three fields intentionally store only UUID strings and why, referencing the fields snapshots, snapshotGroups, snapshotGroupRefs and the existing VolumeResourceMetadata and ResourceMetadata to make the design intent explicit for future maintainers.testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy (1)
604-618: 考虑添加 VFS hooks 以支持更完整的测试场景新增的元数据模拟器目前仅返回空响应对象,与其他端点(如
CREATE_VOLUME_FROM_CACHE_PATH、DELETE_BITS_PATH等)相比缺少对应的 VFS hooks。如果后续测试需要验证元数据的实际读写行为,建议补充相应的 VFS hooks 实现。当前实现对基础功能测试是足够的,可以根据实际测试需求在后续迭代中完善。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy` around lines 604 - 618, 当前对 LocalStorageKvmBackend 的元数据模拟器(标识符:WRITE_VM_METADATA_PATH、GET_VM_INSTANCE_METADATA_PATH、SCAN_VM_METADATA_PATH、CLEANUP_VM_METADATA_PATH)仅返回空响应,建议在这些 simulator 处理器中补充与已有端点(例如 CREATE_VOLUME_FROM_CACHE_PATH、DELETE_BITS_PATH)一致的 VFS hook 调用以模拟真实文件系统行为:在 WRITE_VM_METADATA_PATH 中将接收到的数据写入 VFS;在 GET_VM_INSTANCE_METADATA_PATH 中从 VFS 读取并返回内容;在 SCAN_VM_METADATA_PATH 中列出 VFS 中的元数据条目;在 CLEANUP_VM_METADATA_PATH 中删除对应的 VFS 条目,从而支持后续需要验证实际读写的测试场景(定位 simulator 处理器即可修改实现)。header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java (1)
19-19: 考虑使用更直接的解析方式当前配置使用
NicUuidToVmUuidResolver从vmNicUuid解析 VM UUID,但类中已有vmInstanceUuid字段(第 22 行),可以直接使用:`@MetadataImpact`(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "vmInstanceUuid")这样可以避免额外的 NIC → VM 查询开销。当前实现功能正确,这只是一个优化建议。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java` at line 19, In APIUpdateVmNicDriverMsg change the MetadataImpact annotation to use the direct VM resolver and field to avoid extra NIC→VM lookup: update the `@MetadataImpact`(...) on class APIUpdateVmNicDriverMsg to reference resolver "VmUuidDirectResolver" and field "vmInstanceUuid" instead of "NicUuidToVmUuidResolver" and "vmNicUuid" so the resolver uses the existing vmInstanceUuid field directly.header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java (1)
18-34: 考虑添加 APIAuditor 实现此 API 消息类未实现
APIAuditor接口。项目中其他 API 消息类(如同目录下的APIConvertVmInstanceToTemplatedVmInstanceMsg)通常实现此接口以支持审计功能。如果需要记录元数据更新操作的审计日志,建议添加:💡 建议添加 APIAuditor 实现
+import org.zstack.header.message.APIEvent; +import org.zstack.header.other.APIAuditor; `@RestRequest`( path = "/vm-instances/metadata/actions", method = HttpMethod.PUT, responseClass = APIUpdateVmInstanceMetadataEvent.class, isAction = true ) -public class APIUpdateVmInstanceMetadataMsg extends APIMessage { +public class APIUpdateVmInstanceMetadataMsg extends APIMessage implements APIAuditor { `@APIParam`(resourceType = VmInstanceVO.class, nonempty = true) private List<String> vmUuids; // ... existing code ... + + `@Override` + public Result audit(APIMessage msg, APIEvent rsp) { + // 批量操作可返回第一个 VM UUID 或自定义审计逻辑 + APIUpdateVmInstanceMetadataMsg m = (APIUpdateVmInstanceMetadataMsg) msg; + return new Result(m.vmUuids.isEmpty() ? "" : m.vmUuids.get(0), VmInstanceVO.class); + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java` around lines 18 - 34, Update APIUpdateVmInstanceMetadataMsg to implement the APIAuditor interface and add an audit(APIMessage msg) implementation that returns an audit result listing the affected VM UUIDs (use the vmUuids field) and the resource type VmInstanceVO; ensure the audit method handles null/empty vmUuids gracefully and constructs the standard audit response used by other messages in the same package (mirror the pattern from APIConvertVmInstanceToTemplatedVmInstanceMsg: implement APIAuditor, add audit(...) returning the affected resource UUID(s) and VmInstanceVO as the resource type).sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java (1)
6-11: 建议在 SDK 生成器模板中添加泛型支持,而非在单个 Result 类中修改。当前
vmInstanceMetadata使用 rawList导致类型不安全。虽然建议的修复方案List<VmMetadataScanEntry>是准确的,但根本问题在于 SDK 生成器模板(SdkDataStructureGenerator.groovy)在处理 Collection 字段时只输出类型名称而丢弃了泛型信息。直接修改生成代码会被生成器再次运行时覆盖。建议在生成器模板中保留来自源定义(
ScanVmInstanceMetadataFromPrimaryStorageReply)的泛型参数,使所有生成的 Result 类都包含完整的类型信息。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java` around lines 6 - 11, The generated Result class ScanVmInstanceMetadataFromPrimaryStorageResult exposes a raw java.util.List field vmInstanceMetadata causing loss of generic type information; update the SDK generator template SdkDataStructureGenerator.groovy so when it emits collection-typed fields (like vmInstanceMetadata) it preserves and emits the original generic parameter from the source reply type (ScanVmInstanceMetadataFromPrimaryStorageReply) (e.g., List<VmMetadataScanEntry>) rather than printing only the raw collection type, ensuring all generated Result classes include correct generics.header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java (1)
5-10: 给持久化回调补 Javadoc,说明调用时机和参数约定。这个扩展点参数较多,
resourceType、size的单位、now的来源,以及回调是否要求幂等现在都不清晰,后续实现很容易各自理解。As per coding guidelines "接口方法不应有多余的修饰符(例如 public),且必须配有有效的 Javadoc 注释。"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java` around lines 5 - 10, 为接口 VmMetadataResourcePersistExtensionPoint 及其方法 getPrimaryStorageType、afterVolumePersist、afterSnapshotPersist 添加 Javadoc,说明每个回调的调用时机(如“在资源信息持久化到数据库后立即调用,由持久化流程主动触发”)、参数语义和约定:明确 resourceType 的取值或参考枚举,size 的单位为字节(bytes),now 表示由调用方在持久化时传入的事件时间(Timestamp,建议使用持久化时的数据库/系统时间),并标注回调方法是否必须实现幂等(如要求幂等或说明不保证幂等);同时在接口注释中列出实现者需注意的线程/事务上下文(例如回调在持久化事务之后执行且不在同一事务中)。header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java (1)
3-8: 给扩展点方法补上 Javadoc。这是跨主存储实现共享的公共契约,
validateMetadataPath()的返回约定,以及两个 build 方法期望返回的路径范围/格式,现在只能靠实现方猜。As per coding guidelines "接口方法不应有多余的修饰符(例如 public),且必须配有有效的 Javadoc 注释。"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java` around lines 3 - 8, 为 VmMetadataPathBuildExtensionPoint 接口和其四个方法补写准确的 Javadoc:在接口注释中说明这是跨主存储实现共享的公共契约并列出约定;为 getPrimaryStorageType() 注明返回值应是该扩展实现对应的主存储类型标识符;为 buildVmMetadataPath(String primaryStorageUuid, String vmInstanceUuid) 说明应返回针对给定主存储 UUID 与 VM UUID 的完整元数据文件路径(示例格式或允许的前缀/分隔符);为 buildMetadataDir(String primaryStorageUuid) 说明应返回在该主存储下存放所有 VM 元数据的目录路径(是否以斜杠结尾需约定);为 validateMetadataPath(String primaryStorageUuid, String path) 说明返回约定:当 path 合法返回 null;不合法时返回描述性错误信息(包括哪些检查要做,如路径必须在 buildMetadataDir 返回的目录范围内、无非法字符等)。在注释中引用方法签名以便实现者遵循一致的行为约定。header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java (1)
30-34: 建议在__example__()中指定资源类型为保持一致性,建议使用
uuid(PrimaryStorageVO.class)而不是无参的uuid()。参考同 PR 中APIGetVmInstanceMetadataFromPrimaryStorageMsg的写法:♻️ 建议修改
public static APIScanVmInstanceMetadataFromPrimaryStorageMsg __example__() { APIScanVmInstanceMetadataFromPrimaryStorageMsg msg = new APIScanVmInstanceMetadataFromPrimaryStorageMsg(); - msg.setUuid(uuid()); + msg.setUuid(uuid(PrimaryStorageVO.class)); return msg; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java` around lines 30 - 34, The example generator APIScanVmInstanceMetadataFromPrimaryStorageMsg.__example__() should use a typed UUID for consistency; replace the call to uuid() with uuid(PrimaryStorageVO.class) when setting msg.setUuid(...) so the example mirrors APIGetVmInstanceMetadataFromPrimaryStorageMsg and explicitly indicates the PrimaryStorageVO resource type.compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java (1)
137-141: 建议为新配置添加@GlobalConfigDef注解新增的元数据配置缺少
@GlobalConfigDef注解来定义默认值、类型和描述。参考同文件中其他配置(如VM_CLOCK_SYNC_INTERVAL_IN_SECONDS)的模式:`@GlobalConfigDef`(defaultValue = "false", type = Boolean.class, description = "enable vm metadata feature") `@GlobalConfigValidation`(validValues = {"true", "false"}) public static GlobalConfig VM_METADATA_ENABLED = ...这有助于 API 文档生成和配置管理。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java` around lines 137 - 141, Add `@GlobalConfigDef` annotations for the two new globals so they have defaults, types and descriptions: annotate VM_METADATA_ENABLED with e.g. `@GlobalConfigDef`(defaultValue = "false", type = Boolean.class, description = "enable vm metadata feature") (keep the existing `@GlobalConfigValidation`) and annotate VM_METADATA_LAST_REFRESH_VERSION with a suitable `@GlobalConfigDef` (e.g. defaultValue = "", type = String.class, description = "last refresh version for vm metadata") to match the pattern used by VM_CLOCK_SYNC_INTERVAL_IN_SECONDS and enable proper API docs/config management.header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java (1)
7-9: 建议为接口方法添加 Javadoc 注释。根据编码规范,接口方法必须配有有效的 Javadoc 注释,以便说明方法的用途、参数含义和返回值。
📝 建议的改进
public interface VmMetadataPathReplacementExtensionPoint { + /** + * 获取此扩展点支持的主存储类型 + * `@return` 主存储类型标识符 + */ String getPrimaryStorageType(); + + /** + * 计算元数据路径替换映射 + * `@param` targetPsUuid 目标主存储UUID + * `@param` allOldPaths 所有旧路径列表 + * `@return` 路径替换结果,包含旧路径到新路径的映射 + */ PathReplacementResult calculatePathReplacements(String targetPsUuid, List<String> allOldPaths);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java` around lines 7 - 9, 为 VmMetadataPathReplacementExtensionPoint 接口和其方法添加完整的 Javadoc 注释:在接口声明上写明该扩展点的用途,然后为 getPrimaryStorageType() 和 calculatePathReplacements(String targetPsUuid, List<String> allOldPaths) 分别写明方法用途、参数含义(例如 targetPsUuid 是目标主存储 UUID,allOldPaths 是要替换的老路径列表)和返回值含义(PathReplacementResult 表示替换结果及可能的错误或映射),同时注明实现者的期望行为与线程/异常约束,以便调用者和实现者明确契约。compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java (2)
55-56: 移除多余的空行。Line 56 处存在多余的空行。
♻️ 建议的改进
} - - + String psType = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.type).eq(PrimaryStorageVO_.uuid, psUuid).findValue();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java` around lines 55 - 56, 在 VmExpungeMetadataFlow 类中移除多余的空行:打开 VmExpungeMetadataFlow.java,定位类/方法定义处靠近行 56(类名 VmExpungeMetadataFlow)并删除该多余的空白行以保持文件格式一致和代码整洁;确保只移除空行,不更改其他代码或缩进。
37-37: 使用泛型参数替代原始Map类型。
Map data使用了原始类型,建议添加泛型参数以提高类型安全性。♻️ 建议的改进
`@Override` - public void run(FlowTrigger trigger, Map data) { + public void run(FlowTrigger trigger, Map<String, Object> data) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java` at line 37, The method signature run(FlowTrigger trigger, Map data) uses a raw Map; change it to use a generic type (e.g., Map<String, Object> or the appropriate key/value types used in the method) to improve type safety, update the method signature and any internal references to the Map (casts, get/put calls) to the chosen generic types, and adjust any callers if necessary so the compile-time types align with the new signature.header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java (1)
46-52:__example__()方法可考虑设置success状态。作为 API 文档示例,建议也设置父类
APIEvent的success字段,使示例更完整。📝 建议的改进
public static APICleanupVmInstanceMetadataEvent __example__() { APICleanupVmInstanceMetadataEvent evt = new APICleanupVmInstanceMetadataEvent(); + evt.setSuccess(true); evt.totalCleaned = 5; evt.totalFailed = 0; evt.failedVmUuids = java.util.Collections.emptyList(); return evt; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java` around lines 46 - 52, The example factory APICleanupVmInstanceMetadataEvent.__example__() does not set the inherited APIEvent.success flag; update the method to set evt.setSuccess(true) (or evt.success = true if using a public field) before returning so the example shows a successful APIEvent, referencing APICleanupVmInstanceMetadataEvent.__example__() and the APIEvent.success property.plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java (1)
1988-2086: 这几段“选 host + 委派 backend + 统一失败回包”已经重复了,建议抽 helper。
Get*/Scan*/Cleanup*/Rebase*这四个方法除了消息类型不同,其余分支几乎完全一致。抽一个私有委派方法,后续再加元数据操作时不容易漏改。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java` around lines 1988 - 2086, The four handlers (handle(GetVmInstanceMetadataFromPrimaryStorageMsg), handle(ScanVmInstanceMetadataFromPrimaryStorageMsg), handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg), handle(RebaseVolumeBackingFileOnPrimaryStorageMsg)) duplicate the "select connected host + getBackendByHostUuid + backend.handle(...) with unified fail reply" logic; extract a private helper (e.g. dispatchToBackend(msg, replyCreator, msgClass, ReturnValueCompletionFactory) or a typed generic method) that calls factory.getConnectedHostForOperation(getSelfInventory()), picks hostUuid, obtains NfsPrimaryStorageBackend via getBackendByHostUuid(hostUuid), and invokes backend.handle(...) wiring success->bus.reply(msg, r) and fail->reply.setError(errorCode); then refactor each of the four handlers to call this helper with the appropriate message and reply types and remove the duplicated code paths (keep using ReturnValueCompletion for async callbacks).plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.java (1)
346-363: 建议让 get/scan 响应也支持从 config 注入测试数据。现在
GetVmInstanceMetadataRsp/ScanVmMetadataRsp都是空对象,后续很难在 simulator 里覆盖“返回非空元数据”“分类过滤”等分支。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.java` around lines 346 - 363, Update the simulator endpoints getVmInstanceMetadata and scanVmMetadata to allow injecting test responses from the simulator config: add configurable response holders on the existing config (e.g., a predefined GetVmInstanceMetadataRsp or a list/map of GetVmInstanceMetadataRsp entries and similarly for ScanVmMetadataRsp), and in the methods (getVmInstanceMetadata, scanVmMetadata) if a configured response exists, populate the rsp from that config (respecting any filter criteria from the incoming GetVmInstanceMetadataCmd/ScanVmMetadataCmd such as classification or vm identifiers) before calling reply(entity, rsp); otherwise keep the current empty rsp behavior. Ensure you reference the existing config fields used (config.getVmInstanceMetadataCmds, config.scanVmMetadataCmds) and the response types (GetVmInstanceMetadataRsp, ScanVmMetadataRsp) when adding and reading the injected test data.plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java (1)
37-120: 建议把这组元数据路径规则抽到共享 helper。
buildMetadataDir、buildVmMetadataPath、validateMetadataPath和calculatePathReplacements这几段和NfsVmMetadataExtension基本是同一套规则。现在一旦元数据目录命名、校验规则或 prefix 替换逻辑有调整,就需要双份维护,后面很容易出现一边修了另一边漏修。把公共逻辑收敛到共享 helper / base class,只保留各存储自己的 baseDir 解析和资源持久化,会更稳。As per coding guidelines, "每个模块、类、方法应只承担单一的责任。若某个逻辑过于复杂,应考虑拆分出独立类来处理。"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java` around lines 37 - 120, Extract the shared metadata path logic into a common helper or abstract base (e.g., MetadataPathHelper or AbstractVmMetadataExtension) and have LocalStorageVmMetadataExtension and NfsVmMetadataExtension delegate to it: move the implementations of buildMetadataDir/buildVmMetadataPath/validateMetadataPath/calculatePathReplacements (the validation, prefix extraction, normalization and replacement algorithms that reference VmInstanceMetadataConstants and normalizeBaseDir) into the helper/base; keep only storage-specific pieces (how to obtain baseDir/url) in LocalStorageVmMetadataExtension (e.g., a single method like resolveBaseDir(primaryStorageUuid)) and have the helper call that to build final paths and replacements; ensure normalizeBaseDir remains available to the helper and that PathReplacementResult population and warnings stay consistent.plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java (1)
2157-2162: 建议把空扫描结果也标准化为空列表。这里在
rsp.metadataEntries == null时会把 reply 保持为未设置状态,而同一 PR 里的 LocalStorage 实现已经显式回落到Collections.emptyList()。把两个后端的返回语义统一起来,能减少上层为 NFS 路径单独处理null分支的概率。💡 建议修改
ScanVmInstanceMetadataFromPrimaryStorageReply r = new ScanVmInstanceMetadataFromPrimaryStorageReply(); if (rsp.metadataEntries != null) { rsp.metadataEntries.forEach(entry -> entry.setHostUuid(hostUuid)); r.setVmInstanceMetadata(rsp.metadataEntries); + } else { + r.setVmInstanceMetadata(Collections.emptyList()); } completion.success(r);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java` around lines 2157 - 2162, The reply for ScanVmInstanceMetadataFromPrimaryStorageReply in NfsPrimaryStorageKVMBackend currently leaves VmInstanceMetadata unset when rsp.metadataEntries is null; change the handling in the block (the lambda shown in NfsPrimaryStorageKVMBackend) to always call r.setVmInstanceMetadata(...) and pass an empty list (e.g. Collections.emptyList() or new ArrayList<>()) when rsp.metadataEntries == null, and when non-null keep the existing hostUuid assignment and set that list; this makes the NFS backend consistent with the LocalStorage implementation and avoids nulls for callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java`:
- Around line 1330-1333: 在 VmInstanceApiInterceptor 中对 msg.getMetadataPath()
做空白字符串校验:当前只判断 null/"",需将纯空白(例如 " ")也视为非法。修改对 metadataPath 的检查(在使用
msg.getMetadataPath() 的位置)为在判空前先 trim 或使用 isBlank 等方式(例如 check path == null ||
path.trim().isEmpty()),并在不合法时仍抛出
ApiMessageInterceptionException(argerr("metadataPath cannot be empty"))
保持原错误类型及信息。
In `@conf/db/upgrade/V5.0.0__schema.sql`:
- Around line 12-13: 在外键定义里将被引用表显式加上 zstack schema:把 CONSTRAINT
`fkVmMetadataDirtyVOVmInstanceEO` 的 REFERENCES `VmInstanceEO` (`uuid`) 修改为
REFERENCES `zstack`.`VmInstanceEO` (`uuid`),并把 CONSTRAINT
`fkVmMetadataDirtyVOManagementNodeVO` 的 REFERENCES `ManagementNodeVO` (`uuid`)
修改为 REFERENCES `zstack`.`ManagementNodeVO`
(`uuid`),确保两个外键(fkVmMetadataDirtyVOVmInstanceEO,
fkVmMetadataDirtyVOManagementNodeVO)都使用 zstack. 前缀以保持 conf/db/upgrade
目录脚本的一致性和在非默认库上下文的可读性。
In
`@header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java`:
- Around line 19-24: The extractOldPrefix logic incorrectly returns the prefix
based on the first marker in STORAGE_PATH_MARKERS rather than the earliest
marker occurrence in the given path, producing unstable results when multiple
markers are present; update extractOldPrefix to scan all markers
(STORAGE_PATH_MARKERS), track the smallest non-negative index (e.g., minIdx
initialized to Integer.MAX_VALUE), and after the loop if minIdx !=
Integer.MAX_VALUE return path.substring(0, minIdx + 1) (otherwise preserve
original fallback behavior), ensuring you reference the existing
variables/methods extractOldPrefix, STORAGE_PATH_MARKERS and path when making
the change.
In
`@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.java`:
- Around line 10-29: Add the missing Timestamp fields lastOpDate and createDate
to VmMetadataFingerprintVO (annotated with `@Column`), provide their public
getters and setters, and add a `@PreUpdate` annotated method (e.g., preUpdate())
that sets lastOpDate to null to match the DB schema and the behavior in
VmMetadataDirtyVO; ensure field types and annotations mirror VmMetadataDirtyVO
for consistency.
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java`:
- Around line 3491-3500: In LocalStorageBase inside the
WhileDoneCompletion.done(ErrorCodeList) block, don't treat partial host failures
as success; if errorCodeList.getCauses() is non-empty (i.e. any host failed)
return an overall error via reply.setError(...) instead of returning a partial
list—include the failed host UUIDs and the errorCodeList in the message for
debugging; ensure only when errorCodeList.getCauses().isEmpty() you call
reply.setVmInstanceMetadata(...). Use the existing symbols errorCodeList,
connectedHostUuids, reply.setError and reply.setVmInstanceMetadata to locate and
implement this change.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java`:
- Around line 1950-1978: 不要把所有异常一律包装成 operr——在 NfsPrimaryStorage 的该 try/catch
中(调用 getHostUuidFromVolume, getBackendByHostUuid, backend.handle 和使用
ReturnValueCompletion<UpdateVmInstanceMetadataOnPrimaryStorageReply>
的地方),改为区分异常类型:如果捕获到的是带原始 ErrorCode 的异常(例如 OperationFailureException 或能返回
ErrorCode 的异常),从异常中取出 ErrorCode 并用 reply.setError(thatErrorCode) 返回;否则保留当前的
reply.setError(operr(...)) 逻辑,但同时用 logger.error/exception 记录完整堆栈信息以便排查,并确保仍然调用
bus.reply(msg, reply) 和 chain.next()。
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java`:
- Around line 29-37: The current fallback in resolveBaseDir (and likewise in
calculatePathReplacements) erroneously treats PrimaryStorageVO.url as a local
mount path causing agent-side file operations to use NFS export URLs; change the
logic to require mountPath only: remove the fallback to url, and if mountPath is
null throw a CloudRuntimeException with clear context (including
primaryStorageUuid) so metadata operations (buildMetadataDir,
buildVmMetadataPath) fail fast; also update any callers/validators (or note
NfsPrimaryStorageFactory behavior) to ensure mountPath is set before allowing
metadata-related commands (WriteVmMetadataCmd.metadataPath /
ScanVmMetadataCmd.metadataDir) to be used.
---
Nitpick comments:
In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java`:
- Around line 55-56: 在 VmExpungeMetadataFlow 类中移除多余的空行:打开
VmExpungeMetadataFlow.java,定位类/方法定义处靠近行 56(类名
VmExpungeMetadataFlow)并删除该多余的空白行以保持文件格式一致和代码整洁;确保只移除空行,不更改其他代码或缩进。
- Line 37: The method signature run(FlowTrigger trigger, Map data) uses a raw
Map; change it to use a generic type (e.g., Map<String, Object> or the
appropriate key/value types used in the method) to improve type safety, update
the method signature and any internal references to the Map (casts, get/put
calls) to the chosen generic types, and adjust any callers if necessary so the
compile-time types align with the new signature.
In `@compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java`:
- Around line 137-141: Add `@GlobalConfigDef` annotations for the two new globals
so they have defaults, types and descriptions: annotate VM_METADATA_ENABLED with
e.g. `@GlobalConfigDef`(defaultValue = "false", type = Boolean.class, description
= "enable vm metadata feature") (keep the existing `@GlobalConfigValidation`) and
annotate VM_METADATA_LAST_REFRESH_VERSION with a suitable `@GlobalConfigDef` (e.g.
defaultValue = "", type = String.class, description = "last refresh version for
vm metadata") to match the pattern used by VM_CLOCK_SYNC_INTERVAL_IN_SECONDS and
enable proper API docs/config management.
In
`@header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java`:
- Around line 30-34: The example generator
APIScanVmInstanceMetadataFromPrimaryStorageMsg.__example__() should use a typed
UUID for consistency; replace the call to uuid() with
uuid(PrimaryStorageVO.class) when setting msg.setUuid(...) so the example
mirrors APIGetVmInstanceMetadataFromPrimaryStorageMsg and explicitly indicates
the PrimaryStorageVO resource type.
In
`@header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java`:
- Around line 5-14: Rename the vmMetadata field in ReadVmInstanceMetadataReply
to match the other reply class for consistency: change the field name
vmMetadata, its getter getVmMetadata(), and setter setVmMetadata(String) to
metadata, getMetadata(), and setMetadata(String) respectively; ensure the class
ReadVmInstanceMetadataReply and its usages are updated to reference metadata so
it aligns with GetVmInstanceMetadataFromPrimaryStorageReply.
In `@header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java`:
- Line 19: In APIUpdateVmNicDriverMsg change the MetadataImpact annotation to
use the direct VM resolver and field to avoid extra NIC→VM lookup: update the
`@MetadataImpact`(...) on class APIUpdateVmNicDriverMsg to reference resolver
"VmUuidDirectResolver" and field "vmInstanceUuid" instead of
"NicUuidToVmUuidResolver" and "vmNicUuid" so the resolver uses the existing
vmInstanceUuid field directly.
In
`@header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java`:
- Around line 46-52: The example factory
APICleanupVmInstanceMetadataEvent.__example__() does not set the inherited
APIEvent.success flag; update the method to set evt.setSuccess(true) (or
evt.success = true if using a public field) before returning so the example
shows a successful APIEvent, referencing
APICleanupVmInstanceMetadataEvent.__example__() and the APIEvent.success
property.
In
`@header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java`:
- Around line 26-29: The __example__() in class
APIGetVmInstanceMetadataFromPrimaryStorageEvent returns an empty event; populate
its metadata field with a realistic example so API docs show sample data. Update
APIGetVmInstanceMetadataFromPrimaryStorageEvent.__example__() to call the
class's metadata setter (e.g., evt.setMetadata(...)) and provide a
representative map/collection of entries (for example keys like "user-data",
"meta-data", or a cloud-init payload and corresponding values) or a small
JSON-like map to illustrate structure and types.
In
`@header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy`:
- Around line 12-21: The request block in
APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy currently has an
empty request description (desc """""") — add a short, meaningful description
string to the request's desc field inside the rest.request block (for the
APIGetVmInstanceMetadataFromPrimaryStorageMsg documentation) to improve API docs
completeness and readability; keep it concise and aligned with the top-level
desc content.
- Around line 33-41: The API doc column entries for the List-typed fields (the
"systemTags" and "userTags" column blocks in
APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy) should declare
the list element type if the doc framework supports it; update the two column
definitions to use a typed list (e.g., List<String> or equivalent syntax
supported by the doc generator) for the "type" attribute so the generated API
docs show element types rather than an untyped List, keeping the rest of the
column attributes unchanged.
In
`@header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java`:
- Around line 18-34: Update APIUpdateVmInstanceMetadataMsg to implement the
APIAuditor interface and add an audit(APIMessage msg) implementation that
returns an audit result listing the affected VM UUIDs (use the vmUuids field)
and the resource type VmInstanceVO; ensure the audit method handles null/empty
vmUuids gracefully and constructs the standard audit response used by other
messages in the same package (mirror the pattern from
APIConvertVmInstanceToTemplatedVmInstanceMsg: implement APIAuditor, add
audit(...) returning the affected resource UUID(s) and VmInstanceVO as the
resource type).
In `@header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java`:
- Around line 3-7: The field name "vo" is an unclear abbreviation; rename the
field (e.g., change ResourceMetadata.vo to valueObjectJson or voData) and update
all corresponding accessor methods (getVo/setVo →
getValueObjectJson/setValueObjectJson or getVoData/setVoData) and any usages in
the class or callers (constructors, builders, serialization/deserialization
code) to use the new name so the intent is explicit and compilation remains
clean; ensure any JSON mapping annotations or reflection-based references are
updated accordingly.
In
`@header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java`:
- Around line 11-13: VmInstanceMetadataDTO has inconsistent types: snapshots,
snapshotGroups, snapshotGroupRefs are List<String> while volumes and nics use
typed metadata classes (VolumeResourceMetadata, ResourceMetadata); update the
class to either (A) change snapshots/snapshotGroups/snapshotGroupRefs to use a
dedicated metadata type consistent with VolumeResourceMetadata/ResourceMetadata,
or (B) add a clear class-level JavaDoc on VmInstanceMetadataDTO explaining that
those three fields intentionally store only UUID strings and why, referencing
the fields snapshots, snapshotGroups, snapshotGroupRefs and the existing
VolumeResourceMetadata and ResourceMetadata to make the design intent explicit
for future maintainers.
In `@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java`:
- Around line 3-16: Add Javadoc to the public enum VmMetadataErrors and each
enum constant to document meaning and usage; update the VmMetadataErrors
type-level comment to explain this enum is for VM metadata operation error codes
and for each constant (e.g., METADATA_INVALID_FORMAT,
METADATA_SCHEMA_VERSION_MISMATCH, METADATA_UUID_CONFLICT,
METADATA_STORAGE_NOT_SUPPORTED, METADATA_CROSS_STORAGE_FORBIDDEN,
METADATA_INSTALL_PATH_NOT_FOUND, METADATA_CACHE_VM_NOT_REGISTERABLE,
METADATA_VM_REGISTERING, METADATA_READ_CORRUPTED, METADATA_PAYLOAD_TOO_LARGE,
METADATA_PS_UNREACHABLE, METADATA_FEATURE_DISABLED) add a brief Javadoc
describing the error condition and typical trigger/handling guidance so the
public API is self-documenting.
In
`@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java`:
- Around line 3-8: 为 VmMetadataPathBuildExtensionPoint 接口和其四个方法补写准确的
Javadoc:在接口注释中说明这是跨主存储实现共享的公共契约并列出约定;为 getPrimaryStorageType()
注明返回值应是该扩展实现对应的主存储类型标识符;为 buildVmMetadataPath(String primaryStorageUuid, String
vmInstanceUuid) 说明应返回针对给定主存储 UUID 与 VM UUID 的完整元数据文件路径(示例格式或允许的前缀/分隔符);为
buildMetadataDir(String primaryStorageUuid) 说明应返回在该主存储下存放所有 VM
元数据的目录路径(是否以斜杠结尾需约定);为 validateMetadataPath(String primaryStorageUuid, String
path) 说明返回约定:当 path 合法返回 null;不合法时返回描述性错误信息(包括哪些检查要做,如路径必须在 buildMetadataDir
返回的目录范围内、无非法字符等)。在注释中引用方法签名以便实现者遵循一致的行为约定。
In
`@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java`:
- Around line 7-9: 为 VmMetadataPathReplacementExtensionPoint 接口和其方法添加完整的 Javadoc
注释:在接口声明上写明该扩展点的用途,然后为 getPrimaryStorageType() 和
calculatePathReplacements(String targetPsUuid, List<String> allOldPaths)
分别写明方法用途、参数含义(例如 targetPsUuid 是目标主存储 UUID,allOldPaths
是要替换的老路径列表)和返回值含义(PathReplacementResult
表示替换结果及可能的错误或映射),同时注明实现者的期望行为与线程/异常约束,以便调用者和实现者明确契约。
In
`@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java`:
- Around line 5-10: 为接口 VmMetadataResourcePersistExtensionPoint 及其方法
getPrimaryStorageType、afterVolumePersist、afterSnapshotPersist 添加
Javadoc,说明每个回调的调用时机(如“在资源信息持久化到数据库后立即调用,由持久化流程主动触发”)、参数语义和约定:明确 resourceType
的取值或参考枚举,size 的单位为字节(bytes),now
表示由调用方在持久化时传入的事件时间(Timestamp,建议使用持久化时的数据库/系统时间),并标注回调方法是否必须实现幂等(如要求幂等或说明不保证幂等);同时在接口注释中列出实现者需注意的线程/事务上下文(例如回调在持久化事务之后执行且不在同一事务中)。
In `@header/src/main/java/org/zstack/header/vm/VmInstanceState.java`:
- Around line 194-198: The Registering state transition block currently
registers only three specific events (using Registering and new Transaction(...)
with VmInstanceStateEvent.stopped/destroying/destroyed ->
VmInstanceState.Stopped/Destroying/Destroyed) and lacks a fallback for unmapped
events which leads to a CloudRuntimeException; add a default/unknown mapping for
Registering (e.g., mapping an UNKNOWN or NoState transition to a safe target
such as VmInstanceState.Unknown or VmInstanceState.NoState consistent with other
states' fallback handling) so that any unexpected VmInstanceStateEvent falling
into Registering is handled gracefully instead of throwing; locate the
Registering.transactions(...) call and add the extra Transaction(...) entry for
the unknown/noState fallback using the same pattern as the other Transaction
registrations.
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.java`:
- Around line 346-363: Update the simulator endpoints getVmInstanceMetadata and
scanVmMetadata to allow injecting test responses from the simulator config: add
configurable response holders on the existing config (e.g., a predefined
GetVmInstanceMetadataRsp or a list/map of GetVmInstanceMetadataRsp entries and
similarly for ScanVmMetadataRsp), and in the methods (getVmInstanceMetadata,
scanVmMetadata) if a configured response exists, populate the rsp from that
config (respecting any filter criteria from the incoming
GetVmInstanceMetadataCmd/ScanVmMetadataCmd such as classification or vm
identifiers) before calling reply(entity, rsp); otherwise keep the current empty
rsp behavior. Ensure you reference the existing config fields used
(config.getVmInstanceMetadataCmds, config.scanVmMetadataCmds) and the response
types (GetVmInstanceMetadataRsp, ScanVmMetadataRsp) when adding and reading the
injected test data.
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java`:
- Around line 37-120: Extract the shared metadata path logic into a common
helper or abstract base (e.g., MetadataPathHelper or
AbstractVmMetadataExtension) and have LocalStorageVmMetadataExtension and
NfsVmMetadataExtension delegate to it: move the implementations of
buildMetadataDir/buildVmMetadataPath/validateMetadataPath/calculatePathReplacements
(the validation, prefix extraction, normalization and replacement algorithms
that reference VmInstanceMetadataConstants and normalizeBaseDir) into the
helper/base; keep only storage-specific pieces (how to obtain baseDir/url) in
LocalStorageVmMetadataExtension (e.g., a single method like
resolveBaseDir(primaryStorageUuid)) and have the helper call that to build final
paths and replacements; ensure normalizeBaseDir remains available to the helper
and that PathReplacementResult population and warnings stay consistent.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java`:
- Around line 1988-2086: The four handlers
(handle(GetVmInstanceMetadataFromPrimaryStorageMsg),
handle(ScanVmInstanceMetadataFromPrimaryStorageMsg),
handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg),
handle(RebaseVolumeBackingFileOnPrimaryStorageMsg)) duplicate the "select
connected host + getBackendByHostUuid + backend.handle(...) with unified fail
reply" logic; extract a private helper (e.g. dispatchToBackend(msg,
replyCreator, msgClass, ReturnValueCompletionFactory) or a typed generic method)
that calls factory.getConnectedHostForOperation(getSelfInventory()), picks
hostUuid, obtains NfsPrimaryStorageBackend via getBackendByHostUuid(hostUuid),
and invokes backend.handle(...) wiring success->bus.reply(msg, r) and
fail->reply.setError(errorCode); then refactor each of the four handlers to call
this helper with the appropriate message and reply types and remove the
duplicated code paths (keep using ReturnValueCompletion for async callbacks).
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java`:
- Around line 2157-2162: The reply for
ScanVmInstanceMetadataFromPrimaryStorageReply in NfsPrimaryStorageKVMBackend
currently leaves VmInstanceMetadata unset when rsp.metadataEntries is null;
change the handling in the block (the lambda shown in
NfsPrimaryStorageKVMBackend) to always call r.setVmInstanceMetadata(...) and
pass an empty list (e.g. Collections.emptyList() or new ArrayList<>()) when
rsp.metadataEntries == null, and when non-null keep the existing hostUuid
assignment and set that list; this makes the NFS backend consistent with the
LocalStorage implementation and avoids nulls for callers.
In
`@sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java`:
- Around line 6-11: The generated Result class
ScanVmInstanceMetadataFromPrimaryStorageResult exposes a raw java.util.List
field vmInstanceMetadata causing loss of generic type information; update the
SDK generator template SdkDataStructureGenerator.groovy so when it emits
collection-typed fields (like vmInstanceMetadata) it preserves and emits the
original generic parameter from the source reply type
(ScanVmInstanceMetadataFromPrimaryStorageReply) (e.g.,
List<VmMetadataScanEntry>) rather than printing only the raw collection type,
ensuring all generated Result classes include correct generics.
In `@testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy`:
- Around line 604-618: 当前对 LocalStorageKvmBackend
的元数据模拟器(标识符:WRITE_VM_METADATA_PATH、GET_VM_INSTANCE_METADATA_PATH、SCAN_VM_METADATA_PATH、CLEANUP_VM_METADATA_PATH)仅返回空响应,建议在这些
simulator 处理器中补充与已有端点(例如 CREATE_VOLUME_FROM_CACHE_PATH、DELETE_BITS_PATH)一致的 VFS
hook 调用以模拟真实文件系统行为:在 WRITE_VM_METADATA_PATH 中将接收到的数据写入 VFS;在
GET_VM_INSTANCE_METADATA_PATH 中从 VFS 读取并返回内容;在 SCAN_VM_METADATA_PATH 中列出 VFS
中的元数据条目;在 CLEANUP_VM_METADATA_PATH 中删除对应的 VFS 条目,从而支持后续需要验证实际读写的测试场景(定位
simulator 处理器即可修改实现)。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| String path = msg.getMetadataPath(); | ||
| if (path == null || path.isEmpty()) { | ||
| throw new ApiMessageInterceptionException(argerr("metadataPath cannot be empty")); | ||
| } |
There was a problem hiding this comment.
把纯空白的 metadataPath 也当成非法输入。
现在只拦了 null/"",像 " " 这样的值仍会继续进入后端扩展,导致校验口径依赖具体主存储实现。
✍️ 建议修改
String path = msg.getMetadataPath();
- if (path == null || path.isEmpty()) {
+ if (path == null || path.trim().isEmpty()) {
throw new ApiMessageInterceptionException(argerr("metadataPath cannot be empty"));
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java`
around lines 1330 - 1333, 在 VmInstanceApiInterceptor 中对 msg.getMetadataPath()
做空白字符串校验:当前只判断 null/"",需将纯空白(例如 " ")也视为非法。修改对 metadataPath 的检查(在使用
msg.getMetadataPath() 的位置)为在判空前先 trim 或使用 isBlank 等方式(例如 check path == null ||
path.trim().isEmpty()),并在不合法时仍抛出
ApiMessageInterceptionException(argerr("metadataPath cannot be empty"))
保持原错误类型及信息。
| CONSTRAINT `fkVmMetadataDirtyVOVmInstanceEO` FOREIGN KEY (`vmInstanceUuid`) REFERENCES `VmInstanceEO` (`uuid`) ON DELETE CASCADE, | ||
| CONSTRAINT `fkVmMetadataDirtyVOManagementNodeVO` FOREIGN KEY (`managementNodeUuid`) REFERENCES `ManagementNodeVO` (`uuid`) ON DELETE SET NULL |
There was a problem hiding this comment.
外键引用建议显式带上 zstack schema。
这个目录里的升级脚本约定是固定使用 zstack schema;这里的 REFERENCES \VmInstanceEO`/`ManagementNodeVO`` 省略 schema,后续在非默认库上下文执行时可读性和一致性都差一些。
🛠️ 建议修改
- CONSTRAINT `fkVmMetadataDirtyVOVmInstanceEO` FOREIGN KEY (`vmInstanceUuid`) REFERENCES `VmInstanceEO` (`uuid`) ON DELETE CASCADE,
- CONSTRAINT `fkVmMetadataDirtyVOManagementNodeVO` FOREIGN KEY (`managementNodeUuid`) REFERENCES `ManagementNodeVO` (`uuid`) ON DELETE SET NULL
+ CONSTRAINT `fkVmMetadataDirtyVOVmInstanceEO` FOREIGN KEY (`vmInstanceUuid`) REFERENCES `zstack`.`VmInstanceEO` (`uuid`) ON DELETE CASCADE,
+ CONSTRAINT `fkVmMetadataDirtyVOManagementNodeVO` FOREIGN KEY (`managementNodeUuid`) REFERENCES `zstack`.`ManagementNodeVO` (`uuid`) ON DELETE SET NULL
...
- CONSTRAINT `fkVmMetadataFingerprintVOVmInstanceEO` FOREIGN KEY (`vmInstanceUuid`) REFERENCES `VmInstanceEO` (`uuid`) ON DELETE CASCADE
+ CONSTRAINT `fkVmMetadataFingerprintVOVmInstanceEO` FOREIGN KEY (`vmInstanceUuid`) REFERENCES `zstack`.`VmInstanceEO` (`uuid`) ON DELETE CASCADEBased on learnings, in conf/db/upgrade scripts the schema is fixed as zstack, and referenced tables should be written with the zstack qualifier.
Also applies to: 25-25
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@conf/db/upgrade/V5.0.0__schema.sql` around lines 12 - 13, 在外键定义里将被引用表显式加上
zstack schema:把 CONSTRAINT `fkVmMetadataDirtyVOVmInstanceEO` 的 REFERENCES
`VmInstanceEO` (`uuid`) 修改为 REFERENCES `zstack`.`VmInstanceEO` (`uuid`),并把
CONSTRAINT `fkVmMetadataDirtyVOManagementNodeVO` 的 REFERENCES `ManagementNodeVO`
(`uuid`) 修改为 REFERENCES `zstack`.`ManagementNodeVO`
(`uuid`),确保两个外键(fkVmMetadataDirtyVOVmInstanceEO,
fkVmMetadataDirtyVOManagementNodeVO)都使用 zstack. 前缀以保持 conf/db/upgrade
目录脚本的一致性和在非默认库上下文的可读性。
| for (String marker : STORAGE_PATH_MARKERS) { | ||
| int idx = path.indexOf(marker); | ||
| if (idx >= 0) { | ||
| return path.substring(0, idx + 1); | ||
| } | ||
| } |
There was a problem hiding this comment.
extractOldPrefix 在多标记路径场景下可能截取错误前缀。
当前是按 marker 列表顺序返回,不是按路径最早出现位置返回;若路径同时含多个 marker,会得到不稳定结果。
可参考修复
public static String extractOldPrefix(String path) {
if (path == null || !path.startsWith("/")) {
return null;
}
- for (String marker : STORAGE_PATH_MARKERS) {
- int idx = path.indexOf(marker);
- if (idx >= 0) {
- return path.substring(0, idx + 1);
- }
- }
- return null;
+ int earliest = Integer.MAX_VALUE;
+ for (String marker : STORAGE_PATH_MARKERS) {
+ int idx = path.indexOf(marker);
+ if (idx >= 0 && idx < earliest) {
+ earliest = idx;
+ }
+ }
+ return earliest == Integer.MAX_VALUE ? null : path.substring(0, earliest + 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.
| for (String marker : STORAGE_PATH_MARKERS) { | |
| int idx = path.indexOf(marker); | |
| if (idx >= 0) { | |
| return path.substring(0, idx + 1); | |
| } | |
| } | |
| public static String extractOldPrefix(String path) { | |
| if (path == null || !path.startsWith("/")) { | |
| return null; | |
| } | |
| int earliest = Integer.MAX_VALUE; | |
| for (String marker : STORAGE_PATH_MARKERS) { | |
| int idx = path.indexOf(marker); | |
| if (idx >= 0 && idx < earliest) { | |
| earliest = idx; | |
| } | |
| } | |
| return earliest == Integer.MAX_VALUE ? null : path.substring(0, earliest + 1); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java`
around lines 19 - 24, The extractOldPrefix logic incorrectly returns the prefix
based on the first marker in STORAGE_PATH_MARKERS rather than the earliest
marker occurrence in the given path, producing unstable results when multiple
markers are present; update extractOldPrefix to scan all markers
(STORAGE_PATH_MARKERS), track the smallest non-negative index (e.g., minIdx
initialized to Integer.MAX_VALUE), and after the loop if minIdx !=
Integer.MAX_VALUE return path.substring(0, minIdx + 1) (otherwise preserve
original fallback behavior), ensuring you reference the existing
variables/methods extractOldPrefix, STORAGE_PATH_MARKERS and path when making
the change.
header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.java
Show resolved
Hide resolved
| }).run(new WhileDoneCompletion(msg) { | ||
| @Override | ||
| public void done(ErrorCodeList errorCodeList) { | ||
| if (!errorCodeList.getCauses().isEmpty() && errorCodeList.getCauses().size() == connectedHostUuids.size()) { | ||
| reply.setError(operr("failed to scan vm metadata from all hosts on local primary storage[uuid:%s], causes: %s", | ||
| self.getUuid(), errorCodeList)); | ||
| } else { | ||
| reply.setVmInstanceMetadata(new ArrayList<>(allSummaries)); | ||
| } | ||
| bus.reply(msg, reply); |
There was a problem hiding this comment.
不要把部分扫描结果当成成功返回。
本地存储的元数据分散在各个 host 上,这里只在“全部 host 都失败”时才返回 error,会把一个不完整的扫描结果伪装成成功。后续如果调用方基于这个结果做注册或清理,很容易漏掉失败 host 上的元数据。要么任一 host 失败就整体失败,要么在 reply 里显式标记 partial 并带上失败 host。
💡 更安全的最小修正
- if (!errorCodeList.getCauses().isEmpty() && errorCodeList.getCauses().size() == connectedHostUuids.size()) {
- reply.setError(operr("failed to scan vm metadata from all hosts on local primary storage[uuid:%s], causes: %s",
+ if (!errorCodeList.getCauses().isEmpty()) {
+ reply.setError(operr("failed to scan vm metadata from one or more hosts on local primary storage[uuid:%s], causes: %s",
self.getUuid(), errorCodeList));
} else {
reply.setVmInstanceMetadata(new ArrayList<>(allSummaries));
}📝 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.
| }).run(new WhileDoneCompletion(msg) { | |
| @Override | |
| public void done(ErrorCodeList errorCodeList) { | |
| if (!errorCodeList.getCauses().isEmpty() && errorCodeList.getCauses().size() == connectedHostUuids.size()) { | |
| reply.setError(operr("failed to scan vm metadata from all hosts on local primary storage[uuid:%s], causes: %s", | |
| self.getUuid(), errorCodeList)); | |
| } else { | |
| reply.setVmInstanceMetadata(new ArrayList<>(allSummaries)); | |
| } | |
| bus.reply(msg, reply); | |
| }).run(new WhileDoneCompletion(msg) { | |
| `@Override` | |
| public void done(ErrorCodeList errorCodeList) { | |
| if (!errorCodeList.getCauses().isEmpty()) { | |
| reply.setError(operr("failed to scan vm metadata from one or more hosts on local primary storage[uuid:%s], causes: %s", | |
| self.getUuid(), errorCodeList)); | |
| } else { | |
| reply.setVmInstanceMetadata(new ArrayList<>(allSummaries)); | |
| } | |
| bus.reply(msg, reply); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java`
around lines 3491 - 3500, In LocalStorageBase inside the
WhileDoneCompletion.done(ErrorCodeList) block, don't treat partial host failures
as success; if errorCodeList.getCauses() is non-empty (i.e. any host failed)
return an overall error via reply.setError(...) instead of returning a partial
list—include the failed host UUIDs and the errorCodeList in the message for
debugging; ensure only when errorCodeList.getCauses().isEmpty() you call
reply.setVmInstanceMetadata(...). Use the existing symbols errorCodeList,
connectedHostUuids, reply.setError and reply.setVmInstanceMetadata to locate and
implement this change.
| try { | ||
| String hostUuid = getHostUuidFromVolume(msg.getRootVolumeUuid()); | ||
| if (hostUuid == null || hostUuid.isEmpty()) { | ||
| reply.setError(operr("no host found for volume[uuid:%s]", msg.getRootVolumeUuid())); | ||
| bus.reply(msg, reply); | ||
| chain.next(); | ||
| return; | ||
| } | ||
|
|
||
| final NfsPrimaryStorageBackend backend = getBackendByHostUuid(hostUuid); | ||
| backend.handle(msg, hostUuid, new ReturnValueCompletion<UpdateVmInstanceMetadataOnPrimaryStorageReply>(msg, chain) { | ||
| @Override | ||
| public void success(UpdateVmInstanceMetadataOnPrimaryStorageReply r) { | ||
| bus.reply(msg, r); | ||
| chain.next(); | ||
| } | ||
|
|
||
| @Override | ||
| public void fail(ErrorCode errorCode) { | ||
| reply.setError(errorCode); | ||
| bus.reply(msg, reply); | ||
| chain.next(); | ||
| } | ||
| }); | ||
| } catch (Exception e) { | ||
| reply.setError(operr("unexpected error updating vm metadata on NFS: %s", e.getMessage())); | ||
| bus.reply(msg, reply); | ||
| chain.next(); | ||
| } |
There was a problem hiding this comment.
这里不要把所有异常都改写成通用 operr。
这个 catch (Exception) 会把 OperationFailureException 之类带着原始 ErrorCode 的异常降级成一条普通字符串,既丢掉错误码/details,也丢掉堆栈日志。后续如果上层按错误码做重试或分流,这里会把语义冲掉。
🛠️ 建议修改
- } catch (Exception e) {
- reply.setError(operr("unexpected error updating vm metadata on NFS: %s", e.getMessage()));
- bus.reply(msg, reply);
- chain.next();
- }
+ } catch (OperationFailureException e) {
+ reply.setError(e.getErrorCode());
+ bus.reply(msg, reply);
+ chain.next();
+ } catch (Exception e) {
+ logger.warn(String.format("failed to update vm metadata on NFS primary storage[uuid:%s]", self.getUuid()), e);
+ reply.setError(operr("failed to update vm metadata on NFS primary storage[uuid:%s]", self.getUuid()));
+ bus.reply(msg, reply);
+ chain.next();
+ }As per coding guidelines, 捕获异常应仅用于处理真正的意外情况,不应将异常逻辑当作正常流程控制。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java`
around lines 1950 - 1978, 不要把所有异常一律包装成 operr——在 NfsPrimaryStorage 的该 try/catch
中(调用 getHostUuidFromVolume, getBackendByHostUuid, backend.handle 和使用
ReturnValueCompletion<UpdateVmInstanceMetadataOnPrimaryStorageReply>
的地方),改为区分异常类型:如果捕获到的是带原始 ErrorCode 的异常(例如 OperationFailureException 或能返回
ErrorCode 的异常),从异常中取出 ErrorCode 并用 reply.setError(thatErrorCode) 返回;否则保留当前的
reply.setError(operr(...)) 逻辑,但同时用 logger.error/exception 记录完整堆栈信息以便排查,并确保仍然调用
bus.reply(msg, reply) 和 chain.next()。
| private String resolveBaseDir(String primaryStorageUuid) { | ||
| String baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.mountPath).eq(PrimaryStorageVO_.uuid, primaryStorageUuid).findValue(); | ||
| if (baseDir == null) { | ||
| baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.url).eq(PrimaryStorageVO_.uuid, primaryStorageUuid).findValue(); | ||
| } | ||
| if (baseDir == null) { | ||
| throw new CloudRuntimeException(String.format("cannot find mountPath or url for NFS primary storage[uuid:%s]", primaryStorageUuid)); | ||
| } | ||
| return baseDir.endsWith("/") ? baseDir.substring(0, baseDir.length() - 1) : baseDir; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) 确认 NFS 主存储里 url / mountPath 的语义
rg -n -C2 --type=java '\b(PrimaryStorageVO_\.url|PrimaryStorageVO_\.mountPath|getUrl\(|getMountPath\(|setUrl\(|setMountPath\()'
echo
# 2) 确认 metadataPath 最终是否被 NFS backend 当作宿主机本地文件路径使用
rg -n -C2 --type=java '\b(metadataPath|metadataDir|mountPath)\b' plugin/nfsPrimaryStorage
echo
# 预期结果:
# - 如果 url 被写成 NFS export / 远端地址,而真正可读写的宿主机路径来自 mountPath,
# 那么这里不应回退到 url。
# - 如果 metadataPath 直接被 agent 当作文件路径下发,回退到 url 会导致路径不可访问。Repository: MatheMatrix/zstack
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 查找 NFS primary storage 的初始化工厂代码
echo "=== NFS Primary Storage Factory ==="
fd -e java --type f -path '*nfsPrimaryStorage*' | head -20
echo
echo "=== Checking NFS factory for mountPath initialization ==="
fd -e java --type f -path '*nfsPrimaryStorage*Factory*' -o -path '*nfsPrimaryStorage*Impl*' | xargs -I {} sh -c '
if [ -f "{}" ]; then
echo "File: {}"
grep -n "mountPath\|setMountPath\|setUrl" {} | head -10
fi
'
echo
echo "=== Check if NfsVmMetadataExtension is the only place with this fallback ==="
rg -n "select.*mountPath.*findValue" --type=java -A3 -B1
echo
echo "=== Verify how metadataPath is ultimately used ==="
rg -n "metadataPath" plugin/nfsPrimaryStorage --type=java -B2 -A2Repository: MatheMatrix/zstack
Length of output: 283
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 查找 NFS primary storage 的所有 Java 文件
echo "=== NFS Primary Storage Java Files ==="
find plugin/nfsPrimaryStorage -name "*.java" -type f | sort
echo
echo "=== Check NFS Factory for mountPath/url initialization ==="
find plugin/nfsPrimaryStorage -name "*Factory*" -o -name "*Impl*" | while read f; do
if [ -f "$f" ]; then
echo "=== $f ==="
grep -n "mountPath\|setMountPath\|setUrl\|getUrl" "$f" | head -15
fi
done
echo
echo "=== NFS specific: how are url and mountPath set? ==="
rg -n "setMountPath|setUrl" plugin/nfsPrimaryStorage --type=java -B3 -A1
echo
echo "=== How is metadataPath used in NFS backend? ==="
rg -n "metadataPath|metadataDir" plugin/nfsPrimaryStorage --type=java -B2 -A2Repository: MatheMatrix/zstack
Length of output: 21751
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify the second concern: calculatePathReplacements also has the same fallback
echo "=== NfsVmMetadataExtension.calculatePathReplacements (lines 80-83) ==="
sed -n '80,90p' plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java
echo
echo "=== Check buildMetadataDir method ==="
sed -n '39,51p' plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java
echo
echo "=== Full NfsVmMetadataExtension file to see complete context ==="
wc -l plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.javaRepository: MatheMatrix/zstack
Length of output: 1653
确认 NFS 主存储的 url 和 mountPath 语义差异:必要时应直接失败而非回退
resolveBaseDir() 以及 calculatePathReplacements() (80-83 行)都采用了相同的 fallback 逻辑:优先读取 mountPath,缺失时回退到 url。但在 NFS 场景下:
url保存的是 NFS export 地址(如192.168.0.25:/share/nfs)mountPath保存的是宿主机本地挂载路径(如/mnt/pss/prim-<uuid>)
这两者语义完全不同。buildMetadataDir / buildVmMetadataPath / calculatePathReplacements 生成的路径最终通过 WriteVmMetadataCmd.metadataPath / ScanVmMetadataCmd.metadataDir 等发往 agent 侧执行本地文件读写操作。若回退到 url,将产生 192.168.0.25:/share/nfs/vm-metadata/... 这类无法直接访问的路径,导致 metadata 扫描、写入、以及 replacement 逻辑失败。
虽然 NfsPrimaryStorageFactory 在创建时总是设置 mountPath,但从防御性编程角度,当 mountPath 缺失时更稳妥的做法是直接抛出异常或禁用相关功能,而非假设 url 可作为本地路径使用。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java`
around lines 29 - 37, The current fallback in resolveBaseDir (and likewise in
calculatePathReplacements) erroneously treats PrimaryStorageVO.url as a local
mount path causing agent-side file operations to use NFS export URLs; change the
logic to require mountPath only: remove the fallback to url, and if mountPath is
null throw a CloudRuntimeException with clear context (including
primaryStorageUuid) so metadata operations (buildMetadataDir,
buildVmMetadataPath) fail fast; also update any callers/validators (or note
NfsPrimaryStorageFactory behavior) to ensure mountPath is set before allowing
metadata-related commands (WriteVmMetadataCmd.metadataPath /
ScanVmMetadataCmd.metadataDir) to be used.
ec40b4b to
dba8f07
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (2)
plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java (1)
1974-1978:⚠️ Potential issue | 🟠 Major异常处理丢失原始错误码和堆栈信息。
此
catch (Exception)块会将OperationFailureException等带有原始ErrorCode的异常降级为通用字符串错误,导致:
- 丢失错误码/details,影响上层按错误码做重试或分流
- 丢失堆栈日志,不利于问题排查
🛠️ 建议修改
- } catch (Exception e) { - reply.setError(operr("unexpected error updating vm metadata on NFS: %s", e.getMessage())); - bus.reply(msg, reply); - chain.next(); - } + } catch (OperationFailureException e) { + reply.setError(e.getErrorCode()); + bus.reply(msg, reply); + chain.next(); + } catch (Exception e) { + logger.warn(String.format("failed to update vm metadata on NFS primary storage[uuid:%s]", self.getUuid()), e); + reply.setError(operr("failed to update vm metadata on NFS primary storage[uuid:%s]", self.getUuid())); + bus.reply(msg, reply); + chain.next(); + }As per coding guidelines, 捕获异常时需严格匹配期望的异常类型或其父类,避免捕获错误的异常类型。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java` around lines 1974 - 1978, The catch block in NfsPrimaryStorage is swallowing rich error information; change the broad "catch (Exception e)" to explicitly handle OperationFailureException (or its known subclasses) first: when e is an OperationFailureException extract and pass its original ErrorCode into reply.setError(...) (preserving the original code/details), then call bus.reply(msg, reply) and chain.next(); for any truly unexpected Exception keep a generic operr(...) but log the full stacktrace (logger.error("...", e)) before replying so debugging info is retained; update the catch structure around the reply.setError/operr, bus.reply, and chain.next calls accordingly.plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java (1)
3494-3499:⚠️ Potential issue | 🟠 Major不要把部分扫描结果当成成功返回。
这里只在“全部 host 都失败”时才返回 error;只要还有一个 host 成功,就会把聚合结果当成完整结果返回,而且 reply 里没有任何
partial或失败 host 信息。后续如果调用方据此继续做注册/清理,会静默漏掉失败 host 上的 metadata。建议改成“任一 host 失败即整体失败”,或者在 reply 里显式标记部分成功并携带失败 host 列表。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java` around lines 3494 - 3499, The current logic in LocalStorageBase that sets reply.error only when errorCodeList.getCauses().size() == connectedHostUuids.size() allows partial failures to be treated as fully successful; change the behavior so that any host failure causes an overall failure or explicitly mark partial results: either (A) if !errorCodeList.getCauses().isEmpty() then call reply.setError(...) with the aggregated error (replace the current size check and use errorCodeList and self.getUuid() in the message to preserve context), or (B) modify the reply to include a partial flag and a failed host list (e.g., attach errorCodeList/connectedHostUuids info alongside reply.setVmInstanceMetadata(new ArrayList<>(allSummaries))). Ensure you update the code paths that currently call reply.setVmInstanceMetadata and reply.setError to reflect the chosen approach so callers can detect partial failures.
🧹 Nitpick comments (4)
header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.java (1)
12-14: 建议添加显式的@Table(name = "...")属性根据项目约定,应避免依赖 JPA 默认命名策略,建议显式指定表名以提高代码可读性和可维护性。
♻️ 建议修改
`@Entity` -@Table +@Table(name = "VmMetadataDirtyVO") public class VmMetadataDirtyVO {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.java` around lines 12 - 14, 当前实体类 VmMetadataDirtyVO 使用了 `@Table` 无 name 属性,请按照项目约定显式指定表名以避免依赖 JPA 默认命名策略:在 VmMetadataDirtyVO 类上将 `@Table` 替换为 `@Table`(name = "<明确的表名>"),确保表名遵循项目命名约定(例如 vm_metadata_dirty 或相应现有表名),并保持与数据库实际表名一致以提高可读性和可维护性。header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java (1)
8-15: 建议将uuid作为路径参数而非查询参数。根据编码规范,当 path 中引用消息类变量时,应使用
{variableName}格式。当前uuid是针对特定 PrimaryStorage 资源的操作,将其放入路径中更符合 RESTful 设计原则,也便于 API 发现和理解层级关系。♻️ 建议修改
`@RestRequest`( - path = "/primary-storage/vm-instances/metadata/scan", + path = "/primary-storage/{uuid}/vm-instances/metadata/scan", method = HttpMethod.GET, responseClass = APIScanVmInstanceMetadataFromPrimaryStorageEvent.class ) public class APIScanVmInstanceMetadataFromPrimaryStorageMsg extends APIMessage implements PrimaryStorageMessage { - `@APIParam`(resourceType = PrimaryStorageVO.class) + `@APIParam`(resourceType = PrimaryStorageVO.class, checkAccount = true) private String uuid;As per coding guidelines: "当 path 中引用消息类变量时,使用
{variableName}格式。"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java` around lines 8 - 15, Update the REST path to make uuid a path parameter by changing the `@RestRequest` path to include {uuid} (e.g. "/primary-storage/{uuid}/vm-instances/metadata/scan") so the APIScanVmInstanceMetadataFromPrimaryStorageMsg.uuid is bound from the path; keep the existing `@APIParam`(resourceType = PrimaryStorageVO.class) on the uuid field and ensure no other code expects it as a query param. Ensure the responseClass and HttpMethod remain unchanged.compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java (1)
115-127: 在 GC 任务中应验证rootVolumeUuid的有效性。
submitGC方法将rootVolumeUuid传递给 GC 任务但不进行验证。在 LocalStorage 场景中,如果卷被删除,LocalStorageBase.handle()会尝试通过getHostUuidByResourceUuid()查询该卷以确定主机,这可能失败。虽然代码现已捕获异常并返回错误,但在 GC 触发前应像检查primaryStorageUuid和hostUuid一样,在CleanupVmInstanceMetadataOnPrimaryStorageGC.triggerNow()中添加rootVolumeUuid的存在性验证,以更早发现问题。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java` around lines 115 - 127, The GC task currently receives rootVolumeUuid without validation; update CleanupVmInstanceMetadataOnPrimaryStorageGC.triggerNow() to validate rootVolumeUuid existence just like primaryStorageUuid and hostUuid are checked: verify the volume/resource exists (e.g., via the same mechanism used for getHostUuidByResourceUuid or existing datastore lookups) and return/throw an error or short-circuit the GC if rootVolumeUuid is missing or the lookup fails, so submitGC (and its caller) fails fast when the root volume has been deleted.plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java (1)
3854-3896: 建议把这 4 个 metadata/rebase 代理 handler 抽成小 helper。现在都在重复“组装 cmd →
httpCall()→ 映射 reply/透传 error”的样板;后面如果统一补 tracing、审计或错误包装,容易漏改。抽成proxyEmptyReply(...)/proxyMappedReply(...)之类会更稳。As per coding guidelines “每个模块、类、方法应只承担单一的责任。若某个逻辑过于复杂,应考虑拆分出独立类来处理。”
Also applies to: 3923-3962
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java` around lines 3854 - 3896, These four metadata/rebase handler blocks duplicate the pattern "build cmd → httpCall(...) → map success/fail", so extract two small helpers (e.g., proxyEmptyReply(...) and proxyMappedReply(...)) that take the hostUuid, cmd object, target path constant, response class and a mapping function (or target reply class) to centralize httpCall and success/fail handling; update the handlers for UpdateVmInstanceMetadataOnPrimaryStorageMsg and GetVmInstanceMetadataFromPrimaryStorageMsg to construct WriteVmMetadataCmd/GetVmInstanceMetadataCmd and then call the new helpers instead of calling httpCall and inlining WriteVmMetadataRsp/GetVmInstanceMetadataRsp -> UpdateVmInstanceMetadataOnPrimaryStorageReply/GetVmInstanceMetadataFromPrimaryStorageReply mapping, so tracing/audit/error wrapping can be added in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@compute/src/main/java/org/zstack/compute/vm/CleanupVmInstanceMetadataOnPrimaryStorageGC.java`:
- Around line 59-68: The current run(MessageReply reply) in
CleanupVmInstanceMetadataOnPrimaryStorageGC blindly calls completion.fail()
which causes TimeBasedGarbageCollector to reschedule forever; update the error
handling in run(...) (class CleanupVmInstanceMetadataOnPrimaryStorageGC, method
run) to inspect reply.getError() (e.g. error code or type) and call
completion.cancel() for permanent errors (invalid path, permission denied,
not-found) while keeping completion.fail() for transient errors, or
alternatively implement a retry limit tied to this GC task (store/increment a
retry counter and cancel after N attempts) using vmUuid/primaryStorageUuid to
identify the task.
In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java`:
- Around line 73-80: The catch block in VmExpungeMetadataFlow around the call to
buildVmMetadataPath currently logs and skips cleanup, which prevents retry via
GC; modify the exception handling to also enqueue a GC retry by calling the
existing submitGC routine (use the same parameters used later: psUuid, vmUuid,
rootVolumeUuid, metadataPath, hostUuid) before invoking trigger.next(), or
alternatively narrow the catch to expected exceptions; update the catch in the
method containing buildVmMetadataPath to submitGC(psUuid, vmUuid,
rootVolumeUuid, metadataPath, hostUuid) so failed path construction will be
retried by GC.
In `@header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java`:
- Line 14: The `@MetadataImpact` annotation on APIDeleteVmBootModeMsg uses an
invalid resolver name "VmUuidDirectResolver"; update this to a valid Spring bean
that implements VmUuidFromApiResolver (or register such a bean) so runtime
metadata resolution works: either implement a class that implements
VmUuidFromApiResolver and register it as a Spring bean with the name used in the
resolver parameter, or change the resolver string to the existing registered
bean name; ensure the resolver value in the `@MetadataImpact` annotation matches
the bean name exactly (refer to APIDeleteVmBootModeMsg and the
VmUuidFromApiResolver interface to locate where to add or rename the bean).
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java`:
- Around line 98-115: validateMetadataPath currently calls
buildMetadataDir(primaryStorageUuid) which can throw CloudRuntimeException;
catch any exception (or null/empty result) from buildMetadataDir inside
validateMetadataPath and convert it into a readable validation error string
instead of letting it propagate. Specifically, wrap the call to
buildMetadataDir(primaryStorageUuid) in a try/catch, return a formatted message
like "metadataPath[...] cannot build metadataDir for primaryStorageUuid[...] :
<error>" on failure, then proceed with the existing prefix/suffix and uuidPart
regex checks using VmInstanceMetadataConstants.FILE_METADATA_SUFFIX so the
method only returns strings or null and never throws.
---
Duplicate comments:
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java`:
- Around line 3494-3499: The current logic in LocalStorageBase that sets
reply.error only when errorCodeList.getCauses().size() ==
connectedHostUuids.size() allows partial failures to be treated as fully
successful; change the behavior so that any host failure causes an overall
failure or explicitly mark partial results: either (A) if
!errorCodeList.getCauses().isEmpty() then call reply.setError(...) with the
aggregated error (replace the current size check and use errorCodeList and
self.getUuid() in the message to preserve context), or (B) modify the reply to
include a partial flag and a failed host list (e.g., attach
errorCodeList/connectedHostUuids info alongside reply.setVmInstanceMetadata(new
ArrayList<>(allSummaries))). Ensure you update the code paths that currently
call reply.setVmInstanceMetadata and reply.setError to reflect the chosen
approach so callers can detect partial failures.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java`:
- Around line 1974-1978: The catch block in NfsPrimaryStorage is swallowing rich
error information; change the broad "catch (Exception e)" to explicitly handle
OperationFailureException (or its known subclasses) first: when e is an
OperationFailureException extract and pass its original ErrorCode into
reply.setError(...) (preserving the original code/details), then call
bus.reply(msg, reply) and chain.next(); for any truly unexpected Exception keep
a generic operr(...) but log the full stacktrace (logger.error("...", e)) before
replying so debugging info is retained; update the catch structure around the
reply.setError/operr, bus.reply, and chain.next calls accordingly.
---
Nitpick comments:
In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java`:
- Around line 115-127: The GC task currently receives rootVolumeUuid without
validation; update CleanupVmInstanceMetadataOnPrimaryStorageGC.triggerNow() to
validate rootVolumeUuid existence just like primaryStorageUuid and hostUuid are
checked: verify the volume/resource exists (e.g., via the same mechanism used
for getHostUuidByResourceUuid or existing datastore lookups) and return/throw an
error or short-circuit the GC if rootVolumeUuid is missing or the lookup fails,
so submitGC (and its caller) fails fast when the root volume has been deleted.
In
`@header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java`:
- Around line 8-15: Update the REST path to make uuid a path parameter by
changing the `@RestRequest` path to include {uuid} (e.g.
"/primary-storage/{uuid}/vm-instances/metadata/scan") so the
APIScanVmInstanceMetadataFromPrimaryStorageMsg.uuid is bound from the path; keep
the existing `@APIParam`(resourceType = PrimaryStorageVO.class) on the uuid field
and ensure no other code expects it as a query param. Ensure the responseClass
and HttpMethod remain unchanged.
In `@header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.java`:
- Around line 12-14: 当前实体类 VmMetadataDirtyVO 使用了 `@Table` 无 name
属性,请按照项目约定显式指定表名以避免依赖 JPA 默认命名策略:在 VmMetadataDirtyVO 类上将 `@Table` 替换为 `@Table`(name
= "<明确的表名>"),确保表名遵循项目命名约定(例如 vm_metadata_dirty
或相应现有表名),并保持与数据库实际表名一致以提高可读性和可维护性。
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java`:
- Around line 3854-3896: These four metadata/rebase handler blocks duplicate the
pattern "build cmd → httpCall(...) → map success/fail", so extract two small
helpers (e.g., proxyEmptyReply(...) and proxyMappedReply(...)) that take the
hostUuid, cmd object, target path constant, response class and a mapping
function (or target reply class) to centralize httpCall and success/fail
handling; update the handlers for UpdateVmInstanceMetadataOnPrimaryStorageMsg
and GetVmInstanceMetadataFromPrimaryStorageMsg to construct
WriteVmMetadataCmd/GetVmInstanceMetadataCmd and then call the new helpers
instead of calling httpCall and inlining
WriteVmMetadataRsp/GetVmInstanceMetadataRsp ->
UpdateVmInstanceMetadataOnPrimaryStorageReply/GetVmInstanceMetadataFromPrimaryStorageReply
mapping, so tracing/audit/error wrapping can be added in one place.
🪄 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: ca121317-00e5-4564-b236-9a13ac1da559
⛔ Files ignored due to path filters (5)
conf/globalConfig/vm.xmlis excluded by!**/*.xmlconf/persistence.xmlis excluded by!**/*.xmlconf/serviceConfig/primaryStorage.xmlis excluded by!**/*.xmlconf/serviceConfig/vmInstance.xmlis excluded by!**/*.xmlconf/springConfigXml/VmInstanceManager.xmlis excluded by!**/*.xml
📒 Files selected for processing (144)
compute/src/main/java/org/zstack/compute/vm/CleanupVmInstanceMetadataOnPrimaryStorageGC.javacompute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.javacompute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.javacompute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.javacompute/src/main/java/org/zstack/compute/vm/VmSystemTags.javaconf/db/upgrade/V5.0.0__schema.sqlheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEvent.javaheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageReplyDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.javaheader/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.javaheader/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.javaheader/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.javaheader/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.javaheader/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.javaheader/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.javaheader/src/main/java/org/zstack/header/vm/VmInstanceState.javaheader/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageReplyDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.javaheader/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.javaheader/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.javaheader/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.javaheader/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.javaheader/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.javaheader/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.javaheader/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.javaheader/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.javaheader/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.javaheader/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.javaresourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.javaresourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.javasdk/src/main/java/SourceClassMap.javasdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.javasdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.javasdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.javasdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.javasdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataAction.javasdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.javasdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageAction.javasdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.javasdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.javasdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.javasdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.javastorage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.javatestlib/src/main/java/org/zstack/testlib/ApiHelper.groovytestlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovytestlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
✅ Files skipped from review due to trivial changes (86)
- header/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java
- header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.java
- header/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.java
- header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java
- header/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.java
- testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
- header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.java
- header/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.java
- header/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.java
- header/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.java
- sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.java
- sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.java
- header/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.java
- header/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.java
- sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.java
- header/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.java
- header/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.java
- header/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.java
- header/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.java
- header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.java
- sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java
- header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageReplyDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java
- compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovy
- sdk/src/main/java/SourceClassMap.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java
- header/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java
- header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.java
- header/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.java
- sdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageReplyDoc_zh_cn.groovy
- plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java
- conf/db/upgrade/V5.0.0__schema.sql
- header/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.java
🚧 Files skipped from review as they are similar to previous changes (34)
- header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.java
- header/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.java
- sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java
- header/src/main/java/org/zstack/header/vm/VmInstanceState.java
- header/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java
- header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.java
- resourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.java
- resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java
- header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java
- storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
- sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java
- sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.java
- header/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.java
- plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.java
- sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java
| public void run(MessageReply reply) { | ||
| if (reply.isSuccess()) { | ||
| logger.info(String.format("[MetadataCleanupGC] successfully cleaned up metadata " + | ||
| "for vm[uuid:%s] on ps[uuid:%s]", vmUuid, primaryStorageUuid)); | ||
| completion.success(); | ||
| } else { | ||
| logger.warn(String.format("[MetadataCleanupGC] failed to clean up metadata " + | ||
| "for vm[uuid:%s] on ps[uuid:%s]: %s", vmUuid, primaryStorageUuid, reply.getError())); | ||
| completion.fail(reply.getError()); | ||
| } |
There was a problem hiding this comment.
GC 未区分瞬态与永久性错误,可能导致无限重试。
当 completion.fail() 被调用时,TimeBasedGarbageCollector 会重新调度 GC 任务。如果错误是永久性的(如元数据路径无效、权限问题等),GC 会无限重试。
建议:
- 检查错误码,对永久性错误调用
completion.cancel()而非completion.fail() - 或者添加重试次数限制
🛠️ 建议修改
} else {
logger.warn(String.format("[MetadataCleanupGC] failed to clean up metadata " +
"for vm[uuid:%s] on ps[uuid:%s]: %s", vmUuid, primaryStorageUuid, reply.getError()));
- completion.fail(reply.getError());
+ // 对于永久性错误(如路径不存在),取消 GC 而非重试
+ if (reply.getError().isError(VmMetadataErrors.METADATA_NOT_FOUND)
+ || reply.getError().isError(PrimaryStorageErrors.PRIMARY_STORAGE_NOT_FOUND)) {
+ logger.info(String.format("[MetadataCleanupGC] cancel gc for vm[uuid:%s] due to permanent error: %s",
+ vmUuid, reply.getError().getCode()));
+ completion.cancel();
+ } else {
+ completion.fail(reply.getError());
+ }
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@compute/src/main/java/org/zstack/compute/vm/CleanupVmInstanceMetadataOnPrimaryStorageGC.java`
around lines 59 - 68, The current run(MessageReply reply) in
CleanupVmInstanceMetadataOnPrimaryStorageGC blindly calls completion.fail()
which causes TimeBasedGarbageCollector to reschedule forever; update the error
handling in run(...) (class CleanupVmInstanceMetadataOnPrimaryStorageGC, method
run) to inspect reply.getError() (e.g. error code or type) and call
completion.cancel() for permanent errors (invalid path, permission denied,
not-found) while keeping completion.fail() for transient errors, or
alternatively implement a retry limit tied to this GC task (store/increment a
retry counter and cancel after N attempts) using vmUuid/primaryStorageUuid to
identify the task.
| try { | ||
| metadataPath = ext.buildVmMetadataPath(psUuid, vmUuid); | ||
| } catch (Exception e) { | ||
| logger.warn(String.format("[MetadataExpunge] failed to build metadata path for vm[uuid:%s] on ps[uuid:%s], " + | ||
| "skip metadata cleanup: %s", vmUuid, psUuid, e.getMessage())); | ||
| trigger.next(); | ||
| return; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 检查 buildVmMetadataPath 实现是否依赖数据库查询
ast-grep --pattern $'buildVmMetadataPath($_, $_) {
$$$
}'Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 查找 VmExpungeMetadataFlow.java 文件并检查 ext 对象的类型
find . -name "VmExpungeMetadataFlow.java" -type fRepository: MatheMatrix/zstack
Length of output: 134
🏁 Script executed:
# 搜索 buildVmMetadataPath 方法定义
rg "buildVmMetadataPath" -A 5 -B 2Repository: MatheMatrix/zstack
Length of output: 4443
🏁 Script executed:
# 查找流程顺序配置
fd "VmInstanceManager.xml" -type fRepository: MatheMatrix/zstack
Length of output: 232
🏁 Script executed:
# 搜索 VmInstanceManager.xml 获取流程顺序
find . -name "*.xml" | xargs grep -l "VmExpungeMetadataFlow\|VmExpungeRootVolumeFlow" 2>/dev/null | head -5Repository: MatheMatrix/zstack
Length of output: 106
🏁 Script executed:
# 查看 VmExpungeMetadataFlow.java 的完整内容
cat -n ./compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.javaRepository: MatheMatrix/zstack
Length of output: 6889
🏁 Script executed:
# 搜索 VmExpungeRootVolumeFlow
rg "class VmExpungeRootVolumeFlow" -A 30Repository: MatheMatrix/zstack
Length of output: 3798
🏁 Script executed:
cat ./conf/springConfigXml/VmInstanceManager.xml | grep -A 5 -B 5 "VmExpunge"Repository: MatheMatrix/zstack
Length of output: 763
补充 GC 机制处理元数据路径构建失败的情况。
VmExpungeMetadataFlow 在第 74 行调用 buildVmMetadataPath() 时捕获异常(第 75-80 行)并静默跳过,仅记录警告日志。与之对比,第 108 行在清理消息失败时会提交 GC 任务进行重试。这种不对称的处理机制导致当路径构建失败时(如 LocalStorage 扩展点中查询 PrimaryStorageVO 失败),无法通过 GC 进行恢复,元数据残留在主存储上。
建议在第 75-80 行的异常处理中也提交 GC 任务,确保路径构建失败不会导致元数据被遗弃:
} catch (Exception e) {
logger.warn(String.format("[MetadataExpunge] failed to build metadata path for vm[uuid:%s] on ps[uuid:%s], " +
"skip metadata cleanup: %s", vmUuid, psUuid, e.getMessage()));
// 提交 GC 任务以确保元数据最终被清理
submitGC(psUuid, vmUuid, rootVolumeUuid, metadataPath, hostUuid);
trigger.next();
return;
}或者考虑在异常捕获时只捕获特定的预期异常,而非泛型 Exception。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java`
around lines 73 - 80, The catch block in VmExpungeMetadataFlow around the call
to buildVmMetadataPath currently logs and skips cleanup, which prevents retry
via GC; modify the exception handling to also enqueue a GC retry by calling the
existing submitGC routine (use the same parameters used later: psUuid, vmUuid,
rootVolumeUuid, metadataPath, hostUuid) before invoking trigger.next(), or
alternatively narrow the catch to expected exceptions; update the catch in the
method containing buildVmMetadataPath to submitGC(psUuid, vmUuid,
rootVolumeUuid, metadataPath, hostUuid) so failed path construction will be
retried by GC.
| method = HttpMethod.DELETE, | ||
| responseClass = APIDeleteVmBootModeEvent.class | ||
| ) | ||
| @MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "VmUuidDirectResolver", field = "uuid") |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== 1) 定位 VmUuidDirectResolver 实现及其注解 =="
fd 'VmUuidDirectResolver\.java$' -t f | while read -r f; do
echo "---- $f ----"
sed -n '1,220p' "$f"
done
echo
echo "== 2) 搜索显式 Bean 命名是否为 VmUuidDirectResolver =="
rg -nP '(`@Component`|@Service|@Named)\s*\(\s*"VmUuidDirectResolver"\s*\)|@Bean\s*\(\s*"VmUuidDirectResolver"\s*\)' -C2
echo
echo "== 3) 搜索所有 MetadataImpact resolver 用法,确认命名是否一致 =="
rg -nP '@MetadataImpact\([^)]*resolver\s*=\s*"VmUuidDirectResolver"' -C1Repository: MatheMatrix/zstack
Length of output: 148
🏁 Script executed:
# 查看被审查的文件
cat -n header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java | head -30Repository: MatheMatrix/zstack
Length of output: 1180
🏁 Script executed:
# 搜索所有MetadataImpact注解的使用,了解resolver命名规则
rg -A2 '@MetadataImpact.*resolver\s*=' --type java | head -50Repository: MatheMatrix/zstack
Length of output: 6309
🏁 Script executed:
# 搜索包含"Resolver"的类定义
fd '.*Resolver.*\.java$' -t f | head -20Repository: MatheMatrix/zstack
Length of output: 139
🏁 Script executed:
# 搜索VmUuid相关的类
rg -l 'VmUuid.*Resolver|class.*VmUuid' --type java | head -20Repository: MatheMatrix/zstack
Length of output: 2073
🏁 Script executed:
cat -n header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.javaRepository: MatheMatrix/zstack
Length of output: 913
🏁 Script executed:
# 搜索VmUuidDirectResolver的显式定义或别名
rg 'VmUuidDirectResolver' --type java -A2 -B2Repository: MatheMatrix/zstack
Length of output: 19965
🏁 Script executed:
# 搜索所有@Component、@Service、@Bean注解,查找resolver的注册方式
rg -A3 '(`@Component`|@Service|@Bean).*\(' header/src/main/java/org/zstack/header/vm/metadata/ --type javaRepository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索VmUuidFromApiResolver的实现类
rg 'implements.*VmUuidFromApiResolver|class.*implements' --type java | grep -i 'vmuu\|resolver'Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索所有resolver的实现
fd '.*Resolver.*\.java$' -t f | xargs grep -l '@Component\|@Service' | head -10Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 查看是否有resolver的注册配置或工厂
rg 'VmUuidDirectResolver|registerBean.*Resolver' --type java -A3 -B3Repository: MatheMatrix/zstack
Length of output: 26267
🏁 Script executed:
# 查看metadata目录结构和所有文件
ls -la header/src/main/java/org/zstack/header/vm/metadata/Repository: MatheMatrix/zstack
Length of output: 3298
🏁 Script executed:
cat -n header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.javaRepository: MatheMatrix/zstack
Length of output: 1434
🏁 Script executed:
# 搜索VmUuidFromApiResolver的所有实现
rg 'implements.*VmUuidFromApiResolver' --type java -A10 -B2Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索Spring配置文件中的resolver bean定义
fd '.*\.xml$|.*Config\.java$' -t f | xargs grep -l 'VmUuidDirectResolver\|resolver' 2>/dev/null | head -20Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 在com.example或package中搜索@Bean方法定义resolver
rg '@Bean.*VmUuidDirectResolver|@Bean.*Resolver' --type java -A5 -B2 | head -40Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 查找MetadataImpact注解的处理/拦截器实现
rg 'MetadataImpact' --type java | grep -i 'interceptor\|processor\|handler\|aspect' | head -20Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索处理MetadataImpact的代码
rg 'resolver.*getBean\|resolver.*lookup\|getResolver' --type java -A5 -B5 | head -60Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 直接搜索所有包含@Component和Resolver的类
fd '.*Resolver.*\.java$' -type f -exec grep -l '@Component\|@Service' {} \; | head -10Repository: MatheMatrix/zstack
Length of output: 232
🏁 Script executed:
# 查找applicationContext或bean配置相关文件
fd 'application.*\.xml|.*config\.xml' -type fRepository: MatheMatrix/zstack
Length of output: 232
🏁 Script executed:
# 查找所有Resolver相关的Java类
fd 'Resolver.*\.java$' | head -30Repository: MatheMatrix/zstack
Length of output: 139
🏁 Script executed:
# 搜索包含VmUuidDirectResolver字符串的所有文件
rg 'VmUuidDirectResolver' -t java -lRepository: MatheMatrix/zstack
Length of output: 2231
🏁 Script executed:
# 搜索MetadataImpact的使用位置和拦截处理
rg 'MetadataImpactInterceptor|MetadataImpact.*Aspect|class.*MetadataImpact' -t java -A10 | head -80Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 查找所有@Component和@Service注解的class
rg '@Component|@Service' -t java | grep 'class\|@' | head -50Repository: MatheMatrix/zstack
Length of output: 317
🏁 Script executed:
# 在整个项目中搜索任何VmUuidDirectResolver的引用或实现
rg 'VmUuidDirectResolver' --type javaRepository: MatheMatrix/zstack
Length of output: 5534
🏁 Script executed:
# 搜索VmUuidFromApiResolver的实现
rg 'implements VmUuidFromApiResolver' --type java -A20Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 查找所有Spring `@Component和`@Service的resolver实现
rg '(`@Component`|@Service)' --type java -A3 | grep -B3 -A3 'Resolver'Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 检查是否在测试或其他位置有定义
git grep -i 'vmuuiddirectresolver' 2>/dev/null || echo "git grep not available"Repository: MatheMatrix/zstack
Length of output: 5534
🏁 Script executed:
# 搜索整个项目中所有实现VmUuidFromApiResolver的类
find . -name "*.java" -type f -exec grep -l "implements VmUuidFromApiResolver" {} \;Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 查找core或vm模块中的实现
fd '\.java$' core vm plugin | xargs grep -l "implements VmUuidFromApiResolver" 2>/dev/nullRepository: MatheMatrix/zstack
Length of output: 112
🏁 Script executed:
# 搜索@Component或@Service标注的且名称包含DirectResolver的类
rg '@Component|@Service' --type java -B5 | grep -B5 'DirectResolver'Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 在整个项目中搜索bean注册或Component定义
rg 'name.*VmUuidDirectResolver|"VmUuidDirectResolver"' --type javaRepository: MatheMatrix/zstack
Length of output: 5534
将 resolver 字符串 "VmUuidDirectResolver" 改为有效的 Spring Bean 名称。
仓库中不存在 VmUuidDirectResolver 类或其 Spring Bean 实现。VmUuidFromApiResolver 接口存在但没有任何实现类。@MetadataImpact 注解要求 resolver 参数为实现了 VmUuidFromApiResolver 接口的有效 Spring Bean 名称,但该 Bean 未被注册或不存在,将导致 VM 元数据影响拦截在运行时无法解析。这影响超过 30 个 API 消息类的元数据追踪功能。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java` at
line 14, The `@MetadataImpact` annotation on APIDeleteVmBootModeMsg uses an
invalid resolver name "VmUuidDirectResolver"; update this to a valid Spring bean
that implements VmUuidFromApiResolver (or register such a bean) so runtime
metadata resolution works: either implement a class that implements
VmUuidFromApiResolver and register it as a Spring bean with the name used in the
resolver parameter, or change the resolver string to the existing registered
bean name; ensure the resolver value in the `@MetadataImpact` annotation matches
the bean name exactly (refer to APIDeleteVmBootModeMsg and the
VmUuidFromApiResolver interface to locate where to add or rename the bean).
| @Override | ||
| public String validateMetadataPath(String primaryStorageUuid, String path) { | ||
| // Expected format: <metadataDir>/<uuid>.vmmeta | ||
| // e.g. /local_ps/vm-metadata/a1b2c3d4e5f6...vmmeta | ||
| String metadataDir = buildMetadataDir(primaryStorageUuid); | ||
| String prefix = metadataDir + "/"; | ||
| String suffix = VmInstanceMetadataConstants.FILE_METADATA_SUFFIX; | ||
|
|
||
| if (!path.startsWith(prefix) || !path.endsWith(suffix)) { | ||
| return String.format("metadataPath[%s] does not match expected format: %s/<uuid>%s", | ||
| path, metadataDir, suffix); | ||
| } | ||
|
|
||
| String uuidPart = path.substring(prefix.length(), path.length() - suffix.length()); | ||
| if (!uuidPart.matches("[0-9a-f]{32}")) { | ||
| return String.format("metadataPath[%s] contains invalid uuid[%s], expected 32-char hex", path, uuidPart); | ||
| } | ||
| return null; |
There was a problem hiding this comment.
校验方法里不要抛 CloudRuntimeException。
validateMetadataPath() 这里本来应该返回错误字符串或 null,但 buildMetadataDir(primaryStorageUuid) 在主存储查不到或 URL 取不到时会直接抛异常。这个方法又会被注册链路拿来做参数校验,结果会把一次可预期的校验失败升级成 500。这里更稳妥的做法是把这类情况转换成可读的校验错误返回值。
💡 建议改法
`@Override`
public String validateMetadataPath(String primaryStorageUuid, String path) {
+ if (path == null) {
+ return "metadataPath cannot be null";
+ }
+
- String metadataDir = buildMetadataDir(primaryStorageUuid);
+ final String metadataDir;
+ try {
+ metadataDir = buildMetadataDir(primaryStorageUuid);
+ } catch (CloudRuntimeException e) {
+ return String.format("cannot resolve metadata dir for primary storage[uuid:%s]: %s",
+ primaryStorageUuid, e.getMessage());
+ }
String prefix = metadataDir + "/";
String suffix = VmInstanceMetadataConstants.FILE_METADATA_SUFFIX;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java`
around lines 98 - 115, validateMetadataPath currently calls
buildMetadataDir(primaryStorageUuid) which can throw CloudRuntimeException;
catch any exception (or null/empty result) from buildMetadataDir inside
validateMetadataPath and convert it into a readable validation error string
instead of letting it propagate. Specifically, wrap the call to
buildMetadataDir(primaryStorageUuid) in a try/catch, return a formatted message
like "metadataPath[...] cannot build metadataDir for primaryStorageUuid[...] :
<error>" on failure, then proceed with the existing prefix/suffix and uuidPart
regex checks using VmInstanceMetadataConstants.FILE_METADATA_SUFFIX so the
method only returns strings or null and never throws.
dba8f07 to
c79a64d
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (6)
sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java (1)
28-29: 建议注明这里的uuid是 VM UUID。
header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.javaLine 10-30 里,这个字段对应的是VmInstanceVO。结合/primary-storage/...的路径,SDK 调用方很容易误以为这里要传 primary storage UUID;如果字段名因兼容性不能改,至少补一句注释或 Javadoc。可以用最小改动把语义补清楚
+ /** + * 云主机 UUID,不是 primary storage UUID。 + */ `@Param`(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String uuid;As per coding guidelines "命名应尽量用完整的单词组合表达意图,并在名称中体现数据类型或用途(例如在常量与变量名称中,将类型词放在末尾)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java` around lines 28 - 29, Add a clarifying Javadoc/comment to the uuid field in GetVmInstanceMetadataFromPrimaryStorageAction indicating that this UUID refers to the VM instance (VmInstanceVO) and not the primary storage; reference the corresponding API class APIGetVmInstanceMetadataFromPrimaryStorageMsg and the VmInstanceVO to make the mapping explicit so callers won’t confuse it with a primary storage UUID.header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java (1)
8-12: 缺少@RestResponse注释说明响应类型。根据编码规范,API 消息类应在注释中使用
@RestResponse标注返回类型。建议添加类级别的 Javadoc 注释,说明此 API 使用异步事件模式(APIScanVmInstanceMetadataFromPrimaryStorageEvent)而非同步回复。建议添加文档注释
+/** + * `@api` scan vm instance metadata from primary storage + * `@category` vm metadata + * `@RestResponse`(allTo = "vmInstanceMetadata") + * `@result` see {`@link` APIScanVmInstanceMetadataFromPrimaryStorageEvent} + */ `@RestRequest`( path = "/primary-storage/vm-instances/metadata/scan", method = HttpMethod.GET, responseClass = APIScanVmInstanceMetadataFromPrimaryStorageEvent.class )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java` around lines 8 - 12, 在类 APIScanVmInstanceMetadataFromPrimaryStorageMsg 上补充类级注释并添加 `@RestResponse` 标注,明确响应类型为 APIScanVmInstanceMetadataFromPrimaryStorageEvent;在类 Javadoc 中说明该接口采用异步事件回复模式(返回 APIScanVmInstanceMetadataFromPrimaryStorageEvent),以便与现有 `@RestRequest`(path="/primary-storage/vm-instances/metadata/scan") 配合使用并满足编码规范要求。compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java (1)
140-141:VM_METADATA_LAST_REFRESH_VERSION缺少验证规则。此配置项的
@GlobalConfigValidation()注解为空,没有指定任何验证规则。如果这是一个版本字符串,可以考虑添加notNull或正则表达式验证以防止无效输入。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java` around lines 140 - 141, The GlobalConfig VM_METADATA_LAST_REFRESH_VERSION in VmGlobalConfig currently has an empty `@GlobalConfigValidation`() and needs concrete validation; update the annotation on VM_METADATA_LAST_REFRESH_VERSION to include appropriate rules (e.g., notNull and/or a regex pattern matching your version format) so invalid or empty strings are rejected—use the `@GlobalConfigValidation` parameters supported by your validation framework to add notNull=true or a regex like "^[0-9]+(\\.[0-9]+)*$" (or your project's version pattern) to the annotation on VM_METADATA_LAST_REFRESH_VERSION.plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java (1)
65-68: UUID 验证正则仅匹配小写十六进制字符。正则表达式
[0-9a-f]{32}仅匹配小写字母。如果元数据路径中的 UUID 包含大写字母(如A-F),验证将失败。建议改为[0-9a-fA-F]{32}或在验证前将路径转换为小写。♻️ 建议修改
- if (!uuidPart.matches("[0-9a-f]{32}")) { + if (!uuidPart.toLowerCase().matches("[0-9a-f]{32}")) { return String.format("metadataPath[%s] contains invalid uuid[%s], expected 32-char hex", path, uuidPart); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java` around lines 65 - 68, The UUID validation in NfsVmMetadataExtension uses uuidPart.matches("[0-9a-f]{32}") which only accepts lowercase hex and will reject uppercase A-F; update the check to accept both cases by using a case-insensitive pattern (e.g. "[0-9a-fA-F]{32}") or normalize uuidPart to lower-case before matching so the validation in the method that computes uuidPart correctly accepts 32-char hex UUIDs regardless of letter case.plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java (2)
2132-2163: 空扫描结果也请显式返回空列表。这里在
rsp.metadataEntries == null时直接返回 reply,vmInstanceMetadata会保持null。同一 PR 里的plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java的 Line 3906-3912 已经显式返回Collections.emptyList();建议 NFS 这里保持一致,避免调用方多做一层空指针分支。💡 可直接在这里补一个 else 分支
ScanVmInstanceMetadataFromPrimaryStorageReply r = new ScanVmInstanceMetadataFromPrimaryStorageReply(); if (rsp.metadataEntries != null) { rsp.metadataEntries.forEach(entry -> entry.setHostUuid(hostUuid)); r.setVmInstanceMetadata(rsp.metadataEntries); + } else { + r.setVmInstanceMetadata(Collections.emptyList()); } completion.success(r);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java` around lines 2132 - 2163, In handle(...) of NfsPrimaryStorageKVMBackend (method handling ScanVmInstanceMetadataFromPrimaryStorageMsg) ensure ScanVmInstanceMetadataFromPrimaryStorageReply.vmInstanceMetadata is never left null: after obtaining rsp (NfsPrimaryStorageKVMBackendCommands.ScanVmMetadataRsp) keep the existing branch that sets hostUuid on each entry and sets r.setVmInstanceMetadata(rsp.metadataEntries) when rsp.metadataEntries != null, and add an else that calls r.setVmInstanceMetadata(Collections.emptyList()) (import java.util.Collections) so callers always get a non-null list; this mirrors the LocalStorageKvmBackend behavior.
2065-2196: 建议复用asyncHttpCall(),别再手写 4 份相同的转发逻辑。
Update/Get/Scan/Cleanup这几段都重复了KVMHostAsyncHttpCallMsg构造、toResponse()和rsp.isSuccess()判断,而且也绕过了类里统一的updatePrimaryStorageCapacity()。直接走 helper 会更一致,也更不容易漏掉后续公共逻辑。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java` around lines 2065 - 2196, These handlers duplicate KVMHostAsyncHttpCallMsg construction, bus.send callback, toResponse() and rsp.isSuccess() checks; refactor handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg), handle(GetVmInstanceMetadataFromPrimaryStorageMsg), handle(ScanVmInstanceMetadataFromPrimaryStorageMsg) and handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg) to call the existing asyncHttpCall(...) helper (or extract one if missing) passing the appropriate command (WriteVmMetadataCmd, GetVmInstanceMetadataCmd, ScanVmMetadataCmd, CleanupVmMetadataCmd), path constants (WRITE_VM_METADATA_PATH, GET_VM_INSTANCE_METADATA_PATH, SCAN_VM_METADATA_PATH, CLEANUP_VM_METADATA_PATH) and hostUuid, then process the returned KVMHostAsyncHttpCallReply via toResponse(...) and shared rsp.isSuccess() handling inside that helper; ensure any post-success common logic such as updatePrimaryStorageCapacity(...) or setting hostUuid on metadata entries (rsp.metadataEntries.forEach(...)) is executed after the helper returns success so no common behavior is bypassed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@header/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.java`:
- Line 48: Create and register a Spring bean named SnapshotUuidToVmUuidResolver
that implements the VmUuidFromApiResolver interface and provides the logic to
resolve a snapshot UUID to its VM UUID (used by the `@MetadataImpact` annotation
on APIDeleteVolumeSnapshotMsg); implement the required resolve(...) method to
look up the snapshot (via the snapshot/volume DAO or existing snapshot service)
and return the corresponding VM UUID or throw a clear exception if not found,
annotate the class with `@Component` (or register it in your Spring config) so it
is discoverable, and add the same resolver usage for APIUpdateVolumeSnapshotMsg,
APIRevertVolumeFromSnapshotMsg, and APIShrinkVolumeSnapshotMsg where the
annotation references SnapshotUuidToVmUuidResolver.
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java`:
- Around line 3854-3940: The handleLocalMessage() dispatch in LocalStorageBase
is missing explicit branches for UpdateVmInstanceMetadataOnPrimaryStorageMsg,
GetVmInstanceMetadataFromPrimaryStorageMsg,
ScanVmInstanceMetadataFromPrimaryStorageMsg, and
CleanupVmInstanceMetadataOnPrimaryStorageMsg, causing those messages to fall
through to super and preventing LocalStorageKvmBackend's protected handle(...)
implementations from being invoked; update LocalStorageBase.handleLocalMessage()
to add explicit if/else branches that detect each of those four message classes
and call the corresponding protected handle(msg, hostUuid, completion) method
(same pattern used for RebaseVolumeBackingFileOnPrimaryStorageMsg) so
LocalStorageKvmBackend.handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg ...),
handle(GetVmInstanceMetadataFromPrimaryStorageMsg ...),
handle(ScanVmInstanceMetadataFromPrimaryStorageMsg ...), and
handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg ...) are reached.
In
`@resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java`:
- Line 15: The `@MetadataImpact` annotation on APIUpdateResourceConfigMsg
references a non-existent Spring bean "ResourceUuidToVmUuidResolver"; either
implement and register a bean with that name that implements
VmUuidFromApiResolver to resolve ResourceVO/resourceUuid, or change the resolver
value to an existing registered implementation that performs the same ResourceVO
-> VM UUID resolution; update or add the resolver class (named
ResourceUuidToVmUuidResolver) implementing VmUuidFromApiResolver and
annotate/register it as a Spring bean so the resolver parameter in
APIUpdateResourceConfigMsg resolves at runtime.
---
Nitpick comments:
In `@compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java`:
- Around line 140-141: The GlobalConfig VM_METADATA_LAST_REFRESH_VERSION in
VmGlobalConfig currently has an empty `@GlobalConfigValidation`() and needs
concrete validation; update the annotation on VM_METADATA_LAST_REFRESH_VERSION
to include appropriate rules (e.g., notNull and/or a regex pattern matching your
version format) so invalid or empty strings are rejected—use the
`@GlobalConfigValidation` parameters supported by your validation framework to add
notNull=true or a regex like "^[0-9]+(\\.[0-9]+)*$" (or your project's version
pattern) to the annotation on VM_METADATA_LAST_REFRESH_VERSION.
In
`@header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java`:
- Around line 8-12: 在类 APIScanVmInstanceMetadataFromPrimaryStorageMsg 上补充类级注释并添加
`@RestResponse` 标注,明确响应类型为 APIScanVmInstanceMetadataFromPrimaryStorageEvent;在类
Javadoc 中说明该接口采用异步事件回复模式(返回
APIScanVmInstanceMetadataFromPrimaryStorageEvent),以便与现有
`@RestRequest`(path="/primary-storage/vm-instances/metadata/scan") 配合使用并满足编码规范要求。
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java`:
- Around line 2132-2163: In handle(...) of NfsPrimaryStorageKVMBackend (method
handling ScanVmInstanceMetadataFromPrimaryStorageMsg) ensure
ScanVmInstanceMetadataFromPrimaryStorageReply.vmInstanceMetadata is never left
null: after obtaining rsp
(NfsPrimaryStorageKVMBackendCommands.ScanVmMetadataRsp) keep the existing branch
that sets hostUuid on each entry and sets
r.setVmInstanceMetadata(rsp.metadataEntries) when rsp.metadataEntries != null,
and add an else that calls r.setVmInstanceMetadata(Collections.emptyList())
(import java.util.Collections) so callers always get a non-null list; this
mirrors the LocalStorageKvmBackend behavior.
- Around line 2065-2196: These handlers duplicate KVMHostAsyncHttpCallMsg
construction, bus.send callback, toResponse() and rsp.isSuccess() checks;
refactor handle(UpdateVmInstanceMetadataOnPrimaryStorageMsg),
handle(GetVmInstanceMetadataFromPrimaryStorageMsg),
handle(ScanVmInstanceMetadataFromPrimaryStorageMsg) and
handle(CleanupVmInstanceMetadataOnPrimaryStorageMsg) to call the existing
asyncHttpCall(...) helper (or extract one if missing) passing the appropriate
command (WriteVmMetadataCmd, GetVmInstanceMetadataCmd, ScanVmMetadataCmd,
CleanupVmMetadataCmd), path constants (WRITE_VM_METADATA_PATH,
GET_VM_INSTANCE_METADATA_PATH, SCAN_VM_METADATA_PATH, CLEANUP_VM_METADATA_PATH)
and hostUuid, then process the returned KVMHostAsyncHttpCallReply via
toResponse(...) and shared rsp.isSuccess() handling inside that helper; ensure
any post-success common logic such as updatePrimaryStorageCapacity(...) or
setting hostUuid on metadata entries (rsp.metadataEntries.forEach(...)) is
executed after the helper returns success so no common behavior is bypassed.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java`:
- Around line 65-68: The UUID validation in NfsVmMetadataExtension uses
uuidPart.matches("[0-9a-f]{32}") which only accepts lowercase hex and will
reject uppercase A-F; update the check to accept both cases by using a
case-insensitive pattern (e.g. "[0-9a-fA-F]{32}") or normalize uuidPart to
lower-case before matching so the validation in the method that computes
uuidPart correctly accepts 32-char hex UUIDs regardless of letter case.
In
`@sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java`:
- Around line 28-29: Add a clarifying Javadoc/comment to the uuid field in
GetVmInstanceMetadataFromPrimaryStorageAction indicating that this UUID refers
to the VM instance (VmInstanceVO) and not the primary storage; reference the
corresponding API class APIGetVmInstanceMetadataFromPrimaryStorageMsg and the
VmInstanceVO to make the mapping explicit so callers won’t confuse it with a
primary storage UUID.
🪄 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: dfe4414a-ab0a-4c23-b5e1-c1ec8ca2dc39
⛔ Files ignored due to path filters (5)
conf/globalConfig/vm.xmlis excluded by!**/*.xmlconf/persistence.xmlis excluded by!**/*.xmlconf/serviceConfig/primaryStorage.xmlis excluded by!**/*.xmlconf/serviceConfig/vmInstance.xmlis excluded by!**/*.xmlconf/springConfigXml/VmInstanceManager.xmlis excluded by!**/*.xml
📒 Files selected for processing (145)
compute/src/main/java/org/zstack/compute/vm/CleanupVmInstanceMetadataOnPrimaryStorageGC.javacompute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.javacompute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.javacompute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.javacompute/src/main/java/org/zstack/compute/vm/VmSystemTags.javaconf/db/upgrade/V5.0.0__schema.sqlheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEvent.javaheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageReplyDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.javaheader/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.javaheader/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.javaheader/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.javaheader/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.javaheader/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.javaheader/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.javaheader/src/main/java/org/zstack/header/vm/VmInstanceState.javaheader/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageReplyDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.javaheader/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.javaheader/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.javaheader/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO_.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.javaheader/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.javaheader/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.javaheader/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.javaheader/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.javaheader/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.javaheader/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.javaheader/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.javaresourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.javaresourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.javasdk/src/main/java/SourceClassMap.javasdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.javasdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.javasdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.javasdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.javasdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataAction.javasdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.javasdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageAction.javasdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.javasdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.javasdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.javasdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.javastorage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.javatestlib/src/main/java/org/zstack/testlib/ApiHelper.groovytestlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovytestlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
✅ Files skipped from review due to trivial changes (81)
- header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java
- header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.java
- header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java
- header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.java
- header/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.java
- sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.java
- header/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.java
- header/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.java
- header/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.java
- sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java
- header/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.java
- header/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.java
- header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.java
- header/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.java
- testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.java
- sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.java
- header/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.java
- header/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.java
- header/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java
- header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.java
- header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.java
- testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
- header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageReplyDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java
- sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java
- header/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.java
- header/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovy
- sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEvent.java
- header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.java
- sdk/src/main/java/SourceClassMap.java
- header/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java
- header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java
- header/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageReplyDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.java
- sdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.java
- header/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.java
🚧 Files skipped from review as they are similar to previous changes (44)
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.java
- header/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.java
- header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.java
- header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/vm/VmInstanceState.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java
- header/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.java
- conf/db/upgrade/V5.0.0__schema.sql
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.java
- plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java
- resourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.java
- storage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.java
- header/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.java
- header/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
- sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java
- testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
- compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java
| responseClass = APIDeleteVolumeSnapshotEvent.class | ||
| ) | ||
| @DefaultTimeout(timeunit = TimeUnit.HOURS, value = 6) | ||
| @MetadataImpact(value = MetadataImpact.Impact.STORAGE, resolver = "SnapshotUuidToVmUuidResolver", field = "uuid", updateOnFailure = true) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 搜索 SnapshotUuidToVmUuidResolver 的实现
rg -n "SnapshotUuidToVmUuidResolver" --type=java -C 3Repository: MatheMatrix/zstack
Length of output: 4201
🏁 Script executed:
# 搜索 SnapshotUuidToVmUuidResolver 的定义和实现
rg -n "class SnapshotUuidToVmUuidResolver|@Bean.*SnapshotUuidToVmUuidResolver|SnapshotUuidToVmUuidResolver.*=" --type=java -A 5Repository: MatheMatrix/zstack
Length of output: 3715
🏁 Script executed:
# 搜索 SnapshotUuidToVmUuidResolver 的bean定义或类定义
rg "SnapshotUuidToVmUuidResolver" --type=javaRepository: MatheMatrix/zstack
Length of output: 920
🏁 Script executed:
# 搜索所有可能的resolver相关定义
rg "class.*Resolver.*implements|@Component|@Bean" --type=java | grep -i "snapshot\|resolver" | head -20Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索XML配置文件中的resolver定义
find . -name "*.xml" -type f -exec grep -l "SnapshotUuidToVmUuidResolver" {} \;Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索MetadataImpact接口定义和resolver接口
rg "interface.*Resolver|class MetadataImpact" --type=java -A 10 | head -60Repository: MatheMatrix/zstack
Length of output: 1319
🏁 Script executed:
# 搜索所有实现 VmUuidFromApiResolver 的类
rg "implements VmUuidFromApiResolver" --type=java -B 1Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索所有Resolver相关的类和bean定义
rg "Resolver" --type=java -w | grep -i "class\|@Bean\|@Component" | head -30Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索所有 Resolver 类
rg "Resolver" --type=java | head -50Repository: MatheMatrix/zstack
Length of output: 8926
🏁 Script executed:
# 搜索所有包含 "VmUuid" 的类定义(可能包含各类resolver实现)
rg "class.*VmUuid.*|@Component|@Bean" --type=java -B 2 -A 1 | head -100Repository: MatheMatrix/zstack
Length of output: 14672
🏁 Script executed:
# 在storage模块中搜索resolver或bean相关的注解
find storage -name "*.java" -type f -exec grep -l "@Bean\|@Component" {} \; | head -20Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
# 搜索所有可能的resolver定义和注册方式
rg "SnapshotUuid|VolumeUuid|NicUuid" --type=java | grep -E "class|interface|extends|implements" | head -30Repository: MatheMatrix/zstack
Length of output: 5659
🏁 Script executed:
# 在storage模块中搜索 VmUuidFromApiResolver 的实现
find storage -name "*.java" -type f | xargs grep -l "VmUuidFromApiResolver"Repository: MatheMatrix/zstack
Length of output: 46
🏁 Script executed:
# 最终验证:搜索整个代码库中是否存在任何 VmUuidFromApiResolver 的实现
rg "implements VmUuidFromApiResolver|extends.*Resolver" --type=javaRepository: MatheMatrix/zstack
Length of output: 44
缺少 SnapshotUuidToVmUuidResolver resolver 实现
注解引用的 SnapshotUuidToVmUuidResolver bean 在代码库中不存在。搜索结果表明虽然 VmUuidFromApiResolver 接口已定义,但没有找到任何实现该接口的类。该 resolver 需要被创建并注册为 Spring bean,否则在运行时会导致 bean 查找失败。同样的问题也出现在 APIUpdateVolumeSnapshotMsg、APIRevertVolumeFromSnapshotMsg 和 APIShrinkVolumeSnapshotMsg 中。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@header/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.java`
at line 48, Create and register a Spring bean named SnapshotUuidToVmUuidResolver
that implements the VmUuidFromApiResolver interface and provides the logic to
resolve a snapshot UUID to its VM UUID (used by the `@MetadataImpact` annotation
on APIDeleteVolumeSnapshotMsg); implement the required resolve(...) method to
look up the snapshot (via the snapshot/volume DAO or existing snapshot service)
and return the corresponding VM UUID or throw a clear exception if not found,
annotate the class with `@Component` (or register it in your Spring config) so it
is discoverable, and add the same resolver usage for APIUpdateVolumeSnapshotMsg,
APIRevertVolumeFromSnapshotMsg, and APIShrinkVolumeSnapshotMsg where the
annotation references SnapshotUuidToVmUuidResolver.
plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java
Show resolved
Hide resolved
| method = HttpMethod.PUT, | ||
| isAction = true, | ||
| responseClass = APIUpdateResourceConfigEvent.class) | ||
| @MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "ResourceUuidToVmUuidResolver", field = "resourceUuid") |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== 1) 查找 ResourceUuidToVmUuidResolver 的定义与 Bean 命名 =="
fd 'ResourceUuidToVmUuidResolver.java' -t f -x sh -c '
f="$1"
echo "---- $f ----"
rg -n -C2 "class\\s+ResourceUuidToVmUuidResolver|@Component|@Service|@Named|@Bean\\(" "$f"
' sh {}
echo
echo "== 2) 查找 MetadataImpact 的解析入口,确认 resolver 是按名称获取 Bean 还是按类型获取 =="
rg -n -C3 "MetadataImpact|resolver\\(|getBean\\(|VmUuidFromApiResolver" --type=java
echo
echo "== 3) 检查 resolver 对非 VM 资源(如 Cluster/Host)的处理逻辑 =="
fd 'ResourceUuidToVmUuidResolver.java' -t f -x sh -c '
f="$1"
rg -n -C4 "resolveVmUuid\\(|batchResolveVmUuids\\(|Cluster|Host|Zone|VmInstance|ResourceVO" "$f"
' sh {}Repository: MatheMatrix/zstack
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== 1) ResourceUuidToVmUuidResolver 클래스 전체 검색 (정확한 이름) ==="
find . -type f -name "*ResourceUuidToVmUuidResolver*" 2>/dev/null | head -20
echo
echo "=== 2) VolumeUuidToVmUuidResolver 구현 찾아서 패턴 파악 ==="
fd 'VolumeUuidToVmUuidResolver.java' -t f -x cat {} \; 2>/dev/null | head -100
echo
echo "=== 3) ResourceUuidToVmUuidResolver 문자열 전체 검색 (모든 파일) ==="
rg -l 'ResourceUuidToVmUuidResolver' --type java 2>/dev/null | head -20
echo
echo "=== 4) MetadataImpact 클래스 정의로 resolver 메커니즘 이해 ==="
rg -n -A20 'class MetadataImpact|interface.*MetadataImpact|@interface MetadataImpact' --type java 2>/dev/null | head -80Repository: MatheMatrix/zstack
Length of output: 2946
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== 1) VmUuidFromApiResolver 的所有实现类 ==="
rg -l 'implements VmUuidFromApiResolver|extends.*VmUuidFromApiResolver' --type java | head -20
echo
echo "=== 2) 所有已注册的 resolver Bean(@Component 或 `@Service`) ==="
rg -B5 'VmUuidFromApiResolver' --type java -A2 | grep -E '@Component|@Service|@Named|class.*Resolver' | head -30
echo
echo "=== 3) resourceconfig 模块中 resourceUuid 的相关用法 ==="
rg -n 'resourceUuid' resourceconfig/ --type java -B2 -A2 | head -60
echo
echo "=== 4) 查看 APICreateSystemTagsMsg 中的 resolver 用法(参考) ==="
rg -n -B3 -A1 'ResourceUuidToVmUuidResolver' header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.javaRepository: MatheMatrix/zstack
Length of output: 101
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== 1) 查找 VmUuidFromApiResolver 接口定义 ==="
fd 'VmUuidFromApiResolver.java' -type f -x cat {} 2>/dev/null
echo
echo "=== 2) 查找所有 resolver 相关的类(*Resolver.java)==="
fd 'Resolver.java' -type f | xargs -I{} sh -c 'echo "=== {} ===" && head -30 "{}"' 2>/dev/null | head -150
echo
echo "=== 3) resourceconfig 模块中 Bean 注册(Spring 配置) ==="
find resourceconfig -name '*.xml' -o -name '*Config.java' | xargs cat 2>/dev/null | grep -A5 -B5 'ResourceUuid\|resolver' | head -50
echo
echo "=== 4) 直接查看 APIUpdateResourceConfigMsg 的完整内容 ==="
cat resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.javaRepository: MatheMatrix/zstack
Length of output: 102
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== 1) 用 rg 搜索 VmUuidFromApiResolver 定义 ==="
rg 'interface VmUuidFromApiResolver|class VmUuidFromApiResolver' --type java -A10 2>/dev/null | head -50
echo
echo "=== 2) 查看 APIUpdateResourceConfigMsg 完整内容 ==="
cat resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java 2>/dev/null
echo
echo "=== 3) 搜索所有 Resolver 类(包含类定义) ==="
rg 'class.*Resolver.*implements|class.*Resolver.*extends' --type java 2>/dev/null | head -30
echo
echo "=== 4) 搜索 `@Component` 或 `@Service` 注解的 resolver ==="
rg -B5 'class.*Resolver' --type java | grep -E '(`@Component`|@Service|class.*Resolver)' | head -40Repository: MatheMatrix/zstack
Length of output: 3365
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== 1) 搜索所有 `@Component/`@Service 标注的类及其名称 ==="
rg -B2 '@Component|@Service' --type java | grep -A1 '@Component\|@Service\|class' | grep -i resolver | head -40
echo
echo "=== 2) 查找 VolumeUuidToVmUuidResolver 的实现(作为参考) ==="
rg 'class VolumeUuidToVmUuidResolver' --type java -A20 | head -50
echo
echo "=== 3) 在 header 模块查找所有 resolver 实现 ==="
find header -name '*Resolver.java' -type f -exec sh -c 'echo "=== {} ===" && head -40 "{}"' \; 2>/dev/null | head -100
echo
echo "=== 4) 查找 `@Component` 的 bean name 定义(resourceUuid 相关) ==="
rg '@Component.*value|@Component.*name|@Service.*value|@Service.*name' --type java | grep -i 'resource\|uuid' | head -20Repository: MatheMatrix/zstack
Length of output: 106
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== 1) 列出所有 *Resolver.java 文件 ==="
find . -name '*Resolver.java' -type f 2>/dev/null | head -30
echo
echo "=== 2) 查看 VolumeUuidToVmUuidResolver 实现 ==="
find . -name 'VolumeUuidToVmUuidResolver.java' -type f -exec cat {} \; 2>/dev/null
echo
echo "=== 3) 在 resourceconfig 目录下查找所有 Java 文件 ==="
find resourceconfig -name '*.java' -type f 2>/dev/null
echo
echo "=== 4) 搜索 ResourceUuidToVmUuidResolver 在代码中的引用情况(完整上下文) ==="
rg 'ResourceUuidToVmUuidResolver' --type java -B10 -A10 2>/dev/null | head -100Repository: MatheMatrix/zstack
Length of output: 12813
Resolver Bean "ResourceUuidToVmUuidResolver" 不存在,运行时将失败。
Line 15 中 resolver = "ResourceUuidToVmUuidResolver" 指向的 Spring bean 在代码库中不存在。当使用 @MetadataImpact 时,resolver 参数必须是已注册的 Spring bean 名称(实现 VmUuidFromApiResolver 接口),但当前无法找到该实现类的定义。这会导致运行时抛出 NoSuchBeanDefinitionException。
需要确认:
- 是否需要创建新的
ResourceUuidToVmUuidResolver实现类来处理 ResourceVO 类型的 UUID 解析 - 或者该 resolver 名称是否应改为已存在的实现(如果存在)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java`
at line 15, The `@MetadataImpact` annotation on APIUpdateResourceConfigMsg
references a non-existent Spring bean "ResourceUuidToVmUuidResolver"; either
implement and register a bean with that name that implements
VmUuidFromApiResolver to resolve ResourceVO/resourceUuid, or change the resolver
value to an existing registered implementation that performs the same ResourceVO
-> VM UUID resolution; update or add the resolver class (named
ResourceUuidToVmUuidResolver) implementing VmUuidFromApiResolver and
annotate/register it as a Spring bean so the resolver parameter in
APIUpdateResourceConfigMsg resolves at runtime.
c79a64d to
1d82d97
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (2)
plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java (1)
3491-3500:⚠️ Potential issue | 🟠 Major不要把部分 host 的扫描结果当成成功返回。
Line 3494 现在只有“全部 host 都失败”才会置
reply.error。只要还有任意一个 host 成功,这里就会返回一个看似成功、实际不完整的 metadata 列表;后续如果调用方基于这个结果做注册或清理,很容易漏掉失败 host 上的数据。这里要么任一 host 失败就整体失败,要么在 reply 里显式返回partial和失败 host 列表。💡 一个更安全的最小修正
- if (!errorCodeList.getCauses().isEmpty() && errorCodeList.getCauses().size() == connectedHostUuids.size()) { - reply.setError(operr("failed to scan vm metadata from all hosts on local primary storage[uuid:%s], causes: %s", + if (!errorCodeList.getCauses().isEmpty()) { + reply.setError(operr("failed to scan vm metadata from one or more hosts on local primary storage[uuid:%s], causes: %s", self.getUuid(), errorCodeList)); } else { reply.setVmInstanceMetadata(new ArrayList<>(allSummaries)); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java` around lines 3491 - 3500, The current completion in LocalStorageBase (anonymous WhileDoneCompletion handling errorCodeList, connectedHostUuids, reply, and allSummaries) treats the operation as successful if at least one host returned metadata; change the logic so any host failure causes an overall failure: if errorCodeList.getCauses() is not empty, set reply.setError(operr(...)) (include errorCodeList and failed host UUIDs in the message) and do not return partial allSummaries; alternatively, if you prefer a partial-response API, add explicit fields to the reply (e.g., setPartial(true) and setFailedHostUuids(...)) and populate them—pick one approach and implement consistently in the block that currently checks errorCodeList.getCauses().isEmpty() && size()==connectedHostUuids.size().plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java (1)
99-115:⚠️ Potential issue | 🟠 Major
validateMetadataPath()这里不要抛异常。这是参数校验方法,但 Line 102 会让
buildMetadataDir()的异常直接冒泡,Line 106 在path == null时也会直接 NPE。一次可预期的校验失败会被放大成 500;这里应该始终返回错误字符串或null。💡 建议改法
`@Override` public String validateMetadataPath(String primaryStorageUuid, String path) { + if (path == null) { + return "metadataPath cannot be null"; + } + // Expected format: <metadataDir>/<uuid>.vmmeta // e.g. /local_ps/vm-metadata/a1b2c3d4e5f6...vmmeta - String metadataDir = buildMetadataDir(primaryStorageUuid); + final String metadataDir; + try { + metadataDir = buildMetadataDir(primaryStorageUuid); + } catch (Exception e) { + return String.format("metadataPath[%s] cannot build metadataDir for primaryStorageUuid[%s]: %s", + path, primaryStorageUuid, e.getMessage()); + } String prefix = metadataDir + "/"; String suffix = VmInstanceMetadataConstants.FILE_METADATA_SUFFIX;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java` around lines 99 - 115, The validateMetadataPath method currently lets buildMetadataDir() exceptions and null path NPEs propagate; change validateMetadataPath(String primaryStorageUuid, String path) so it catches any exceptions from buildMetadataDir(primaryStorageUuid) and treats null/invalid path inputs safely, returning a descriptive error string instead of throwing; specifically, wrap buildMetadataDir call in a try/catch returning a formatted error message on failure, check path for null before using startsWith/endsWith, and keep the existing uuid regex check, returning null only when the path is valid.
🧹 Nitpick comments (2)
testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy (1)
525-539: 建议让这 4 个 NFS 模拟路径至少记录请求。现在这些 path 只是“命中即成功”,既不反序列化 body,也不把命令挂到测试状态里。这样元数据链路的测试覆盖不到
metadataDir、目标资源和 cleanup 范围,序列化/路由回归会直接漏掉。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy` around lines 525 - 539, The four simulator handlers for NfsPrimaryStorageKVMBackend (WRITE_VM_METADATA_PATH, GET_VM_INSTANCE_METADATA_PATH, SCAN_VM_METADATA_PATH, CLEANUP_VM_METADATA_PATH) currently just return empty response objects; change each simulator(...) block to read and deserialize the incoming request body into the corresponding command type (e.g. WriteVmMetadataCmd -> produce WriteVmMetadataRsp, GetVmInstanceMetadataCmd -> GetVmInstanceMetadataRsp, ScanVmMetadataCmd -> ScanVmMetadataRsp, CleanupVmMetadataCmd -> CleanupVmMetadataRsp), and record the deserialized command into the test state/context (capture metadataDir, target resource identifiers and cleanup scope) so tests can assert on request contents and routing; keep the response behavior the same but ensure the command objects are stored in the test fixture/state for later verification.plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java (1)
96-104: 给新增接口方法补上 Javadoc。这组
handle(...)重载只靠签名很难看出hostUuid选择规则、失败语义,以及它们和handle(PrimaryStorageInventory, ...)的分工,接口层最好把约束写清楚。 As per coding guidelines "接口方法不应有多余的修饰符(例如public),且必须配有有效的 Javadoc 注释。"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java` around lines 96 - 104, Add Javadoc comments to each overloaded handle(...) method (UpdateVmInstanceMetadataOnPrimaryStorageMsg, GetVmInstanceMetadataFromPrimaryStorageMsg, ScanVmInstanceMetadataFromPrimaryStorageMsg, CleanupVmInstanceMetadataOnPrimaryStorageMsg, RebaseVolumeBackingFileOnPrimaryStorageMsg) that document the rule for choosing hostUuid (when it must be null vs the specific host), the expected failure semantics and how errors are reported via the ReturnValueCompletion reply, and the division of responsibility versus the other handle(PrimaryStorageInventory, ...) overload (which handles operations targeting a specific primary storage instance rather than a host). Ensure each method-level Javadoc is concise, follows project style, and clearly states preconditions, postconditions, and error propagation so callers know how to invoke these overloads.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java`:
- Around line 102-124: The current code unconditionally calls submitGC(...)
whenever reply.isSuccess() is false, causing permanent errors (e.g. invalid
path/params) to produce endless GC retries; modify the error-handling in the
callback so you inspect reply.getError() and only call submitGC when the error
is retryable. Concretely, implement a helper (e.g., isRetryableError(ErrorCode))
and in the block that currently calls submitGC(...) check that helper against
reply.getError().getCode()/ErrorCode before scheduling GC; for non-retryable
errors just log a clear warn/error and do not submit GC (or alternatively mark
the GC task with a terminal condition/max attempts in
CleanupVmInstanceMetadataOnPrimaryStorageGC).
In `@header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java`:
- Line 16: APIDeleteTagMsg currently references a non-existent Spring bean via
the `@MetadataImpact` annotation (MetadataImpact on class APIDeleteTagMsg with
resolver "SystemTagUuidToVmUuidResolver"), which breaks startup; either remove
the MetadataImpact annotation from APIDeleteTagMsg to avoid referencing the
missing resolver, or implement and register the missing resolver bean(s)
(SystemTagUuidToVmUuidResolver and the related VmUuidFromApiResolver hierarchy)
with correct semantics for generic tag deletion (ensure the resolver does not
assume only system tags). Locate the annotation on APIDeleteTagMsg and either
delete it or add the resolver classes as Spring components and wire them into
the MetadataImpact framework so startup can complete.
In
`@header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.java`:
- Around line 17-25: The class APIRegisterVmInstanceFromMetadataMsg is missing a
Javadoc API comment and the `@RestResponse` annotation; add a descriptive Javadoc
block above the class explaining the API purpose and parameters and annotate the
class with `@RestResponse`(APIRegisterVmInstanceFromMetadataEvent.class) so the
response is clearly documented; ensure the existing `@RestRequest` and
responseClass (APIRegisterVmInstanceFromMetadataEvent) remain unchanged and that
the response class extends APIEvent as required.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java`:
- Around line 1991-1998: The failure path for
factory.getConnectedHostForOperation(getSelfInventory()) is not converted into a
reply here, so handlers may throw instead of returning an error reply; change
this block to mirror the existing try/catch that wraps
getConnectedHostForOperation in an OperationFailureException-to-reply conversion
(as used elsewhere in this class) — i.e., call
factory.getConnectedHostForOperation(...) inside a try, catch
OperationFailureException and set reply.setError(operrFromEx) then
bus.reply(msg, reply) and return; reuse the same helper/exception handling
pattern used around getConnectedHostForOperation to ensure the "no connected
host" case always produces a reply instead of throwing.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java`:
- Around line 2157-2162: The reply does not set an empty vmInstanceMetadata list
when rsp.metadataEntries is null, causing inconsistent return contracts; in
NfsPrimaryStorageKVMBackend update the block around
ScanVmInstanceMetadataFromPrimaryStorageReply r so that
r.setVmInstanceMetadata(...) is always called: if rsp.metadataEntries is
non-null set hostUuid on each entry and set that list, otherwise set an empty
list (e.g. Collections.emptyList() or new ArrayList<>()), then call
completion.success(r) to ensure callers always receive a populated (possibly
empty) vmInstanceMetadata field.
In `@sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java`:
- Around line 28-30: The vmUuids field in CleanupVmInstanceMetadataAction lacks
a client-side maximum size check, allowing arbitrarily large batch requests; add
a validation in CleanupVmInstanceMetadataAction (e.g., in a validate() method or
the vmUuids setter) that enforces a maximum list size (match server limit, e.g.
100) and throws a clear IllegalArgumentException when vmUuids.size() > 100 so
oversized requests are rejected before reaching the backend.
---
Duplicate comments:
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java`:
- Around line 3491-3500: The current completion in LocalStorageBase (anonymous
WhileDoneCompletion handling errorCodeList, connectedHostUuids, reply, and
allSummaries) treats the operation as successful if at least one host returned
metadata; change the logic so any host failure causes an overall failure: if
errorCodeList.getCauses() is not empty, set reply.setError(operr(...)) (include
errorCodeList and failed host UUIDs in the message) and do not return partial
allSummaries; alternatively, if you prefer a partial-response API, add explicit
fields to the reply (e.g., setPartial(true) and setFailedHostUuids(...)) and
populate them—pick one approach and implement consistently in the block that
currently checks errorCodeList.getCauses().isEmpty() &&
size()==connectedHostUuids.size().
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java`:
- Around line 99-115: The validateMetadataPath method currently lets
buildMetadataDir() exceptions and null path NPEs propagate; change
validateMetadataPath(String primaryStorageUuid, String path) so it catches any
exceptions from buildMetadataDir(primaryStorageUuid) and treats null/invalid
path inputs safely, returning a descriptive error string instead of throwing;
specifically, wrap buildMetadataDir call in a try/catch returning a formatted
error message on failure, check path for null before using startsWith/endsWith,
and keep the existing uuid regex check, returning null only when the path is
valid.
---
Nitpick comments:
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java`:
- Around line 96-104: Add Javadoc comments to each overloaded handle(...) method
(UpdateVmInstanceMetadataOnPrimaryStorageMsg,
GetVmInstanceMetadataFromPrimaryStorageMsg,
ScanVmInstanceMetadataFromPrimaryStorageMsg,
CleanupVmInstanceMetadataOnPrimaryStorageMsg,
RebaseVolumeBackingFileOnPrimaryStorageMsg) that document the rule for choosing
hostUuid (when it must be null vs the specific host), the expected failure
semantics and how errors are reported via the ReturnValueCompletion reply, and
the division of responsibility versus the other handle(PrimaryStorageInventory,
...) overload (which handles operations targeting a specific primary storage
instance rather than a host). Ensure each method-level Javadoc is concise,
follows project style, and clearly states preconditions, postconditions, and
error propagation so callers know how to invoke these overloads.
In `@testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy`:
- Around line 525-539: The four simulator handlers for
NfsPrimaryStorageKVMBackend (WRITE_VM_METADATA_PATH,
GET_VM_INSTANCE_METADATA_PATH, SCAN_VM_METADATA_PATH, CLEANUP_VM_METADATA_PATH)
currently just return empty response objects; change each simulator(...) block
to read and deserialize the incoming request body into the corresponding command
type (e.g. WriteVmMetadataCmd -> produce WriteVmMetadataRsp,
GetVmInstanceMetadataCmd -> GetVmInstanceMetadataRsp, ScanVmMetadataCmd ->
ScanVmMetadataRsp, CleanupVmMetadataCmd -> CleanupVmMetadataRsp), and record the
deserialized command into the test state/context (capture metadataDir, target
resource identifiers and cleanup scope) so tests can assert on request contents
and routing; keep the response behavior the same but ensure the command objects
are stored in the test fixture/state for later verification.
🪄 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: a5042835-f156-4725-b95e-cb7bdff23682
⛔ Files ignored due to path filters (5)
conf/globalConfig/vm.xmlis excluded by!**/*.xmlconf/persistence.xmlis excluded by!**/*.xmlconf/serviceConfig/primaryStorage.xmlis excluded by!**/*.xmlconf/serviceConfig/vmInstance.xmlis excluded by!**/*.xmlconf/springConfigXml/VmInstanceManager.xmlis excluded by!**/*.xml
📒 Files selected for processing (146)
compute/src/main/java/org/zstack/compute/vm/CleanupVmInstanceMetadataOnPrimaryStorageGC.javacompute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.javacompute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.javacompute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.javacompute/src/main/java/org/zstack/compute/vm/VmSystemTags.javaconf/db/upgrade/V5.0.0__schema.sqlheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEvent.javaheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.javaheader/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.javaheader/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntryDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.javaheader/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.javaheader/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.javaheader/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.javaheader/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.javaheader/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.javaheader/src/main/java/org/zstack/header/vm/VmInstanceState.javaheader/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.javaheader/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.javaheader/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.javaheader/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO_.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.javaheader/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.javaheader/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.javaheader/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.javaheader/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.javaheader/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.javaheader/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.javaheader/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.javaresourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.javaresourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.javasdk/src/main/java/SourceClassMap.javasdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.javasdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.javasdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.javasdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.javasdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataAction.javasdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.javasdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageAction.javasdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.javasdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.javasdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.javasdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.javastorage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.javatestlib/src/main/java/org/zstack/testlib/ApiHelper.groovytestlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovytestlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
✅ Files skipped from review due to trivial changes (75)
- header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java
- header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntryDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.java
- header/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.java
- header/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.java
- header/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java
- header/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.java
- header/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.java
- header/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEvent.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.java
- header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO_.java
- header/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java
- header/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.java
- sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.java
- sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.java
- header/src/main/java/org/zstack/header/vm/VmInstanceState.java
- testlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovy
- sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.java
- sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java
- sdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.java
- sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java
- header/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.java
- header/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy
- sdk/src/main/java/SourceClassMap.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.java
🚧 Files skipped from review as they are similar to previous changes (40)
- header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.java
- header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.java
- header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.java
- header/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.java
- header/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovy
- resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java
- header/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.java
- header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.java
- header/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.java
- compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java
- conf/db/upgrade/V5.0.0__schema.sql
- header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.java
- resourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java
- header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.java
- compute/src/main/java/org/zstack/compute/vm/CleanupVmInstanceMetadataOnPrimaryStorageGC.java
- header/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.java
- plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java
- compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java
| if (reply.isSuccess()) { | ||
| logger.info(String.format("[MetadataExpunge] successfully deleted metadata for vm[uuid:%s] on ps[uuid:%s]", | ||
| vmUuid, finalPsUuid)); | ||
| } else { | ||
| logger.warn(String.format("[MetadataExpunge] failed to delete metadata for vm[uuid:%s] on ps[uuid:%s]: %s, " + | ||
| "submitting GC job for retry", vmUuid, finalPsUuid, reply.getError())); | ||
| submitGC(finalPsUuid, vmUuid, rootVolumeUuid, metadataPath, finalHostUuid); | ||
| } | ||
| trigger.next(); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| private void submitGC(String psUuid, String vmUuid, String rootVolumeUuid, String metadataPath, String hostUuid) { | ||
| CleanupVmInstanceMetadataOnPrimaryStorageGC gc = new CleanupVmInstanceMetadataOnPrimaryStorageGC(); | ||
| gc.NAME = CleanupVmInstanceMetadataOnPrimaryStorageGC.getGCName(vmUuid); | ||
| gc.primaryStorageUuid = psUuid; | ||
| gc.vmUuid = vmUuid; | ||
| gc.rootVolumeUuid = rootVolumeUuid; | ||
| gc.metadataPath = metadataPath; | ||
| gc.hostUuid = hostUuid; | ||
| long gcIntervalSec = TimeUnit.HOURS.toSeconds(VmGlobalConfig.VM_METADATA_CLEANUP_GC_INTERVAL.value(Long.class)); | ||
| gc.deduplicateSubmit(gcIntervalSec, TimeUnit.SECONDS); |
There was a problem hiding this comment.
不要把所有清理失败都无条件转成 GC 重试。
这里对任意 reply.isSuccess() == false 都提交 GC,没有区分可重试错误和永久错误。像路径或参数永久无效这类失败会持续制造无意义重试,建议按错误码过滤,或者在 GC 中设置明确的终止条件。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java`
around lines 102 - 124, The current code unconditionally calls submitGC(...)
whenever reply.isSuccess() is false, causing permanent errors (e.g. invalid
path/params) to produce endless GC retries; modify the error-handling in the
callback so you inspect reply.getError() and only call submitGC when the error
is retryable. Concretely, implement a helper (e.g., isRetryableError(ErrorCode))
and in the block that currently calls submitGC(...) check that helper against
reply.getError().getCode()/ErrorCode before scheduling GC; for non-retryable
errors just log a clear warn/error and do not submit GC (or alternatively mark
the GC task with a terminal condition/max attempts in
CleanupVmInstanceMetadataOnPrimaryStorageGC).
| method = HttpMethod.DELETE, | ||
| responseClass = APIDeleteTagEvent.class | ||
| ) | ||
| @MetadataImpact(value = MetadataImpact.Impact.CONFIG, resolver = "SystemTagUuidToVmUuidResolver", field = "uuid") |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 查找 SystemTagUuidToVmUuidResolver 的实现,确认其对非 VM 标签的处理逻辑
echo "=== 查找 SystemTagUuidToVmUuidResolver 实现 ==="
ast-grep --pattern 'class SystemTagUuidToVmUuidResolver $$$'
echo ""
echo "=== 搜索 resolver 的 resolve 方法实现 ==="
rg -n -A 20 'class SystemTagUuidToVmUuidResolver'
echo ""
echo "=== 检查 MetadataImpact 注解在其他非 VM 资源 API 上的使用模式 ==="
rg -n '@MetadataImpact.*SystemTagUuidToVmUuidResolver'Repository: MatheMatrix/zstack
Length of output: 560
🏁 Script executed:
#!/bin/bash
echo "=== 查找 MetadataImpact 注解定义 ==="
find . -type f -name "*.java" -exec grep -l "class MetadataImpact\|interface MetadataImpact" {} \;
echo ""
echo "=== 搜索 SystemTagUuidToVmUuidResolver(更宽泛的搜索) ==="
rg -i "SystemTagUuidToVmUuidResolver" --type java
echo ""
echo "=== 查找其他 resolver 的模式 ==="
rg 'resolver = "' --type java | head -20
echo ""
echo "=== 查看 APIDeleteTagMsg 的完整内容 ==="
cat -n header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java
echo ""
echo "=== 查看 APIUpdateSystemTagMsg 的完整内容(同样使用该 resolver)==="
cat -n header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.javaRepository: MatheMatrix/zstack
Length of output: 7333
🏁 Script executed:
#!/bin/bash
echo "=== 查看 MetadataImpact 注解定义 ==="
cat -n ./header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.java | head -50
echo ""
echo "=== 搜索 resolver 接口或基类定义 ==="
rg -i "interface.*Resolver|class.*Resolver" --type java | grep -i "metadata\|vm" | head -20
echo ""
echo "=== 搜索 SystemTagUuidToVmUuidResolver 的注册或定义 ==="
rg "SystemTagUuidToVmUuidResolver" -B 2 -A 5 --type java
echo ""
echo "=== 搜索如何查询标签关联的资源 ==="
rg "SystemTagVO\|Tag.*resourceUuid\|resourceUuid.*tag" --type java | head -15
echo ""
echo "=== 查看 SystemTagVO 定义 ==="
find . -name "SystemTagVO.java" -exec cat -n {} \; 2>/dev/null | head -40Repository: MatheMatrix/zstack
Length of output: 4332
🏁 Script executed:
#!/bin/bash
echo "=== 查看 VmUuidFromApiResolver 接口 ==="
cat -n ./header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.java
echo ""
echo "=== 查找所有 VmUuidFromApiResolver 的实现 ==="
rg "implements VmUuidFromApiResolver" --type java
echo ""
echo "=== 查找 SystemTagUuidToVmUuidResolver 类定义 ==="
rg "class SystemTagUuidToVmUuidResolver" -B 2 -A 30 --type java
echo ""
echo "=== 查看 TagAO 定义以了解标签结构 ==="
find . -name "TagAO.java" -exec cat -n {} \; 2>/dev/null | head -80Repository: MatheMatrix/zstack
Length of output: 3148
🏁 Script executed:
#!/bin/bash
echo "=== 搜索所有包含 SystemTagUuidToVmUuidResolver 的文件 ==="
git ls-files | xargs grep -l "SystemTagUuidToVmUuidResolver" 2>/dev/null
echo ""
echo "=== 搜索所有实现 VmUuidFromApiResolver 的类 ==="
rg "class.*implements.*VmUuidFromApiResolver" --type java
echo ""
echo "=== 搜索 `@Component` 或 `@Bean` 注册的 resolver ==="
rg "@Component|@Bean.*[Rr]esolver" --type java | head -30
echo ""
echo "=== 查找 tag 模块中的实现类 ==="
find . -path "*/tag/*" -name "*Resolver*.java" -type f
echo ""
echo "=== 搜索所有继承或实现 Resolver 的类 ==="
rg "VmUuidFromApiResolver" --type javaRepository: MatheMatrix/zstack
Length of output: 1045
🏁 Script executed:
#!/bin/bash
echo "=== 查找 MetadataImpact 的使用处理器 ==="
rg "MetadataImpact" --type java | grep -v "@MetadataImpact" | head -20
echo ""
echo "=== 查找所有其他 resolver 的定义 ==="
rg "VolumeUuidToVmUuidResolver\|ResourceUuidToVmUuidResolver\|VmUuidDirectResolver" --type java | grep -v "@MetadataImpact" | head -20
echo ""
echo "=== 搜索 resolver 的 Spring bean 注册 ==="
rg "@Bean.*[Rr]esolver|Bean.*name.*[Rr]esolver" -B 2 -A 5 --type java | head -40
echo ""
echo "=== 查找如何加载和使用 resolver ==="
rg "resolveVmUuid\|VmUuidFromApiResolver" -B 3 -A 3 --type java | head -50Repository: MatheMatrix/zstack
Length of output: 2857
🏁 Script executed:
#!/bin/bash
echo "=== 查找处理 MetadataImpact 的拦截器/切面 ==="
rg "getAnnotation.*MetadataImpact|MetadataImpact.*getAnnotation" --type java
echo ""
echo "=== 查找 Interceptor 或 Aspect 相关的类 ==="
rg "class.*Interceptor.*|class.*Aspect.*" --type java | grep -i "metadata\|tag" | head -20
echo ""
echo "=== 搜索所有 Interceptor 类 ==="
find . -name "*Interceptor*.java" -type f | head -20
echo ""
echo "=== 查找 getAnnotation 的使用 ==="
rg "\.getAnnotation\(MetadataImpact" --type java
echo ""
echo "=== 检查是否有 tag 相关的 plugin ==="
find . -type d -name "*tag*" | head -20Repository: MatheMatrix/zstack
Length of output: 2330
🏁 Script executed:
#!/bin/bash
echo "=== 查看 TagApiInterceptor 实现 ==="
cat -n ./tag/src/main/java/org/zstack/tag/TagApiInterceptor.java | head -100
echo ""
echo "=== 查找 Spring bean 配置文件 ==="
find . -name "*.xml" -o -name "*Config*.java" | xargs grep -l "SystemTagUuidToVmUuidResolver\|resolver" 2>/dev/null | head -10
echo ""
echo "=== 查看 tag 模块的启动配置 ==="
find ./tag -name "*Impl.java" -type f | head -10Repository: MatheMatrix/zstack
Length of output: 4942
🏁 Script executed:
#!/bin/bash
echo "=== 获取 TagApiInterceptor.validate(APIDeleteTagMsg) 的完整实现 ==="
sed -n '98,150p' ./tag/src/main/java/org/zstack/tag/TagApiInterceptor.java
echo ""
echo "=== 查找所有处理 MetadataImpact 的代码 ==="
rg "\.class\.getAnnotation\|getAnnotation.*Type|@interface.*Metadata" --type java | head -20
echo ""
echo "=== 查看 APIDeleteTagMsg 实际是否删除所有标签还是仅系统标签 ==="
rg -B 5 -A 10 "APIDeleteTagMsg" tag/src/main/java/org/zstack/tag/TagManagerImpl.java | head -50
echo ""
echo "=== 查找 resolver 定义位置 ==="
find . -name "*.java" -type f -exec grep -l "implements VmUuidFromApiResolver" {} \; 2>/dev/nullRepository: MatheMatrix/zstack
Length of output: 4253
🏁 Script executed:
#!/bin/bash
echo "=== 查找 resolver 的动态加载或工厂模式 ==="
rg "getBean.*Resolver\|newResolver\|createResolver" --type java | head -20
echo ""
echo "=== 确认 MetadataImpact 的处理器 ==="
rg "beforeSend\|beforePublish\|intercept.*metadata" --type java | head -30
echo ""
echo "=== 查看 APIDeleteTagMsg 和 APIUpdateSystemTagMsg 是否不同 ==="
echo "APIDeleteTagMsg 的完整代码:"
wc -l header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java
echo ""
echo "APIUpdateSystemTagMsg 的完整代码:"
wc -l header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java
echo ""
echo "=== 最后验证:是否有其他 resolver 的实现存在? ==="
rg "VolumeUuidToVmUuidResolver\|ResourceUuidToVmUuidResolver\|VmUuidDirectResolver" --type java | grep -E "class|implements" | head -10Repository: MatheMatrix/zstack
Length of output: 410
删除 @MetadataImpact 注解或补充缺失的 Resolver 实现。
SystemTagUuidToVmUuidResolver 引用的 Spring Bean 在代码库中不存在。该 Resolver 及整个 VmUuidFromApiResolver 实现体系都未被定义,导致运行时 Spring 会因无法装配该 Bean 而失败。
此外,APIDeleteTagMsg 是通用标签删除 API,可删除任意类型标签(UserTagVO、SystemTagVO、TagPatternVO),而注解名称 SystemTagUuidToVmUuidResolver 隐含仅针对系统标签的假设,两者存在语义不匹配。
建议:
- 如果 MetadataImpact 框架已完成,补充 Resolver 实现;
- 如果框架仍在开发,暂时移除该注解。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java` at line 16,
APIDeleteTagMsg currently references a non-existent Spring bean via the
`@MetadataImpact` annotation (MetadataImpact on class APIDeleteTagMsg with
resolver "SystemTagUuidToVmUuidResolver"), which breaks startup; either remove
the MetadataImpact annotation from APIDeleteTagMsg to avoid referencing the
missing resolver, or implement and register the missing resolver bean(s)
(SystemTagUuidToVmUuidResolver and the related VmUuidFromApiResolver hierarchy)
with correct semantics for generic tag deletion (ensure the resolver does not
assume only system tags). Locate the annotation on APIDeleteTagMsg and either
delete it or add the resolver classes as Spring components and wire them into
the MetadataImpact framework so startup can complete.
| @TagResourceType(VmInstanceVO.class) | ||
| @RestRequest( | ||
| path = "/vm-instances/metadata/register", | ||
| method = HttpMethod.POST, | ||
| responseClass = APIRegisterVmInstanceFromMetadataEvent.class, | ||
| parameterName = "params" | ||
| ) | ||
| @DefaultTimeout(timeunit = TimeUnit.HOURS, value = 1) | ||
| public class APIRegisterVmInstanceFromMetadataMsg extends APIMessage { |
There was a problem hiding this comment.
建议补充 API 注释块并标注 @RestResponse。
当前类缺少 API 说明注释,建议补充,避免新 API 在文档规范上与现有消息类不一致。
📝 建议补丁
`@TagResourceType`(VmInstanceVO.class)
+/**
+ * `@api` register vm instance from metadata
+ * `@category` vm
+ * `@cli`
+ * `@msg` {}
+ * `@httpMsg` {}
+ * `@result` see :ref:`APIRegisterVmInstanceFromMetadataEvent`
+ * `@since` 5.0.0
+ * `@RestResponse`(allTo = "APIRegisterVmInstanceFromMetadataEvent")
+ */
`@RestRequest`(
path = "/vm-instances/metadata/register",
method = HttpMethod.POST,As per coding guidelines “API 消息类需要继承 APIMessage;其返回类必须继承 APIReply 或 APIEvent,并在注释中用 @RestResponse 进行标注。”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.java`
around lines 17 - 25, The class APIRegisterVmInstanceFromMetadataMsg is missing
a Javadoc API comment and the `@RestResponse` annotation; add a descriptive
Javadoc block above the class explaining the API purpose and parameters and
annotate the class with
`@RestResponse`(APIRegisterVmInstanceFromMetadataEvent.class) so the response is
clearly documented; ensure the existing `@RestRequest` and responseClass
(APIRegisterVmInstanceFromMetadataEvent) remain unchanged and that the response
class extends APIEvent as required.
plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java
Show resolved
Hide resolved
| ScanVmInstanceMetadataFromPrimaryStorageReply r = new ScanVmInstanceMetadataFromPrimaryStorageReply(); | ||
| if (rsp.metadataEntries != null) { | ||
| rsp.metadataEntries.forEach(entry -> entry.setHostUuid(hostUuid)); | ||
| r.setVmInstanceMetadata(rsp.metadataEntries); | ||
| } | ||
| completion.success(r); |
There was a problem hiding this comment.
空扫描结果也要回填空列表。
metadataEntries == null 时这里直接返回默认 reply,vmInstanceMetadata 会保持未设置状态;这会让 NFS 和 LocalStorage 两个 backend 的返回契约不一致,也给上层引入额外的判空分支。
💡 建议修改
ScanVmInstanceMetadataFromPrimaryStorageReply r = new ScanVmInstanceMetadataFromPrimaryStorageReply();
if (rsp.metadataEntries != null) {
rsp.metadataEntries.forEach(entry -> entry.setHostUuid(hostUuid));
r.setVmInstanceMetadata(rsp.metadataEntries);
+ } else {
+ r.setVmInstanceMetadata(Collections.emptyList());
}
completion.success(r);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java`
around lines 2157 - 2162, The reply does not set an empty vmInstanceMetadata
list when rsp.metadataEntries is null, causing inconsistent return contracts; in
NfsPrimaryStorageKVMBackend update the block around
ScanVmInstanceMetadataFromPrimaryStorageReply r so that
r.setVmInstanceMetadata(...) is always called: if rsp.metadataEntries is
non-null set hostUuid on each entry and set that list, otherwise set an empty
list (e.g. Collections.emptyList() or new ArrayList<>()), then call
completion.success(r) to ensure callers always receive a populated (possibly
empty) vmInstanceMetadata field.
| @Param(required = true, nonempty = true, nullElements = false, emptyString = true, noTrim = false) | ||
| public java.util.List vmUuids; | ||
|
|
There was a problem hiding this comment.
vmUuids 缺少数量上限,存在大批量请求风险。
建议在 SDK 侧增加前置校验(并与服务端上限保持一致,例如 100),避免超大请求直接进入后端清理流程。
🛠 建议补丁
public class CleanupVmInstanceMetadataAction extends AbstractAction {
+ private static final int MAX_VM_UUIDS = 100;
@@
`@Param`(required = true, nonempty = true, nullElements = false, emptyString = true, noTrim = false)
public java.util.List vmUuids;
@@
+ private void validateVmUuids() {
+ if (vmUuids != null && vmUuids.size() > MAX_VM_UUIDS) {
+ throw new ApiException(String.format("vmUuids size cannot exceed %s", MAX_VM_UUIDS));
+ }
+ }
+
public Result call() {
+ validateVmUuids();
ApiResult res = ZSClient.call(this);
return makeResult(res);
}
@@
public void call(final Completion<Result> completion) {
+ validateVmUuids();
ZSClient.call(this, new InternalCompletion() {
`@Override`
public void complete(ApiResult res) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java` around
lines 28 - 30, The vmUuids field in CleanupVmInstanceMetadataAction lacks a
client-side maximum size check, allowing arbitrarily large batch requests; add a
validation in CleanupVmInstanceMetadataAction (e.g., in a validate() method or
the vmUuids setter) that enforces a maximum list size (match server limit, e.g.
100) and throws a clear IllegalArgumentException when vmUuids.size() > 100 so
oversized requests are rejected before reaching the backend.
1d82d97 to
f0d16ea
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (7)
plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.java (1)
966-967: 多余的空行。Lines 966-967 之间有多余的空行,建议删除以保持代码风格一致。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.java` around lines 966 - 967, The file contains an extra blank line before the declaration of the GetVmInstanceMetadataCmd class; remove the stray empty line between the previous code and the "public static class GetVmInstanceMetadataCmd extends NfsPrimaryStorageAgentCommand {" declaration so the class starts immediately after the prior statement, keeping formatting consistent around GetVmInstanceMetadataCmd.sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.java (2)
28-35: 建议使用泛型类型参数。
vmUuids、systemTags和userTags字段使用了原始类型List,建议使用泛型类型(如List<String>)以提高类型安全性并消除编译器警告。如果此文件是自动生成的 SDK 代码,可忽略此建议。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.java` around lines 28 - 35, The fields vmUuids, systemTags and userTags in class UpdateVmInstanceMetadataAction are declared with raw List types; change them to use generics (e.g., List<String>) to improve type safety and remove compiler warnings: update the declarations of vmUuids, systemTags and userTags to parameterize the List type consistently across the class (including any getters/setters or usages) so compilation and API contracts reflect the element type.
5-5: 冗余的通配符导入。
import org.zstack.sdk.*;是冗余的,因为当前类已经在org.zstack.sdk包中。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.java` at line 5, 当前类 UpdateVmInstanceMetadataAction 位于 org.zstack.sdk 包内,故行中的通配符导入 import org.zstack.sdk.*; 是多余的;请删除该冗余导入行,保留或添加只需要的显式导入(若有外部类型未解析的话)以消除编译器或 IDE 的警告,确保类仍能正确引用其它类型。sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java (1)
31-35: 建议使用泛型类型参数。与
UpdateVmInstanceMetadataAction类似,systemTags和userTags使用了原始类型List。如果此文件是自动生成的 SDK 代码,可忽略此建议。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java` around lines 31 - 35, GetVmInstanceMetadataFromPrimaryStorageAction declares systemTags and userTags as raw java.util.List; change them to use appropriate generic type parameters (e.g., java.util.List<String> or the same generic used in UpdateVmInstanceMetadataAction) to avoid raw-type warnings. Update the field declarations for systemTags and userTags in the GetVmInstanceMetadataFromPrimaryStorageAction class, and ensure any getters/setters or usages are updated to the same generic type so compilation and type-safety are preserved.testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy (1)
525-540: LGTM! 四个新的 VM 元数据操作模拟器遵循现有模式。代码正确地为 VM 元数据 API(写入、获取、扫描、清理)添加了基础模拟器,返回空响应对象。这与文件中其他仅模拟器实现(如
PING_PATH、UPLOAD_TO_SFTP_PATH)的模式一致。可选建议:后续如需更完整的 VFS 测试
如果后续测试用例需要验证元数据文件在虚拟文件系统中的实际读写行为,可以参考现有模式(如
DELETE_PATH、CHECK_BITS_PATH)添加对应的VFS.vfsHook实现。基于已有学习记录,VFS hooks 对于完整测试 NFS 操作非常重要。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy` around lines 525 - 540, The four new VM metadata simulators (NfsPrimaryStorageKVMBackend.WRITE_VM_METADATA_PATH, GET_VM_INSTANCE_METADATA_PATH, SCAN_VM_METADATA_PATH, CLEANUP_VM_METADATA_PATH) are correct as simple responders; if you need fuller VFS-level testing later, implement VFS.vfsHook handlers similar to DELETE_PATH and CHECK_BITS_PATH to simulate actual metadata file read/write behavior and verify on-disk state during tests so the simulator returns realistic responses for WriteVmMetadataRsp, GetVmInstanceMetadataRsp, ScanVmMetadataRsp and CleanupVmMetadataRsp.plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java (1)
80-89: calculatePathReplacements 中的 fallback 逻辑与 resolveBaseDir 一致。这里复制了
resolveBaseDir中的mountPath -> urlfallback 逻辑。如果之前关于 url vs mountPath 语义差异的问题需要修复,这里也需要同步更新。考虑提取公共方法避免逻辑分散。建议统一使用 resolveBaseDir
`@Override` public PathReplacementResult calculatePathReplacements(String targetPsUuid, List<String> allOldPaths) { if (allOldPaths == null || allOldPaths.isEmpty()) { PathReplacementResult result = new PathReplacementResult(); result.setMetadataToCurrentPathMap(Collections.emptyMap()); return result; } - String baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.mountPath).eq(PrimaryStorageVO_.uuid, targetPsUuid).findValue(); - if (baseDir == null) { - baseDir = Q.New(PrimaryStorageVO.class).select(PrimaryStorageVO_.url).eq(PrimaryStorageVO_.uuid, targetPsUuid).findValue(); - } - if (baseDir == null) { + final String baseDir; + try { + baseDir = resolveBaseDir(targetPsUuid); + } catch (CloudRuntimeException e) { logger.warn(String.format("NFS PS[uuid:%s] has no mountPath or url, path replacement disabled", targetPsUuid)); PathReplacementResult result = new PathReplacementResult(); result.setMetadataToCurrentPathMap(Collections.emptyMap()); return result; } - String newPrefix = baseDir.endsWith("/") ? baseDir : baseDir + "/"; + String newPrefix = baseDir + "/";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java` around lines 80 - 89, The duplicated fallback logic in calculatePathReplacements (checking PrimaryStorageVO.mountPath then .url) should be removed and the method should call and reuse resolveBaseDir to obtain baseDir; update calculatePathReplacements to call resolveBaseDir(targetPsUuid) (or the appropriate resolveBaseDir signature), handle a null return the same way it currently does (log warning, create PathReplacementResult with empty map), and remove the local mountPath->url lookup to avoid divergent semantics between calculatePathReplacements and resolveBaseDir.plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java (1)
944-952: 冗余的完全限定类名。
PrefixRebaseBackingFilesCmd和PrefixRebaseBackingFilesRsp在继承时使用了完全限定类名LocalStorageKvmBackend.AgentCommand和LocalStorageKvmBackend.AgentResponse,但由于它们是同一个类的内部类,可以直接使用AgentCommand和AgentResponse。♻️ 简化继承声明
- public static class PrefixRebaseBackingFilesCmd extends LocalStorageKvmBackend.AgentCommand { + public static class PrefixRebaseBackingFilesCmd extends AgentCommand { public List<String> filePaths; public String oldPrefix; public String newPrefix; } - public static class PrefixRebaseBackingFilesRsp extends LocalStorageKvmBackend.AgentResponse { + public static class PrefixRebaseBackingFilesRsp extends AgentResponse { public int rebasedCount; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java` around lines 944 - 952, 当前两个内部类 PrefixRebaseBackingFilesCmd 和 PrefixRebaseBackingFilesRsp 使用了冗余的完全限定父类名 LocalStorageKvmBackend.AgentCommand 和 LocalStorageKvmBackend.AgentResponse;请改为直接继承内部类型 AgentCommand 和 AgentResponse(即将 "LocalStorageKvmBackend.AgentCommand" -> "AgentCommand" 与 "LocalStorageKvmBackend.AgentResponse" -> "AgentResponse"),以简化声明并保持与同一外部类的其他内部类一致。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java`:
- Around line 134-145: The createResourceRef method currently calls
dbf.persist(ref) unconditionally and can violate the composite primary key
(resourceUuid, primaryStorageUuid, hostUuid) when retries/concurrent calls
occur; update createResourceRef (and follow the pattern used in
LocalStorageBase.java) to first query the LocalStorageResourceRefVO by the full
key combination (resourceUuid + primaryStorageUuid + hostUuid) and only persist
if no existing record is found (or update/return the existing record), ensuring
the existence check uses the same three fields that form the VO's composite key
to prevent duplicate-insert primary key errors.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java`:
- Around line 52-70: The validateMetadataPath method should not let
CloudRuntimeException from buildMetadataDir(primaryStorageUuid) propagate; wrap
the call to buildMetadataDir(primaryStorageUuid) in a try/catch for
CloudRuntimeException (or RuntimeException if necessary) inside
validateMetadataPath and return a validation error string (e.g.
"metadataPath[...] failed to build metadata dir: <exception message>" or similar
consistent message) instead of throwing; keep existing checks for prefix/suffix
and uuidPart unchanged and use the same return-null-on-success behavior.
---
Nitpick comments:
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.java`:
- Around line 944-952: 当前两个内部类 PrefixRebaseBackingFilesCmd 和
PrefixRebaseBackingFilesRsp 使用了冗余的完全限定父类名 LocalStorageKvmBackend.AgentCommand 和
LocalStorageKvmBackend.AgentResponse;请改为直接继承内部类型 AgentCommand 和 AgentResponse(即将
"LocalStorageKvmBackend.AgentCommand" -> "AgentCommand" 与
"LocalStorageKvmBackend.AgentResponse" ->
"AgentResponse"),以简化声明并保持与同一外部类的其他内部类一致。
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.java`:
- Around line 966-967: The file contains an extra blank line before the
declaration of the GetVmInstanceMetadataCmd class; remove the stray empty line
between the previous code and the "public static class GetVmInstanceMetadataCmd
extends NfsPrimaryStorageAgentCommand {" declaration so the class starts
immediately after the prior statement, keeping formatting consistent around
GetVmInstanceMetadataCmd.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java`:
- Around line 80-89: The duplicated fallback logic in calculatePathReplacements
(checking PrimaryStorageVO.mountPath then .url) should be removed and the method
should call and reuse resolveBaseDir to obtain baseDir; update
calculatePathReplacements to call resolveBaseDir(targetPsUuid) (or the
appropriate resolveBaseDir signature), handle a null return the same way it
currently does (log warning, create PathReplacementResult with empty map), and
remove the local mountPath->url lookup to avoid divergent semantics between
calculatePathReplacements and resolveBaseDir.
In
`@sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.java`:
- Around line 31-35: GetVmInstanceMetadataFromPrimaryStorageAction declares
systemTags and userTags as raw java.util.List; change them to use appropriate
generic type parameters (e.g., java.util.List<String> or the same generic used
in UpdateVmInstanceMetadataAction) to avoid raw-type warnings. Update the field
declarations for systemTags and userTags in the
GetVmInstanceMetadataFromPrimaryStorageAction class, and ensure any
getters/setters or usages are updated to the same generic type so compilation
and type-safety are preserved.
In `@sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.java`:
- Around line 28-35: The fields vmUuids, systemTags and userTags in class
UpdateVmInstanceMetadataAction are declared with raw List types; change them to
use generics (e.g., List<String>) to improve type safety and remove compiler
warnings: update the declarations of vmUuids, systemTags and userTags to
parameterize the List type consistently across the class (including any
getters/setters or usages) so compilation and API contracts reflect the element
type.
- Line 5: 当前类 UpdateVmInstanceMetadataAction 位于 org.zstack.sdk 包内,故行中的通配符导入
import org.zstack.sdk.*; 是多余的;请删除该冗余导入行,保留或添加只需要的显式导入(若有外部类型未解析的话)以消除编译器或 IDE
的警告,确保类仍能正确引用其它类型。
In `@testlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy`:
- Around line 525-540: The four new VM metadata simulators
(NfsPrimaryStorageKVMBackend.WRITE_VM_METADATA_PATH,
GET_VM_INSTANCE_METADATA_PATH, SCAN_VM_METADATA_PATH, CLEANUP_VM_METADATA_PATH)
are correct as simple responders; if you need fuller VFS-level testing later,
implement VFS.vfsHook handlers similar to DELETE_PATH and CHECK_BITS_PATH to
simulate actual metadata file read/write behavior and verify on-disk state
during tests so the simulator returns realistic responses for
WriteVmMetadataRsp, GetVmInstanceMetadataRsp, ScanVmMetadataRsp and
CleanupVmMetadataRsp.
🪄 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: 5ecd76b5-1569-432f-82cc-d2e4b379563d
⛔ Files ignored due to path filters (5)
conf/globalConfig/vm.xmlis excluded by!**/*.xmlconf/persistence.xmlis excluded by!**/*.xmlconf/serviceConfig/primaryStorage.xmlis excluded by!**/*.xmlconf/serviceConfig/vmInstance.xmlis excluded by!**/*.xmlconf/springConfigXml/VmInstanceManager.xmlis excluded by!**/*.xml
📒 Files selected for processing (146)
compute/src/main/java/org/zstack/compute/vm/CleanupVmInstanceMetadataOnPrimaryStorageGC.javacompute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.javacompute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.javacompute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.javacompute/src/main/java/org/zstack/compute/vm/VmSystemTags.javaconf/db/upgrade/V5.0.0__schema.sqlheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEvent.javaheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.javaheader/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.javaheader/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntryDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIRevertVolumeFromSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.javaheader/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.javaheader/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.javaheader/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachL3NetworkToVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeInstanceOfferingMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.javaheader/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.javaheader/src/main/java/org/zstack/header/vm/APIConvertTemplatedVmInstanceToVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.javaheader/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.javaheader/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.javaheader/src/main/java/org/zstack/header/vm/APIRecoverVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootOrderMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.javaheader/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.javaheader/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.javaheader/src/main/java/org/zstack/header/vm/VmInstanceState.javaheader/src/main/java/org/zstack/header/vm/cdrom/APISetVmInstanceDefaultCdRomMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.javaheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovyheader/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.javaheader/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageMsg.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.javaheader/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.javaheader/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.javaheader/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO_.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.javaheader/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.javaheader/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.javaheader/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.javaheader/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.javaheader/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotGroupMsg.javaheader/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.javaheader/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIDetachDataVolumeFromVmMsg.javaheader/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.javaheader/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.javaheader/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.javaheader/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageKvmBackend.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.javaplugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackendCommands.javaplugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.javaresourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.javaresourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.javasdk/src/main/java/SourceClassMap.javasdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.javasdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.javasdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageAction.javasdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.javasdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataAction.javasdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.javasdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageAction.javasdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.javasdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataAction.javasdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.javasdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.javastorage/src/main/java/org/zstack/storage/primary/PrimaryStorageBase.javatestlib/src/main/java/org/zstack/testlib/ApiHelper.groovytestlib/src/main/java/org/zstack/testlib/LocalStorageSpec.groovytestlib/src/main/java/org/zstack/testlib/NfsPrimaryStorageSpec.groovy
✅ Files skipped from review due to trivial changes (75)
- header/src/main/java/org/zstack/header/vm/APIUpdateVmInstanceMsg.java
- resourceconfig/src/main/java/org/zstack/resourceconfig/APIDeleteResourceConfigMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/APISetVmQxlMemoryMsg.java
- header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/APISetVmStaticIpMsg.java
- sdk/src/main/java/org/zstack/sdk/UpdateVmInstanceMetadataResult.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataCategory.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIUpdateVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmHostnameMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIUngroupVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/volume/APIChangeVolumeStateMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataReply.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataReply.java
- header/src/main/java/org/zstack/header/tag/APICreateSystemTagMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmSoundTypeMsg.java
- sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageResult.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIShrinkVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/metadata/VolumeResourceMetadata.java
- header/src/main/java/org/zstack/header/tag/APICreateSystemTagsMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIUpdateVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/volume/APIUpdateVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsgDoc_zh_cn.groovy
- sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataResult.java
- header/src/main/java/org/zstack/header/storage/primary/ReadVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/APIReimageVmInstanceMsg.java
- header/src/main/java/org/zstack/header/tag/APIDeleteTagMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmSshKeyMsg.java
- header/src/main/java/org/zstack/header/volume/APIExpungeDataVolumeMsg.java
- sdk/src/main/java/org/zstack/sdk/GetVmInstanceMetadataFromPrimaryStorageResult.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/ResourceMetadata.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmUuidFromApiResolver.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmStaticIpMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/APIConvertVmInstanceToTemplatedVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIAttachIsoToVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmBootModeMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/UpdateVmInstanceMetadataOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.java
- header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntry.java
- header/src/main/java/org/zstack/header/volume/APISyncVolumeSizeMsg.java
- header/src/main/java/org/zstack/header/tag/APIUpdateSystemTagMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO_.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathBuildExtensionPoint.java
- header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyService.java
- header/src/main/java/org/zstack/header/storage/primary/CleanupVmInstanceMetadataOnPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageMsg.java
- sdk/src/main/java/SourceClassMap.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataPathReplacementExtensionPoint.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/storage/primary/GetVmInstanceMetadataFromPrimaryStorageMsg.java
- sdk/src/main/java/org/zstack/sdk/VmMetadataScanEntry.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataFingerprintVO.java
- header/src/main/java/org/zstack/header/vm/metadata/APICleanupVmInstanceMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/metadata/APIRegisterVmInstanceFromMetadataEvent.java
- header/src/main/java/org/zstack/header/vm/APIDetachL3NetworkFromVmMsg.java
- conf/db/upgrade/V5.0.0__schema.sql
- header/src/main/java/org/zstack/header/storage/primary/RebaseVolumeBackingFileOnPrimaryStorageMsg.java
- sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataResult.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataDirtyVO_.java
- sdk/src/main/java/org/zstack/sdk/CleanupVmInstanceMetadataAction.java
- header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataDTO.java
- header/src/main/java/org/zstack/header/vm/APIDetachIsoFromVmInstanceMsg.java
🚧 Files skipped from review as they are similar to previous changes (47)
- header/src/main/java/org/zstack/header/storage/primary/VmMetadataScanEntryDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/vm/APIChangeVmNicStateMsg.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/APILocalStorageMigrateVolumeMsg.java
- header/src/main/java/org/zstack/header/volume/APIAttachDataVolumeToVmMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataEventDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIDeleteVolumeSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/volume/APIDeleteDataVolumeMsg.java
- header/src/main/java/org/zstack/header/volume/APIUndoSnapshotCreationMsg.java
- header/src/main/java/org/zstack/header/volume/APIRecoverDataVolumeMsg.java
- header/src/main/java/org/zstack/header/storage/snapshot/APIDeleteVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/vm/APIChangeVmNicNetworkMsg.java
- header/src/main/java/org/zstack/header/volume/APICreateVolumeSnapshotMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmClockTrackMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmConsolePasswordMsg.java
- header/src/main/java/org/zstack/header/vm/APIDestroyVmInstanceMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmBootModeMsg.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmConsolePasswordMsg.java
- header/src/main/java/org/zstack/header/vm/APIAttachVmNicToVmMsg.java
- header/src/main/java/org/zstack/header/vm/APISetVmSshKeyMsg.java
- header/src/main/java/org/zstack/header/volume/APIFlattenVolumeMsg.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmNicDriverMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/APIUpdateVmInstanceMetadataMsg.java
- header/src/main/java/org/zstack/header/storage/primary/ScanVmInstanceMetadataFromPrimaryStorageReply.java
- header/src/main/java/org/zstack/header/vm/APIDeleteVmHostnameMsg.java
- header/src/main/java/org/zstack/header/vm/APIMigrateVmMsg.java
- header/src/main/java/org/zstack/header/vm/APIUpdateVmPriorityMsg.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulatorConfig.java
- header/src/main/java/org/zstack/header/vm/metadata/APIGetVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/MetadataImpact.java
- resourceconfig/src/main/java/org/zstack/resourceconfig/APIUpdateResourceConfigMsg.java
- header/src/main/java/org/zstack/header/vm/metadata/VmInstanceMetadataConstants.java
- header/src/main/java/org/zstack/header/vm/metadata/VmMetadataErrors.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageHypervisorBackend.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageEvent.java
- compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java
- header/src/main/java/org/zstack/header/storage/snapshot/group/APIRevertVmFromSnapshotGroupMsg.java
- header/src/main/java/org/zstack/header/storage/primary/APIScanVmInstanceMetadataFromPrimaryStorageMsgDoc_zh_cn.groovy
- plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageBackend.java
- sdk/src/main/java/org/zstack/sdk/RegisterVmInstanceFromMetadataAction.java
- compute/src/main/java/org/zstack/compute/vm/CleanupVmInstanceMetadataOnPrimaryStorageGC.java
- compute/src/main/java/org/zstack/compute/vm/VmGlobalConfig.java
- sdk/src/main/java/org/zstack/sdk/ScanVmInstanceMetadataFromPrimaryStorageAction.java
- plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageSimulator.java
- plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorage.java
- plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsPrimaryStorageKVMBackend.java
- compute/src/main/java/org/zstack/compute/vm/VmExpungeMetadataFlow.java
| private void createResourceRef(String primaryStorageUuid, String resourceUuid, | ||
| String resourceType, String hostUuid, long size, Timestamp now) { | ||
| LocalStorageResourceRefVO ref = new LocalStorageResourceRefVO(); | ||
| ref.setPrimaryStorageUuid(primaryStorageUuid); | ||
| ref.setResourceUuid(resourceUuid); | ||
| ref.setResourceType(resourceType); | ||
| ref.setHostUuid(hostUuid); | ||
| ref.setSize(size); | ||
| ref.setCreateDate(now); | ||
| ref.setLastOpDate(now); | ||
| dbf.persist(ref); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 检查 LocalStorageResourceRefVO 的主键和唯一约束定义
ast-grep --pattern $'class LocalStorageResourceRefVO {
$$$
}'Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
#!/bin/bash
# Find the LocalStorageResourceRefVO class file
fd -t f "LocalStorageResourceRefVO" --extension javaRepository: MatheMatrix/zstack
Length of output: 378
🏁 Script executed:
#!/bin/bash
# If the above doesn't find it, search by name pattern
find . -type f -name "*LocalStorageResourceRef*" | head -20Repository: MatheMatrix/zstack
Length of output: 1294
🏁 Script executed:
#!/bin/bash
# Also check for any entity/model files in the local storage plugin directory
fd -t f -e java . plugin/localstorage | grep -i "ref\|model\|entity" | head -20Repository: MatheMatrix/zstack
Length of output: 1205
🏁 Script executed:
#!/bin/bash
# Read the LocalStorageResourceRefVO class definition
cat -n plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageResourceRefVO.javaRepository: MatheMatrix/zstack
Length of output: 3495
🏁 Script executed:
#!/bin/bash
# Read the CompositePrimaryKeyForLocalStorageResourceRefVO class
cat -n plugin/localstorage/src/main/java/org/zstack/storage/primary/local/CompositePrimaryKeyForLocalStorageResourceRefVO.javaRepository: MatheMatrix/zstack
Length of output: 2616
🏁 Script executed:
#!/bin/bash
# Find all call sites of createResourceRef
rg "createResourceRef" plugin/localstorage/src/main/java/org/zstack/storage/primary/local/ -B 3 -A 3Repository: MatheMatrix/zstack
Length of output: 8722
🏁 Script executed:
#!/bin/bash
# Check the full LocalStorageVmMetadataExtension class to understand context
wc -l plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.javaRepository: MatheMatrix/zstack
Length of output: 169
🏁 Script executed:
#!/bin/bash
# Get the full context of the idempotency check in LocalStorageBase.java
rg -B 5 -A 8 "LocalStorageResourceRefVO_.hostUuid" plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageBase.java | head -40Repository: MatheMatrix/zstack
Length of output: 2217
🏁 Script executed:
#!/bin/bash
# Find all implementations of afterVolumePersist and afterSnapshotPersist
rg "afterVolumePersist|afterSnapshotPersist" plugin/localstorage/src/main/java/org/zstack/storage/primary/local/ -lRepository: MatheMatrix/zstack
Length of output: 165
🏁 Script executed:
#!/bin/bash
# Check the interface definition
fd -type f -name "*.java" -path "*/header/*" | xargs rg -l "afterVolumePersist|afterSnapshotPersist" | head -5Repository: MatheMatrix/zstack
Length of output: 449
🏁 Script executed:
#!/bin/bash
# Read the VmMetadataResourcePersistExtensionPoint interface
cat -n header/src/main/java/org/zstack/header/vm/metadata/VmMetadataResourcePersistExtensionPoint.javaRepository: MatheMatrix/zstack
Length of output: 645
🏁 Script executed:
#!/bin/bash
# Search for all calls to afterVolumePersist or afterSnapshotPersist
rg "afterVolumePersist\(|afterSnapshotPersist\(" --type java -B 2 -A 2 | head -50Repository: MatheMatrix/zstack
Length of output: 2812
🏁 Script executed:
#!/bin/bash
# Search for invocations of the afterVolumePersist extension point
rg "afterVolumePersist\)" --type java -B 5 -A 2 | head -60Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
#!/bin/bash
# Look for where VmMetadataResourcePersistExtensionPoint is used
rg "VmMetadataResourcePersistExtensionPoint" --type java -lRepository: MatheMatrix/zstack
Length of output: 261
🏁 Script executed:
#!/bin/bash
# Search for where afterVolumePersist is actually called (not defined)
rg "\.afterVolumePersist\(|\.afterSnapshotPersist\(" --type java -B 3 -A 3Repository: MatheMatrix/zstack
Length of output: 44
🏁 Script executed:
#!/bin/bash
# Check the full LocalStorageVmMetadataExtension.java file to see complete implementation
cat -n plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.javaRepository: MatheMatrix/zstack
Length of output: 7840
完善幂等性检查以避免主键约束冲突。
createResourceRef 方法直接调用 dbf.persist() 创建新记录,若注册流程重试或并发调用导致相同资源的引用重复插入,会触发主键约束异常。LocalStorageResourceRefVO 的复合主键由三个字段组成:resourceUuid、primaryStorageUuid 和 hostUuid,因此需在持久化前验证完整的主键组合是否已存在。
建议参考 LocalStorageBase.java 中的现有模式,在持久化前完整检查这三个字段,而非仅检查其中部分。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageVmMetadataExtension.java`
around lines 134 - 145, The createResourceRef method currently calls
dbf.persist(ref) unconditionally and can violate the composite primary key
(resourceUuid, primaryStorageUuid, hostUuid) when retries/concurrent calls
occur; update createResourceRef (and follow the pattern used in
LocalStorageBase.java) to first query the LocalStorageResourceRefVO by the full
key combination (resourceUuid + primaryStorageUuid + hostUuid) and only persist
if no existing record is found (or update/return the existing record), ensuring
the existence check uses the same three fields that form the VO's composite key
to prevent duplicate-insert primary key errors.
| @Override | ||
| public String validateMetadataPath(String primaryStorageUuid, String path) { | ||
| // Expected format: <metadataDir>/<uuid>.vmmeta | ||
| // e.g. /mnt/pss/vm-metadata/a1b2c3d4e5f6...vmmeta | ||
| String metadataDir = buildMetadataDir(primaryStorageUuid); | ||
| String prefix = metadataDir + "/"; | ||
| String suffix = VmInstanceMetadataConstants.FILE_METADATA_SUFFIX; | ||
|
|
||
| if (!path.startsWith(prefix) || !path.endsWith(suffix)) { | ||
| return String.format("metadataPath[%s] does not match expected format: %s/<uuid>%s", | ||
| path, metadataDir, suffix); | ||
| } | ||
|
|
||
| String uuidPart = path.substring(prefix.length(), path.length() - suffix.length()); | ||
| if (!uuidPart.matches("[0-9a-f]{32}")) { | ||
| return String.format("metadataPath[%s] contains invalid uuid[%s], expected 32-char hex", path, uuidPart); | ||
| } | ||
| return null; | ||
| } |
There was a problem hiding this comment.
validateMetadataPath 不应传播 CloudRuntimeException。
validateMetadataPath 方法用于参数校验,预期行为是返回错误字符串或 null。但第 56 行调用的 buildMetadataDir(primaryStorageUuid) 在主存储不存在时会抛出 CloudRuntimeException,导致本应返回校验错误的场景升级为 500 异常。
建议捕获异常并转换为校验错误字符串:
建议修改
`@Override`
public String validateMetadataPath(String primaryStorageUuid, String path) {
+ if (path == null) {
+ return "metadataPath cannot be null";
+ }
+
// Expected format: <metadataDir>/<uuid>.vmmeta
// e.g. /mnt/pss/vm-metadata/a1b2c3d4e5f6...vmmeta
- String metadataDir = buildMetadataDir(primaryStorageUuid);
+ final String metadataDir;
+ try {
+ metadataDir = buildMetadataDir(primaryStorageUuid);
+ } catch (CloudRuntimeException e) {
+ return String.format("cannot resolve metadata dir for primary storage[uuid:%s]: %s",
+ primaryStorageUuid, e.getMessage());
+ }
String prefix = metadataDir + "/";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@plugin/nfsPrimaryStorage/src/main/java/org/zstack/storage/primary/nfs/NfsVmMetadataExtension.java`
around lines 52 - 70, The validateMetadataPath method should not let
CloudRuntimeException from buildMetadataDir(primaryStorageUuid) propagate; wrap
the call to buildMetadataDir(primaryStorageUuid) in a try/catch for
CloudRuntimeException (or RuntimeException if necessary) inside
validateMetadataPath and return a validation error string (e.g.
"metadataPath[...] failed to build metadata dir: <exception message>" or similar
consistent message) instead of throwing; keep existing checks for prefix/suffix
and uuidPart unchanged and use the same return-null-on-success behavior.
APIImpact Resolves: ZSV-11559 Change-Id: I6b6a6378627264646d6a76726762736e77787373
f0d16ea to
3ed3e17
Compare
APIImpact
Resolves: ZSV-11559
Change-Id: I6b6a6378627264646d6a76726762736e77787373
sync from gitlab !9472