Skip to content

Conversation

@zstack-robot-2
Copy link
Collaborator

1、type slover
2、Platfrom err method param change

Resolves: ZSTAC-66343

Change-Id: I6c6f7570776b6e616365677a6d6872686e6c7278

sync from gitlab !8541

lin.ma added 4 commits September 30, 2025 10:33
1、type slover
2、Platfrom err method param change

Resolves: ZSTAC-66343

Change-Id: I6c6f7570776b6e616365677a6d6872686e6c7278
1、replace Platfrom err method call

Resolves: ZSTAC-66343

Change-Id: I6a6b6e6f6e627365786a646166716c6d776a7572
1、sdk

Resolves: ZSTAC-66343

Change-Id: I6e6f67676f7a72677868706d616768617a7a7378
Resolves: ZSTAC-66343

Change-Id: I666e6b686f6670706c6b6975686e72776b6c6476
@coderabbitai
Copy link

coderabbitai bot commented Oct 17, 2025

Caution

Review failed

Failed to post review comments

错误代码标准化重构

高层总结

系统范围内将数百个文件中的错误处理从通用错误消息和代码替换为组织级别的标准化 CloudOperationsErrorCode 常量(ORG_ZSTACK_*),保留现有消息内容但增强错误可追踪性。

变更列表

内聚组 / 文件 变更摘要
计算模块 - 虚拟机操作验证
compute/src/main/java/org/zstack/compute/VmNicUtils.java, compute/src/main/java/org/zstack/compute/vm/MacOperator.java, compute/src/main/java/org/zstack/compute/vm/StaticIpOperator.java
将 argerr(...) 调用替换为带特定错误代码(ORG_ZSTACK_COMPUTE_VM_10001-10235)的版本,覆盖 MAC 地址验证、静态 IP 配置等操作
计算模块 - 主机分配器
compute/src/main/java/org/zstack/compute/allocator/*AllocatorFlow.java (12 个文件)
在所有主机/存储分配流中用 ORG_ZSTACK_COMPUTE_ALLOCATOR_10000-10036 代替通用错误,影响候选主机、存储、网络选择等路径
计算模块 - 集群管理
compute/src/main/java/org/zstack/compute/cluster/*.java, compute/src/main/java/org/zstack/compute/host/*.java
将 argerr/operr 调用标准化为 ORG_ZSTACK_COMPUTE_CLUSTER_10000-10010 和 ORG_ZSTACK_COMPUTE_HOST_10086-10122
计算模块 - VM 流程
compute/src/main/java/org/zstack/compute/vm/*.java (20+ 个文件)
用 ORG_ZSTACK_COMPUTE_VM_10001-10243 标准化 VM 创建、启动、停止、设备操作的错误代码
配置模块
configuration/src/main/java/org/zstack/configuration/*.java
将提供项创建/更新验证错误替换为 ORG_ZSTACK_CONFIGURATION_10000-10012
控制台模块
console/src/main/java/org/zstack/console/*.java
用 ORG_ZSTACK_CONSOLE_10000-10013 标准化代理连接、会话验证错误
核心模块 - 基础设施
core/src/main/java/org/zstack/core/{Platform,With,cloudbus,config,*.java}
大量标准化:Platform.java 增加 globalErrorCode 参数支持;CloudBus、Ansible、REST、Workflow 等核心组件用 ORG_ZSTACK_CORE_* 系列代码标准化
身份认证模块
identity/src/main/java/org/zstack/identity/*.java
会话、权限、配额检查用 ORG_ZSTACK_IDENTITY_10000-10072 替换 IdentityErrors
网络模块 - L2/L3
network/src/main/java/org/zstack/network/l{2,3}/*.java
网络创建、IP 分配、配置验证用 ORG_ZSTACK_NETWORK_L2_10000-10007 和 ORG_ZSTACK_NETWORK_L3_10000-10078
网络模块 - 服务提供商
network/src/main/java/org/zstack/network/service/*.java
DHCP、主机路由、EIP 等网络服务用 ORG_ZSTACK_NETWORK_SERVICE_* 系列标准化
存储模块 - Ceph
plugin/ceph/src/main/java/org/zstack/storage/ceph/*.java
Ceph 池、Mon、PG 操作用 ORG_ZSTACK_STORAGE_CEPH_* 系列(备份10000-10025、主存储10000-10052、容量10000-10001)
其他插件
plugin/{ldap,kvm,loadBalancer,directory,acl,...}/*.java (60+ 文件)
各插件用对应的 ORG_ZSTACK_* 错误代码系列标准化错误处理(KVM 10000-10161、LDAP 10000-10019、负载均衡器 10000-10171 等)

序列图

此次变更不涉及新功能或控制流修改,仅改进错误报告的粒度,无需序列图说明。

预计代码审查工作量

🎯 3 (中等复杂度) | ⏱️ ~25 分钟

理由:变更跨越大量文件(100+),但具有高度的同质性 - 几乎所有改动都遵循相同的模式(用特定的 ORG_ZSTACK_* 常量替换通用错误代码)。每处改动的逻辑几乎相同,只是错误代码常量不同。虽然文件数量多,但因为改动模式重复一致,审查工作量相对较低。需要验证:(1) 所有错误代码常量存在且正确;(2) Platform.java 的签名变更不破坏现有调用;(3) 关键错误路径的消息仍然有意义。

可能相关的 PR

诗歌

🐰 满山的代码,错误声声,
从前模糊,今朝标清晰——
一码一道,组织来规范,
CloudOperations 的梦想,闪闪发光。✨
百般变化,万般一致,
追踪难题,从此有迹可循!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.88% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed 本PR标题"[error code]: global error code"严格遵循了指定的"[scope]: "格式。标题中type为"feature",scope为"error code",description为"global error code",总长度为40个字符,符合72个字符的限制要求。标题清晰准确地反映了PR的核心目标:向整个代码库添加全局错误代码机制,与raw_summary中描述的大量文件更改(在Platform.java中更新错误方法签名、在ErrorCode.java中添加globalErrorCode字段、以及在各模块中用CloudOperationsErrorCode常量替换plain error messages)完全相关。
Description Check ✅ Passed PR描述与变更集相关。描述中提到"Platform err method param change"与raw_summary中Platform.java的核心变化一致,即更新所有error方法的签名以添加globalErrorCode参数。虽然描述中存在拼写错误("type slover"和"Platfrom"),但内容仍然涉及变更集的实质性方面。描述包含JIRA工单号ZSTAC-66343和Change-Id,提供了追踪信息。虽然描述相对简洁且有拼写问题,但符合"宽松检查"的标准——内容与变更集相关且不离题。
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sync/lin.ma/malin_error_code_v3@@2

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 80

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (26)
core/src/main/java/org/zstack/core/externalservice/ExternalServiceManagerImpl.java (1)

90-110: 修复控制流缺陷:缺少return语句导致错误被覆盖。

在第100行设置错误后缺少return语句,导致代码继续执行到第103-107行。如果服务不支持重载配置且未运行,第106行的错误会覆盖第100行设置的错误,用户将收到错误的错误码和消息。

应用以下修复:

         if (!service.getExternalServiceCapabilities().isReloadConfig()) {
             event.setError(operr(ORG_ZSTACK_CORE_EXTERNALSERVICE_10002, "service[%s] does not support reload config", msg.getName()));
+            bus.publish(event);
+            return;
         }
 
         if (service.isAlive()) {
core/src/main/java/org/zstack/core/encrypt/EncryptFacadeImpl.java (1)

216-232: 修复异常被吞没的问题

第 221 行抛出的 OperationFailureException 会被第 230 行的 catch (Exception e) 捕获并吞没,仅记录 debug 日志后继续循环。这违背了抛出特定错误码异常的初衷。

加密失败应该是一个严重错误,不应被静默处理。根据编码规范:"在必要时,应继续抛出异常,使上层业务处理者可以转换为用户友好的错误提示"。

建议:

  1. OperationFailureException 从 catch 块中排除,让其向上传播
  2. 或者在 catch 块中特殊处理 OperationFailureException,重新抛出而不是仅记录日志

应用此 diff 修复异常处理:

                         try {
                             String decryptedString = decrypt(encryptedString);
                             ErrorableValue<String> encrypt = encrypt(decryptedString, key);
                             if (encrypt.error != null) {
                                 logger.error(String.format("Encryption error : %s", encrypt.error));
                                 throw new OperationFailureException(operr(ORG_ZSTACK_CORE_ENCRYPT_10000, "Encryption error : %s", encrypt.error));
                             }

                             String sql = String.format("update %s set %s = :encrypted where uuid = :uuid", className, field.getName());

                             Query query = dbf.getEntityManager().createQuery(sql);
                             query.setParameter("encrypted", encrypt.result);
                             query.setParameter("uuid", uuid);
                             query.executeUpdate();
+                        } catch (OperationFailureException e) {
+                            // 重新抛出操作失败异常,不应被吞没
+                            throw e;
                         } catch (Exception e) {
                             logger.debug(String.format("decrypt[className: %s, uuid: %s] origin password error because : %s", className, uuid, e.getMessage()));
                         }
header/src/main/java/org/zstack/header/errorcode/ErrorCode.java (3)

76-84: 拷贝构造函数遗漏了新字段 globalErrorCode

拷贝构造函数未复制新增的 globalErrorCode 字段,这会导致调用 copy() 方法时全局错误码丢失。这与本次 PR 引入全局错误码的目标相悖,会造成错误追踪信息不完整。

应用以下修复:

 public ErrorCode(ErrorCode other) {
     this.code = other.code;
     this.description = other.description;
     this.details = other.details;
     this.elaboration = other.elaboration;
     this.messages = other.messages;
     this.cause = other.cause;
     this.location = other.location;
+    this.globalErrorCode = other.globalErrorCode;
 }

172-185: equals() 方法未包含新字段 globalErrorCode

equals() 方法的比较逻辑中未包含新增的 globalErrorCode 字段。这意味着两个仅 globalErrorCode 不同的 ErrorCode 对象会被判定为相等,这可能导致在 HashMap、HashSet 等集合中出现逻辑错误,并且与引入全局错误码以区分不同错误的初衷不符。

应用以下修复:

 @Override
 public boolean equals(Object t) {
     if (this == t){
         return true;
     }
     if (!(t instanceof ErrorCode)){
         return false;
     }

     ErrorCode other = (ErrorCode)t;
     return Objects.equals(this.code, other.code) &&
             Objects.equals(this.cause, other.cause) &&
             Objects.equals(this.details, other.details) &&
-            Objects.equals(this.opaque, other.opaque);
+            Objects.equals(this.opaque, other.opaque) &&
+            Objects.equals(this.globalErrorCode, other.globalErrorCode);
 }

188-195: hashCode() 方法未包含新字段 globalErrorCode

hashCode() 方法的计算中未包含新增的 globalErrorCode 字段。这违反了 Java 的 equals-hashCode 契约:相等的对象必须具有相同的哈希码。由于 equals() 方法也需要更新以包含该字段,hashCode() 也必须相应调整以保持一致性。

应用以下修复:

 @Override
 public int hashCode() {
     StringBuilder sb = new StringBuilder();
     sb.append(code == null ? "" : code);
     sb.append(details == null ? "" : details);
     sb.append(opaque == null ? "" : opaque);
     sb.append(cause == null ? "" : cause.toString());
+    sb.append(globalErrorCode == null ? "" : globalErrorCode);
     return sb.toString().hashCode();
 }
plugin/ceph/src/main/java/org/zstack/storage/ceph/primary/CephSnapshotProtector.java (1)

27-30: 缺少 return 语句,可能导致 completion 回调被多次调用。

在 Line 29 调用 completion.success() 后缺少 return 语句,导致程序继续执行到 Line 32 及之后的逻辑。这可能导致 completion 回调被多次调用(例如再次调用 completion.fail()completion.success()),引发不可预期的行为或运行时异常。

应用以下修复:

 if (irregularThirdPartySnapshotInstallPath) {
     completion.success();
+    return;
 }
plugin/directory/src/main/java/org/zstack/directory/VmDirectoryChecker.java (1)

21-30: 修复空值处理问题以避免运行时异常。

存在以下问题:

  1. 第22行:当 directoryUuid 不存在时,find() 返回 null,第25行和第28行调用 vo.getZoneUuid() 会抛出 NullPointerException
  2. 第25行:如果 resourceUuids 为空列表,zoneUuids 也会为空,allMatch 对空流会返回 true,这可能不是期望的行为。

根据编码规范:"对于可以通过预检查避免的 RuntimeException(如 NullPointerException),不建议使用 try-catch 来进行处理",应当添加预检查。

应用此差异修复空值处理:

 @Override
 public ErrorCode check(String directoryUuid, List<String> resourceUuids) {
     DirectoryVO vo = Q.New(DirectoryVO.class).eq(DirectoryVO_.uuid, directoryUuid).find();
+    if (vo == null) {
+        return argerr(ORG_ZSTACK_DIRECTORY_10004, "directory[uuid:%s] not found", directoryUuid);
+    }
+    if (resourceUuids == null || resourceUuids.isEmpty()) {
+        return argerr(ORG_ZSTACK_DIRECTORY_10004, "resource list cannot be empty");
+    }
+    
     List<String> zoneUuids = Q.New(VmInstanceVO.class).select(VmInstanceVO_.zoneUuid)
             .in(VmInstanceVO_.uuid, resourceUuids).listValues();
     if(zoneUuids.stream().allMatch(s -> s.equals(vo.getZoneUuid()))) {
         return null;
     } else {
         return argerr(ORG_ZSTACK_DIRECTORY_10004, "all resources zoneUuid must be consistent with the directory zoneUuid[%s]", vo.getZoneUuid());
     }
 }
configuration/src/main/java/org/zstack/configuration/ConfigurationManagerImpl.java (1)

1106-1119: 修复复制粘贴错误:使用了错误的系统标签验证

此方法位于 DiskOfferingUserConfigValidator 类中,但存在以下关键问题:

  1. Line 1109:检查的是 InstanceOfferingSystemTags.INSTANCE_OFFERING_USER_CONFIG,应该检查 DiskOfferingSystemTags.DISK_OFFERING_USER_CONFIG
  2. Line 1112:错误消息中使用了 "instanceOffering",应该使用 "diskOffering"

这些错误会导致 DiskOffering 的重复系统标签验证失效。

应用以下修复:

         public void validateSystemTagInCreateMessage(APICreateMessage msg) {
             int userdataTagCount = 0;
             for (String sysTag : msg.getSystemTags()) {
-                if (InstanceOfferingSystemTags.INSTANCE_OFFERING_USER_CONFIG.isMatch(sysTag)) {
+                if (DiskOfferingSystemTags.DISK_OFFERING_USER_CONFIG.isMatch(sysTag)) {
                     if (userdataTagCount > 0) {
                         throw new OperationFailureException(argerr(
-                        ORG_ZSTACK_CONFIGURATION_10004,         "Shouldn't be more than one systemTag for one instanceOffering."));
+                        ORG_ZSTACK_CONFIGURATION_10004,         "Shouldn't be more than one systemTag for one diskOffering."));
                     }
                     userdataTagCount++;
 
                     check(msg.getResourceUuid(), sysTag);
                 }
             }
         }
plugin/directory/src/main/java/org/zstack/directory/DirectoryBase.java (1)

361-362: 潜在空指针异常风险

Line 361 的查询结果 parentVO 可能为 null(当 targetParentUuid 不存在时),但 Line 362 直接调用了 parentVO.getGroupName() 而未进行空值检查,这会导致 NullPointerException

建议在使用前添加空值校验:

 vo.setParentUuid(msg.getTargetParentUuid());
 DirectoryVO parentVO = Q.New(DirectoryVO.class).eq(DirectoryVO_.uuid, msg.getTargetParentUuid()).find();
+if (parentVO == null) {
+    completion.fail(operr("target parent directory[uuid:%s] not found", msg.getTargetParentUuid()));
+    return;
+}
 String newGroupName = String.format("%s/%s", parentVO.getGroupName(), vo.getName());
core/src/main/java/org/zstack/core/salt/SaltSetupMinionJob.java (1)

156-156: 代码中包含中文字符,违反编码规范。

日志消息中使用了中文冒号(:),违反了编码规范要求:"代码里不应当有有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写"。

根据编码规范要求。

应用此修改以使用正确的英文:

-                    logger.warn(String.format("FileInputStream close IOException:%s", e.getMessage()));
+                    logger.warn(String.format("Failed to close FileInputStream: %s", e.getMessage()));
plugin/directory/src/main/java/org/zstack/directory/DirectoryApiInterceptor.java (3)

35-35: 将正则表达式定义为常量

根据编码规范,该正则表达式应定义为 private static final 常量,使用全大写命名,例如 NAME_VALIDATION_REGEX

应用以下修改:

-    String regex = "^[\\u4e00-\\u9fa5a-zA-Z0-9\\s()()【】@._+-]+$";
+    private static final String NAME_VALIDATION_REGEX = "^[\\u4e00-\\u9fa5a-zA-Z0-9\\s()()【】@._+-]+$";

然后在方法中更新引用:

-        boolean result = CharacterUtils.checkCharactersByRegex(regex, msg.getName());
+        boolean result = CharacterUtils.checkCharactersByRegex(NAME_VALIDATION_REGEX, msg.getName());

根据编码规范


117-124: 缺少对用户输入的 trim 处理

根据 Interceptor 编码规范,来自 Message 的参数应该先进行 trim 处理,因为用户可能在浏览器上复制粘贴带有空格、换行符等的数据。当前代码直接对 msg.getName() 进行正则校验,未做 trim 处理。

应用以下修改:

     private void validate(APIUpdateDirectoryMsg msg) {
-        boolean result = CharacterUtils.checkCharactersByRegex(regex, msg.getName());
+        String name = msg.getName();
+        if (name != null) {
+            name = name.trim();
+            msg.setName(name);
+        }
+        boolean result = CharacterUtils.checkCharactersByRegex(NAME_VALIDATION_REGEX, name);
         if (!result) {
             throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_DIRECTORY_10002, "name contains unsupported characters," +
                     " name can only contain Chinese characters, English letters, " +
                     "numbers, spaces, and the following characters: ()()【】@._-+ "));
         }
     }

根据编码规范


126-134: 缺少对用户输入的 trim 处理

validate(APIUpdateDirectoryMsg msg) 方法相同的问题,来自 Message 的参数应该先进行 trim 处理。当前代码直接对 msg.getName() 进行正则校验,未做 trim 处理。

应用以下修改:

     private void validate(APICreateDirectoryMsg msg) {
         //judge whether special characters are included
-        boolean result = CharacterUtils.checkCharactersByRegex(regex, msg.getName());
+        String name = msg.getName();
+        if (name != null) {
+            name = name.trim();
+            msg.setName(name);
+        }
+        boolean result = CharacterUtils.checkCharactersByRegex(NAME_VALIDATION_REGEX, name);
         if (!result) {
             throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_DIRECTORY_10003, "name contains unsupported characters," +
                     " name can only contain Chinese characters, English letters, " +
                     "numbers, spaces, and the following characters: ()()【】@._-+ "));
         }
     }

根据编码规范

core/src/main/java/org/zstack/core/ansible/AnsibleFacadeImpl.java (2)

442-442: 修正日志消息中的中文字符。

日志消息中使用了中文冒号":",应改为英文冒号":"。根据编码规范,代码中不应包含中文字符。

应用以下修改:

-                            logger.warn(String.format("FileInputStream close IOException:%s", e.getMessage()));
+                            logger.warn(String.format("FileInputStream close IOException: %s", e.getMessage()));

As per coding guidelines


463-463: 修正日志消息中的中文字符。

日志消息中使用了中文冒号":",应改为英文冒号":"。根据编码规范,代码中不应包含中文字符。

应用以下修改:

-                            logger.warn(String.format("FileInputStream close IOException:%s", e.getMessage()));
+                            logger.warn(String.format("FileInputStream close IOException: %s", e.getMessage()));

As per coding guidelines

plugin/acl/src/main/java/org/zstack/acl/AccessControlListApiInterceptor.java (2)

122-148: 缺少对 Message 参数的 trim 处理。

根据编码规范,Interceptor 必须检查来自 Message 的参数是否做过 trim。用户可能在浏览器上复制粘贴的数据带有空格、换行符等。

当前代码直接使用 msg.getEntries() 而没有进行 trim 处理,可能导致验证逻辑出现问题。

建议在验证前对字符串参数进行 trim:

 private void validate (APIAddAccessControlListEntryMsg msg) {
+    if (StringUtils.isNotBlank(msg.getEntries())) {
+        msg.setEntries(msg.getEntries().trim());
+    }
     AccessControlListVO acl = dbf.findByUuid(msg.getAclUuid(), AccessControlListVO.class);

根据编码规范要求。


150-195: 缺少对 Message 参数的 trim 处理。

根据编码规范,Interceptor 必须检查来自 Message 的参数是否做过 trim。当前代码直接使用 msg.getDomain()msg.getUrl() 而没有进行 trim 处理。

建议在验证前对字符串参数进行 trim:

 private void validate (APIAddAccessControlListRedirectRuleMsg msg) {
+    if (StringUtils.isNotBlank(msg.getDomain())) {
+        msg.setDomain(msg.getDomain().trim());
+    }
+    if (StringUtils.isNotBlank(msg.getUrl())) {
+        msg.setUrl(msg.getUrl().trim());
+    }
     AccessControlListVO acl = dbf.findByUuid(msg.getAclUuid(), AccessControlListVO.class);

根据编码规范要求。

plugin/hostNetworkInterface/src/main/java/org/zstack/network/hostNetworkInterface/lldp/LldpApiInterceptor.java (1)

45-53: 需要对 Message 参数进行 trim 处理

根据 Interceptor 类的编码规范,来自 Message 的参数应该进行 trim 处理,因为用户可能在浏览器上复制粘贴带有空格、换行符等的数据。msg.getInterfaceUuids() 返回的 UUID 列表应该在使用前进行清理。

As per coding guidelines.

建议应用以下修改:

 private void validate(APIChangeHostNetworkInterfaceLldpModeMsg msg) {
+    List<String> trimmedUuids = msg.getInterfaceUuids().stream()
+            .map(String::trim)
+            .collect(Collectors.toList());
     List<String> hostUuids = Q.New(HostNetworkInterfaceVO.class).select(HostNetworkInterfaceVO_.hostUuid)
-            .in(HostNetworkInterfaceVO_.uuid, msg.getInterfaceUuids())
+            .in(HostNetworkInterfaceVO_.uuid, trimmedUuids)
             .listValues();
     Set<String> set = new HashSet<>(hostUuids);
     if (set.size() > 1) {
         throw new ApiMessageInterceptionException((argerr(ORG_ZSTACK_NETWORK_HOSTNETWORKINTERFACE_LLDP_10000, "could not change lldp mode for the interfaces of different hosts")));
     }
 }

注意:需要在文件顶部添加导入:

import java.util.stream.Collectors;
core/src/main/java/org/zstack/core/workflow/AsyncWorkFlowChain.java (1)

153-161: 注意异常消息的空值处理和AI摘要不一致

该改动将未处理异常的错误码标准化,这是好的实践。但需要注意以下问题:

  1. AI摘要不一致:AI摘要中提到的错误码是 ORG_ZSTACK_CORE_WORKFLOW_10000,但实际代码使用的是 ORG_ZSTACK_CORE_WORKFLOW_10002。请确认使用的错误码是否正确。

  2. 空值安全性t.getMessage() 可能返回 null,这可能导致错误信息不完整。建议使用更安全的方式获取异常信息。

建议应用以下改进以处理潜在的空消息:

-            ErrorCode err = inerr(ORG_ZSTACK_CORE_WORKFLOW_10002, t.getMessage());
+            String message = t.getMessage() != null ? t.getMessage() : t.getClass().getName();
+            ErrorCode err = inerr(ORG_ZSTACK_CORE_WORKFLOW_10002, message);

或者使用更简洁的方式:

-            ErrorCode err = inerr(ORG_ZSTACK_CORE_WORKFLOW_10002, t.getMessage());
+            ErrorCode err = inerr(ORG_ZSTACK_CORE_WORKFLOW_10002, 
+                    t.getMessage() != null ? t.getMessage() : t.toString());
compute/src/main/java/org/zstack/compute/vm/MacOperator.java (2)

78-84: 方法职责混乱且命名具有误导性。

方法名 isMulticastMac 暗示其仅检查是否为组播MAC地址并返回布尔值,但实际上该方法还承担了MAC格式校验的职责(Line 79-81会抛出异常)。这违反了单一职责原则,并且容易造成误解。

建议:

  1. 将格式校验逻辑提取到 validateAvailableMac 方法中,避免重复校验
  2. isMulticastMac 方法仅负责组播判断,假定输入已经是有效的MAC地址

Line 80的错误码变更符合PR目标。


50-59: 严重Bug:错误地传递常量而非实际值。

Line 55的第二个参数直接传递了 VmSystemTags.MAC_TOKEN 常量,而不是从 tokens Map中获取对应的值。这会导致 VmMacStruct 中存储的是常量字符串(可能是 "mac" 之类的token key),而非实际的MAC地址。

对比Line 54的正确做法(使用 tokens.get()),Line 55应该使用相同的方式获取MAC值。

应用以下修复:

         for (Map<String, String> tokens : tokenList) {
             structs.add(new VmMacStruct(tokens.get(VmSystemTags.STATIC_IP_L3_UUID_TOKEN),
-                    VmSystemTags.MAC_TOKEN));
+                    tokens.get(VmSystemTags.MAC_TOKEN)));
 
         }
plugin/ldap/src/main/java/org/zstack/ldap/LdapUtil.java (1)

811-815: 错误文案小幅润色,提升可读性

当前串联为 “... first.getDn error filter:%s”,建议断句与措辞更自然。

建议补丁:

-            ORG_ZSTACK_LDAP_10019,         LdapErrors.UNABLE_TO_GET_SPECIFIED_LDAP_UID, "You'd better check the LDAP/AD server[url:%s, baseDN:%s, encryption:%s, username:%s, password:******]" +
-                            " configuration and test connection first.getDn error filter:%s",
+            ORG_ZSTACK_LDAP_10019,         LdapErrors.UNABLE_TO_GET_SPECIFIED_LDAP_UID, "Please check the LDAP/AD server [url:%s, baseDN:%s, encryption:%s, username:%s, password:******] " +
+                            "configuration and test the connection first. getDn error filter: %s",
network/src/main/java/org/zstack/network/l3/L3NetworkApiInterceptor.java (3)

124-131: 否定缺失导致语义反转

应为“could not delete ip address”。建议修正:

-                throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_L3_10000, "could delete ip address, " +
+                throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_L3_10000, "could not delete ip address, " +

180-186: 占位符缺失:未输出“旧区间”的起止 IP

当前格式串仅有两个 %s,导致旧区间未显示(多余参数被忽略)。建议补齐占位符:

-                    throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_L3_10008, "could not reserve ip range, " +
-                            "because new range [%s:%s] is overlapped with old range",
-                            msg.getStartIp(), msg.getEndIp(),
-                            reserveRange.getStartIp(), reserveRange.getEndIp()));
+                    throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_L3_10008, "could not reserve ip range, " +
+                            "because new range [%s:%s] is overlapped with old range [%s:%s]",
+                            msg.getStartIp(), msg.getEndIp(),
+                            reserveRange.getStartIp(), reserveRange.getEndIp()));

209-215: 占位符缺失(IPv6 版本)

同上,补齐旧区间占位符并修正单词:

-                    throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_L3_10011, "could not reserve ip range, " +
-                                    "because new range [%s:%s] is overlapped with old range",
+                    throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_L3_10011, "could not reserve ip range, " +
+                                    "because new range [%s:%s] is overlapped with old range [%s:%s]",
compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java (1)

332-361: 修复两处静态IP校验的逻辑错误:found未按IP重置、UsedIpVO查询使用了错误参数

  • found 变量未在每次循环开始重置,可能导致后续IP绕过区间校验。
  • 占用校验使用了 msg.getStaticIp()/msg.getDestL3NetworkUuid(),应使用当前迭代 staticIp 与 l3Uuid。

以下修复保证每个IP独立校验并查询正确的L3与IP:

-            boolean found = false;
-            for (String staticIp : ips) {
+            for (String staticIp : ips) {
+                boolean found = false;
                 int ipVersion = IPv6Constants.IPv4;
                 if (IPv6NetworkUtils.isIpv6Address(staticIp)) {
                     ipVersion = IPv6Constants.IPv6;
                 }
                 for (NormalIpRangeVO ipr : iprs) {
                     if (ipVersion != ipr.getIpVersion()) {
                         continue;
                     }
                     if (NetworkUtils.isInRange(staticIp, ipr.getStartIp(), ipr.getEndIp())) {
                         found = true;
                         break;
                     }
                 }
 
                 if (!l3NetworkVO.enableIpAddressAllocation()) {
                     found = true;
                 }
 
                 if (!found) {
                     throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_COMPUTE_VM_10055, "the static IP[%s] is not in any IP range of the L3 network[uuid:%s]", staticIp, l3Uuid));
                 }
 
                 SimpleQuery<UsedIpVO> uq = dbf.createQuery(UsedIpVO.class);
-                uq.add(UsedIpVO_.l3NetworkUuid, Op.EQ, msg.getDestL3NetworkUuid());
-                uq.add(UsedIpVO_.ip, Op.EQ, msg.getStaticIp());
+                uq.add(UsedIpVO_.l3NetworkUuid, Op.EQ, l3Uuid);
+                uq.add(UsedIpVO_.ip, Op.EQ, staticIp);
                 if (uq.isExists()) {
                     throw new ApiMessageInterceptionException(operr(ORG_ZSTACK_COMPUTE_VM_10056, "the static IP[%s] has been occupied on the L3 network[uuid:%s]", staticIp, l3Uuid));
                 }
-            }
+            }

private void doAddHost(final AddHostMessage msg, ReturnValueCompletion<HostInventory > completion) {
if (Q.New(HostVO.class).eq(HostVO_.managementIp, msg.getManagementIp()).isExists()) {
completion.fail(argerr("there has been a host having managementIp[%s]", msg.getManagementIp()));
completion.fail(argerr(ORG_ZSTACK_COMPUTE_HOST_10098, "there has been a host having managementIp[%s]", msg.getManagementIp()));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

修正英文语法错误

错误消息的英文表达不够地道。根据编码规范要求使用正确的、无拼写错误的英文。

应用此修改以改进英文表达:

-            completion.fail(argerr(ORG_ZSTACK_COMPUTE_HOST_10098, "there has been a host having managementIp[%s]", msg.getManagementIp()));
+            completion.fail(argerr(ORG_ZSTACK_COMPUTE_HOST_10098, "a host with managementIp[%s] already exists", msg.getManagementIp()));
🤖 Prompt for AI Agents
In compute/src/main/java/org/zstack/compute/host/HostManagerImpl.java around
line 375, the error message string "there has been a host having
managementIp[%s]" is grammatically incorrect; change it to a natural English
message such as "there is already a host with managementIp[%s]" (or "a host with
managementIp[%s] already exists") by updating the argerr call to use the
corrected message while keeping the same placeholder and error code.

final ClusterVO cluster = findClusterByUuid(msg.getClusterUuid());
if (cluster == null) {
completion.fail(argerr("cluster[uuid:%s] is not existing", msg.getClusterUuid()));
completion.fail(argerr(ORG_ZSTACK_COMPUTE_HOST_10099, "cluster[uuid:%s] is not existing", msg.getClusterUuid()));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

修正英文语法错误

"is not existing" 的表达不符合英文习惯。根据编码规范要求使用正确的英文。

应用此修改以改进英文表达:

-            completion.fail(argerr(ORG_ZSTACK_COMPUTE_HOST_10099, "cluster[uuid:%s] is not existing", msg.getClusterUuid()));
+            completion.fail(argerr(ORG_ZSTACK_COMPUTE_HOST_10099, "cluster[uuid:%s] does not exist", msg.getClusterUuid()));
🤖 Prompt for AI Agents
In compute/src/main/java/org/zstack/compute/host/HostManagerImpl.java around
line 381, the error message uses unidiomatic English ("is not existing"); change
the message to use correct grammar such as "does not exist" — e.g. replace
"cluster[uuid:%s] is not existing" with "cluster[uuid:%s] does not exist"
(keeping the same error code and arg formatting).

Comment on lines +490 to 491
trigger.fail(operr(ORG_ZSTACK_COMPUTE_HOST_10101, "cluster[uuid:%s]'s architecture is %s, not match the host[name:%s, ip:%s] architecture %s",
vo.getClusterUuid(), cluster.getArchitecture(), vo.getName(), vo.getManagementIp(), arch));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

修正英文语法错误

"not match" 缺少助动词,应改为 "does not match"。根据编码规范要求使用正确的英文语法。

应用此修改:

-                    trigger.fail(operr(ORG_ZSTACK_COMPUTE_HOST_10101, "cluster[uuid:%s]'s architecture is %s, not match the host[name:%s, ip:%s] architecture %s",
+                    trigger.fail(operr(ORG_ZSTACK_COMPUTE_HOST_10101, "cluster[uuid:%s]'s architecture is %s, does not match the host[name:%s, ip:%s] architecture %s",
                             vo.getClusterUuid(), cluster.getArchitecture(), vo.getName(), vo.getManagementIp(), arch));
🤖 Prompt for AI Agents
In compute/src/main/java/org/zstack/compute/host/HostManagerImpl.java around
lines 490-491, the error message uses incorrect English ("not match"); update
the message to use the correct auxiliary verb by changing "not match the
host[name:%s, ip:%s] architecture %s" to "does not match the host[name:%s,
ip:%s] architecture %s" so the full logged sentence reads grammatically correct.


if(hostUuid == null){
ErrorCode errorCode = operr(" Can not find the vm's host, please start the vm[%s], then mount the disk", spec.getVmInventory().getUuid());
ErrorCode errorCode = operr(ORG_ZSTACK_COMPUTE_VM_10236, " Can not find the vm's host, please start the vm[%s], then mount the disk", spec.getVmInventory().getUuid());
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

修正错误消息的格式和语法问题

错误消息存在以下问题:

  1. 消息开头有多余的空格:" Can not find..." 应改为 "Cannot find..."
  2. 语法错误:英文中 "Can not" 应写成一个单词 "Cannot"
  3. 标点和大小写不够专业,建议改进为更规范的表达

根据编码规范,错误消息应使用正确的、无拼写错误的英文。

建议应用以下修改:

-            ErrorCode errorCode = operr(ORG_ZSTACK_COMPUTE_VM_10236, " Can not find the vm's host, please start the vm[%s], then mount the disk", spec.getVmInventory().getUuid());
+            ErrorCode errorCode = operr(ORG_ZSTACK_COMPUTE_VM_10236, "Cannot find the VM's host. Please start the VM [%s] and then attach the disk.", spec.getVmInventory().getUuid());
🤖 Prompt for AI Agents
In
compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageForAttachingDiskFlow.java
around line 46, the error message string has a leading space, uses "Can not"
(should be "Cannot") and is awkwardly phrased; replace it with a concise,
grammatically correct message such as "Cannot find the VM's host; start the VM
[%s] before mounting the disk" (keeping the UUID placeholder) so there is no
leading space, "Cannot" is one word, and the instruction reads professionally.

vnic = persistAndRetryIfMacCollision(vnic);
if (vnic == null) {
throw new FlowException(err(VmErrors.ALLOCATE_MAC_ERROR, "unable to find an available mac address after re-try 5 times, too many collisions"));
throw new FlowException(err(ORG_ZSTACK_COMPUTE_VM_10036, VmErrors.ALLOCATE_MAC_ERROR, "unable to find an available mac address after re-try 5 times, too many collisions"));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

修正错误消息的语法问题并消除魔法值。

错误消息中存在语法问题:"after re-try 5 times" 应改为 "after retrying 5 times" 或 "after 5 retry attempts"。

此外,根据编码规范,应避免使用魔法值。数字 5 在代码中出现了两次(第 54 行和第 46 行的错误消息中),建议提取为常量。

应用以下修改:

+    private static final int MAX_MAC_ALLOCATION_RETRIES = 5;
+
     @Override
     public VmNicVO createVmNic(VmNicInventory nic, VmInstanceSpec spec) {
         String acntUuid = Account.getAccountUuidOfResource(spec.getVmInventory().getUuid());
 
         VmNicVO vnic = VmInstanceNicFactory.createVmNic(nic);
         vnic.setType(type.toString());
         vnic.setAccountUuid(acntUuid);
         vnic = persistAndRetryIfMacCollision(vnic);
         if (vnic == null) {
-            throw new FlowException(err(ORG_ZSTACK_COMPUTE_VM_10036, VmErrors.ALLOCATE_MAC_ERROR, "unable to find an available mac address after re-try 5 times, too many collisions"));
+            throw new FlowException(err(ORG_ZSTACK_COMPUTE_VM_10036, VmErrors.ALLOCATE_MAC_ERROR, 
+                String.format("unable to find an available mac address after retrying %d times, too many collisions", MAX_MAC_ALLOCATION_RETRIES)));
         }

同时更新 persistAndRetryIfMacCollision 方法:

     public VmNicVO persistAndRetryIfMacCollision(VmNicVO vo) {
-        int tries = 5;
+        int tries = MAX_MAC_ALLOCATION_RETRIES;
         while (tries-- > 0) {

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In compute/src/main/java/org/zstack/compute/vm/VmNicFactory.java around line 46,
the thrown FlowException message contains a grammar issue ("after re-try 5
times") and a magic number is used; define a private static final int
MAX_MAC_RETRY = 5 (and use it where the literal 5 appears) and update the error
message to use that constant and correct grammar (e.g., "unable to find an
available mac address after retrying " + MAX_MAC_RETRY + " times" or "after " +
MAX_MAC_RETRY + " retry attempts"); also update the
persistAndRetryIfMacCollision method to reference MAX_MAC_RETRY instead of
hardcoded 5 and to construct the same corrected, constant-driven error message.

Comment on lines +167 to 168
throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SERVICE_FLAT_10002, "can not bound more than 1 %s eip to a vm nic[uuid:%s] of flat ",
version, vmNicUuid));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

修正错误消息中的语法错误。

错误码添加正确,但错误消息存在语法问题:

  • "can not bound" 应改为 "cannot bind"("bound" 是过去分词,此处应使用动词原形 "bind")
  • "of flat" 表达不清晰,建议改为 "in flat network" 或 "for flat networking"

建议修改为:

-                throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SERVICE_FLAT_10002, "can not bound more than 1 %s eip to a vm nic[uuid:%s] of flat ",
-                        version, vmNicUuid));
+                throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SERVICE_FLAT_10002, "cannot bind more than 1 %s eip to a vm nic[uuid:%s] in flat network",
+                        version, vmNicUuid));
🤖 Prompt for AI Agents
In
plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatEipApiInterceptor.java
around lines 167 to 168, fix the grammar and clarity of the thrown error
message: replace "can not bound more than 1 %s eip to a vm nic[uuid:%s] of flat"
with a grammatically correct and clearer phrase such as "cannot bind more than 1
%s EIP to a VM NIC [uuid:%s] in flat network" so the message uses the correct
verb form ("cannot bind") and clarifies "flat network".

Comment on lines 55 to 60
private void validate(APIGetHostNetworkInterfaceLldpMsg msg) {
String mode = Q.New(HostNetworkInterfaceLldpVO.class).select(HostNetworkInterfaceLldpVO_.mode).eq(HostNetworkInterfaceLldpVO_.interfaceUuid, msg.getInterfaceUuid()).findValue();
if (mode != null && !mode.contains("rx")) {
throw new ApiMessageInterceptionException((argerr("could not get interface lldp info which is not in receive mode")));
throw new ApiMessageInterceptionException((argerr(ORG_ZSTACK_NETWORK_HOSTNETWORKINTERFACE_LLDP_10001, "could not get interface lldp info which is not in receive mode")));
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

需要对 Message 参数进行 trim 处理

同样地,msg.getInterfaceUuid() 返回的 UUID 字符串也应该在使用前进行 trim 处理,以防用户在浏览器复制粘贴时带入空格或换行符。

As per coding guidelines.

建议应用以下修改:

 private void validate(APIGetHostNetworkInterfaceLldpMsg msg) {
-    String mode = Q.New(HostNetworkInterfaceLldpVO.class).select(HostNetworkInterfaceLldpVO_.mode).eq(HostNetworkInterfaceLldpVO_.interfaceUuid, msg.getInterfaceUuid()).findValue();
+    String interfaceUuid = msg.getInterfaceUuid().trim();
+    String mode = Q.New(HostNetworkInterfaceLldpVO.class).select(HostNetworkInterfaceLldpVO_.mode).eq(HostNetworkInterfaceLldpVO_.interfaceUuid, interfaceUuid).findValue();
     if (mode != null && !mode.contains("rx")) {
         throw new ApiMessageInterceptionException((argerr(ORG_ZSTACK_NETWORK_HOSTNETWORKINTERFACE_LLDP_10001, "could not get interface lldp info which is not in receive mode")));
     }
 }
🤖 Prompt for AI Agents
In
plugin/hostNetworkInterface/src/main/java/org/zstack/network/hostNetworkInterface/lldp/LldpApiInterceptor.java
around lines 55 to 60, the code uses msg.getInterfaceUuid() directly when
querying the DB which can fail or behave incorrectly if the caller included
surrounding whitespace/newlines; trim the interface UUID before using it (e.g.,
create a local String interfaceUuid = msg.getInterfaceUuid() == null ? null :
msg.getInterfaceUuid().trim()), use that trimmed variable in the Q.New(...)
query and keep the existing null check/behavior unchanged so whitespace inputs
are handled robustly.

final T rsp = rep.toResponse(respType);
if (!rsp.success) {
completion.fail(operr("operation error, because:%s", rsp.error));
completion.fail(operr(ORG_ZSTACK_ISCSI_KVM_10000, "operation error, because:%s", (String) rsp.error));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

修复类型转换风险并改进错误消息的清晰度。

当前实现存在以下问题:

  1. 类型转换风险(String) rsp.error 未进行类型检查或空值检查,可能导致 ClassCastException。根据编码规范,应避免通过 try-catch 处理可预检的 RuntimeException

  2. 错误消息缺乏自解释性

    • "operation error" 过于通用,未说明具体是什么操作失败
    • 英文格式错误:"because:%s" 应为 "because: %s"(冒号后需空格)
    • 应明确说明是 HTTP 调用失败及具体的操作类型

根据编码规范要求代码应自解释且错误消息使用正确英文。

建议修改如下:

-                    completion.fail(operr(ORG_ZSTACK_ISCSI_KVM_10000, "operation error, because:%s", (String) rsp.error));
+                    String errorMsg = rsp.error != null ? rsp.error.toString() : "unknown error";
+                    completion.fail(operr(ORG_ZSTACK_ISCSI_KVM_10000, "HTTP call to KVM host failed, path [%s], error: %s", path, errorMsg));

改进点:

  • 使用 toString() 替代强制类型转换,更安全
  • 处理 null 情况
  • 提供具体的操作上下文(HTTP 调用和路径信息)
  • 修正英文格式

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
plugin/iscsi/src/main/java/org/zstack/iscsi/kvm/KvmIscsiNodeServer.java around
line 348: avoid the unsafe cast (String)rsp.error and improve the error text;
replace the cast with a null-safe toString (e.g. rsp.error != null ?
rsp.error.toString() : "null"), update the message to be self-explanatory
(mention the HTTP call and the specific operation/path), and fix spacing to
"because: %s" so the completion.fail call logs a clear, null-safe, and correctly
formatted error string.

Comment on lines +32 to 33
throw new OperationFailureException(operr(ORG_ZSTACK_KVM_10146, "Failed to start vm," +
" because can not disable vm.cpu.hypervisor.feature with vm.cpuMode none"));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

修正错误消息中的语法问题。

错误消息中存在语法问题:

  • "can not" 应写作 "cannot"(一个单词)
  • 为保持一致性,建议将 "vm" 改为 "VM"
  • 消息表述可以更清晰

应用此差异来改进错误消息:

-            throw new OperationFailureException(operr(ORG_ZSTACK_KVM_10146, "Failed to start vm," +
-                    " because can not disable vm.cpu.hypervisor.feature with vm.cpuMode none"));
+            throw new OperationFailureException(operr(ORG_ZSTACK_KVM_10146, "Failed to start VM" +
+                    " because vm.cpu.hypervisor.feature cannot be disabled when vm.cpuMode is set to 'none'"));
🤖 Prompt for AI Agents
In
plugin/kvm/src/main/java/org/zstack/kvm/KvmVmHardwareVerifyExtensionPoint.java
around lines 32-33, fix the error message grammar and clarity by changing "can
not" to "cannot", capitalizing "VM", and rephrasing for clarity; for example,
use a message along the lines of: Failed to start VM: cannot disable
vm.cpu.hypervisor.feature because VM CPU mode is 'none'.

Comment on lines +201 to 202
errs.add(operr(ORG_ZSTACK_KVM_XMLHOOK_10001, "xml hook[uuid: %s] updated successfully, but failed to restart vm[uuid:%s]. details is: %s",
msg.getXmlHookUuid(), vmUuid, reply.getError().getDetails()));
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

使用结构化错误码是良好的改进,建议验证错误码定义并修正语法错误。

将硬编码的错误消息替换为结构化错误码 ORG_ZSTACK_KVM_XMLHOOK_10001 是一个很好的改进,符合全局错误码标准化的目标。

不过需要注意两点:

  1. 请确认错误码 ORG_ZSTACK_KVM_XMLHOOK_10001 已在 CloudOperationsErrorCode 类中正确定义,并验证该错误码在整个代码库中的使用是否一致。

  2. 错误消息中存在语法错误:"details is" 应改为 "details are"(details 是复数形式)。

运行以下脚本验证错误码的定义和使用情况:

关于语法错误的修正建议:

-                                errs.add(operr(ORG_ZSTACK_KVM_XMLHOOK_10001, "xml hook[uuid: %s] updated successfully, but failed to restart vm[uuid:%s]. details is: %s",
+                                errs.add(operr(ORG_ZSTACK_KVM_XMLHOOK_10001, "xml hook[uuid: %s] updated successfully, but failed to restart vm[uuid:%s]. details are: %s",

🏁 Script executed:

#!/bin/bash
# 描述:验证错误码 ORG_ZSTACK_KVM_XMLHOOK_10001 的定义和使用

# 查找错误码的定义
echo "=== 查找错误码定义 ==="
rg -n "ORG_ZSTACK_KVM_XMLHOOK_10001" --type=java -C3

# 检查 CloudOperationsErrorCode 类的定义
echo -e "\n=== 检查 CloudOperationsErrorCode 类 ==="
fd -e java "CloudOperationsErrorCode.java" --exec cat {}

Length of output: 279217


修复错误消息的语法错误

错误码 ORG_ZSTACK_KVM_XMLHOOK_10001 已在 CloudOperationsErrorCode 类中正确定义,结构化错误处理方式符合规范。但错误消息中存在语法错误需要修正。

在第 201-202 行,将错误消息中的 "details is" 改为 "details are"(details 为复数形式):

-                                errs.add(operr(ORG_ZSTACK_KVM_XMLHOOK_10001, "xml hook[uuid: %s] updated successfully, but failed to restart vm[uuid:%s]. details is: %s",
+                                errs.add(operr(ORG_ZSTACK_KVM_XMLHOOK_10001, "xml hook[uuid: %s] updated successfully, but failed to restart vm[uuid:%s]. details are: %s",
🤖 Prompt for AI Agents
In plugin/kvm/src/main/java/org/zstack/kvm/xmlhook/XmlHookBase.java around lines
201-202, the error message text has a grammar issue; change the message fragment
"details is: %s" to the grammatically correct "details are: %s" so the formatted
error string reads "... but failed to restart vm[uuid:%s]. details are: %s";
keep the error code ORG_ZSTACK_KVM_XMLHOOK_10001 and the existing parameters
unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants