Skip to content

<feature>[kvm]: add libvirt TLS config#3458

Closed
zstack-robot-2 wants to merge 1 commit into
5.5.12from
sync/yingzhe.hu/ZSTAC-81343@@2
Closed

<feature>[kvm]: add libvirt TLS config#3458
zstack-robot-2 wants to merge 1 commit into
5.5.12from
sync/yingzhe.hu/ZSTAC-81343@@2

Conversation

@zstack-robot-2

Copy link
Copy Markdown
Collaborator

Add libvirt.tls.enabled GlobalConfig and useTls field in MigrateVmCmd to support TLS-encrypted libvirt connections for migration and V2V.

Resolves: ZSTAC-81343

Change-Id: I391fa36c0dd63c25c5d85d102bc3579c8eb3d685

sync from gitlab !9317

@coderabbitai

coderabbitai Bot commented Mar 11, 2026

Copy link
Copy Markdown

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

一组功能与平台改进:为 KVM 迁移加入 TLS 支持并传递证书 IP;扩展数据库表以支持通知与 BareMetal2 DPU;新增/修改平台核心(实体生命周期可卸载回调、任务进度详细解析);放宽安全组优先级校验;大量测试与 SDK 辅助方法扩展;若干配置与脚本调整。

Changes

Cohort / File(s) Summary
KVM TLS 与迁移参数
plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java, plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalConfig.java, plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java, plugin/kvm/src/main/java/org/zstack/kvm/KVMHostDeployArguments.java
为迁移命令新增 useTlssrcHostManagementIp 字段并添加访问器;新增全局配置 LIBVIRT_TLS_ENABLED;在构建迁移时设置 useTls、源管理 IP,并将管理 IP 与额外 IP 汇总为 tls_cert_ips 并传入部署参数。
数据库 schema 与迁移脚本
conf/db/upgrade/V5.5.12__schema.sql, conf/db/upgrade/beforeMigrate.sql
新增通知与 webhook 表、BareMetal2 DPU 相关表并调整若干外键为 ON DELETE SET NULL;将 JSON 函数字符串参数与返回类型扩容为 MEDIUMTEXT。
核心生命周期回调
core/src/main/java/org/zstack/core/db/DatabaseFacade.java, core/src/main/java/org/zstack/core/db/DatabaseFacadeImpl.java
增加可卸载的实体生命周期回调 API,实现事件 -> 回调列表结构,支持注册/注销并在触发时遍历回调列表。
任务进度与长任务详情
header/src/main/java/org/zstack/header/core/progress/LongJobProgressDetail.java, .../LongJobProgressDetailBuilder.java, .../TaskProgressInventory.java, core/src/main/java/org/zstack/core/progress/ProgressReportService.java, header/src/main/java/org/zstack/header/longjob/LongJobProgressNotificationMessage.java, header/src/main/java/org/zstack/header/core/progress/APIGetTaskProgressReply.java
新增 LongJobProgressDetail 及其解析器 Builder,从 TaskProgressVO.opaque 解析多种进度格式并在进度库存/通知中暴露详细字段;ProgressReportService 填充 progressDetail。
安全组优先级校验调整
plugin/securityGroup/src/main/java/org/zstack/network/securitygroup/SecurityGroupApiInterceptor.java
移除必须从 1 开始且连续的优先级要求,改为基于最大允许值的范围校验,并更新相关错误信息。
主机/裸金属相关与管理
compute/src/main/java/org/zstack/compute/host/HostManagerImpl.java, compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java, utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java, header/src/main/java/org/zstack/header/cluster/APICreateClusterMsg.java, header/src/main/java/org/zstack/header/cluster/APICreateClusterMsgDoc_zh_cn.groovy
为跳过架构检查引入常量列表(含 baremetal2/baremetal2Dpu);允许起 VM 时在无 L3 网络情况下的候选分配;新增 Baremetal2 相关错误码常量;扩展 cluster hypervisor 类型允许值为 baremetal2Dpu
安装脚本与版本
conf/tools/install.sh, VERSION
简化/硬化 Python venv 与 Ansible 重建检查逻辑;更新版本号(UPDATE 从 6 到 12)。
本地化解析与测试
core/src/main/java/org/zstack/core/errorcode/LocaleUtils.java, test/src/test/groovy/org/zstack/test/integration/core/ErrorCodeI18nCase.groovy
加强 Accept-Language 解析中的空标签跳过逻辑;新增针对 LocaleUtils 与 ErrorCode 拷贝构造器的集成测试集。
LoadBalancer 运行时校验
plugin/loadBalancer/src/main/java/org/zstack/network/service/lb/LoadBalancerApiInterceptor.java
新增运行时校验:若存在系统标签禁止 HTTP 压缩则拒绝创建监听器并返回特定错误码。
测试调整与测试库扩展
test/.../securitygroup/*.groovy, testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
若干安全组测试从期望异常改为校验返回结果;大量新增 API helper wrapper 方法以扩展测试库的请求能力。

Sequence Diagram(s)

sequenceDiagram
    participant KVMHost as KVMHost
    participant Config as KVMGlobalConfig
    participant AgentCmd as KVMAgentCommands.MigrateVmCmd
    participant DeployArgs as KVMHostDeployArguments
    participant Libvirt as Libvirt (remote)

    KVMHost->>Config: 读取 LIBVIRT_TLS_ENABLED
    Config-->>KVMHost: 返回值 (true/false)
    KVMHost->>AgentCmd: new MigrateVmCmd(...)\nsetUseTls(value)\nsetSrcHostManagementIp(srcHostMnIp)
    KVMHost->>DeployArgs: setTlsCertIps(managementIp[, extraIps])
    KVMHost->>Libvirt: 发送迁移请求(包含 useTls, srcHostManagementIp, tlsCertIps)
    Libvirt-->>KVMHost: 返回迁移响应
Loading

预计代码审查工作量

🎯 5 (Critical) | ⏱️ ~120 分钟

🐰 我把证书轻轻叼起,
源主机 IP 放口袋里,
TLS 隧道跳一道,
虚拟机暖暖到另一堤,
胡萝卜庆贺真欢喜 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR标题遵循正确的格式[feature][scope]: description,长度38字符,未超过72字符限制,准确描述了主要变更(添加libvirt TLS配置)。
Description check ✅ Passed PR描述与变更集相关,清晰说明了目标:添加libvirt.tls.enabled全局配置和MigrateVmCmd中的useTls字段以支持TLS加密的libvirt连接用于迁移和V2V。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/yingzhe.hu/ZSTAC-81343@@2
📝 Coding Plan
  • Generate coding plan for human review comments

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/kvm/src/main/java/org/zstack/kvm/KVMHost.java`:
- Line 3177: The call to
KVMGlobalConfig.LIBVIRT_TLS_ENABLED.value(Boolean.class) in KVMHost (affecting
cmd.setUseTls) bypasses cluster-scoped overrides; change it to fetch the
cluster-level value via the resource config facade (use
rcf.getResourceConfigValue) for the host's cluster (use the host/cluster UUID
available in KVMHost) and pass that Boolean into cmd.setUseTls, matching the
pattern used elsewhere in this class (e.g., where rcf.getResourceConfigValue is
used around lines ~3157, ~3931, ~1782).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)

Review profile: CHILL

Plan: Pro

Run ID: 7bb792e6-a9b5-4822-b465-e9ee96620481

📥 Commits

Reviewing files that changed from the base of the PR and between 1912469 and 32af041.

📒 Files selected for processing (3)
  • plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java
  • plugin/kvm/src/main/java/org/zstack/kvm/KVMGlobalConfig.java
  • plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java

Comment thread plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java Outdated
@MatheMatrix MatheMatrix force-pushed the sync/yingzhe.hu/ZSTAC-81343@@2 branch from 69e99d0 to 5e7f24f Compare March 13, 2026 06:41
@zstack-robot-2

Copy link
Copy Markdown
Collaborator Author

Comment from yaohua.wu:

Review: MR !9317 — ZSTAC-81343 (libvirt TLS 配置 - Java 侧)

关联 MR: zstack-utility !6727 | premium !13134

正面评价

  • LIBVIRT_TLS_ENABLED 正确定义为全局配置(移除了 @BindResourceConfig),避免集群间 TLS 配置不一致导致的迁移失败
  • defaultValue = "true" 确保新安装环境默认安全
  • srcHostManagementIp 字段正确补充了反向迁移场景(migrateFromDestination=true)的 TLS 证书 SAN 匹配需求
  • @GrayVersion(value = "5.5.12") 灰度版本标注正确

Warning

  1. [KVMHost.java] 其他构造 MigrateVmCmd 的代码路径

    当前 diff 仅展示了一处设置 cmd.setUseTls()cmd.setSrcHostManagementIp() 的位置。如果项目中还有其他地方构造 MigrateVmCmd(如 V2V 模块、存储迁移模块、mini 残留路径),这些位置需要同步设置 TLS 参数。

    kvmagent 侧通过 getattr(cmd, 'useTls', False) 做了向后兼容,遗漏的构造点会 fallback 到 TCP——而 TCP 端口 16509 已被 libvirtd.conf 关闭,会导致连接拒绝。

    建议全局搜索 new MigrateVmCmd()MigrateVmCmd cmd 确认所有构造点已覆盖。

Suggestion

  1. [KVMGlobalConfig.java] 补充回退约束注释

    建议在 LIBVIRT_TLS_ENABLED 声明处添加注释说明:设为 false 仅影响迁移协议选择,不会自动恢复物理机的 TCP 监听(需手动修改 libvirtd.conf + 重启 libvirtd)。避免后续维护者误解该配置的完整回退能力。

Verdict: APPROVED

Java 侧改动简洁正确,架构决策合理(全局配置 vs 集群级配置的选择正确)。Warning #1 建议确认但不阻塞合并。


🤖 Robot Reviewer

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
plugin/kvm/src/main/java/org/zstack/kvm/KVMHostDeployArguments.java (1)

140-146: 建议为 tlsCertIps 的格式约束补充简短说明。

当前使用 String 表达“IP 列表”语义,建议在 Line 140-146 的访问器处补一行 Javadoc(例如分隔符、是否允许空值、IPv6 表达方式),可降低调用方误传风险。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/kvm/src/main/java/org/zstack/kvm/KVMHostDeployArguments.java` around
lines 140 - 146, 为 KVMHostDeployArguments 类的 tlsCertIps 访问器补充一行
Javadoc,说明该字段是用何种格式表示“IP 列表”的(例如分隔符为逗号或分号)、是否允许空值/空字符串表示“无 IP”、是否支持
IPv6(是否需要方括号或纯文本形式)、以及一个短示例;在 getTlsCertIps 和 setTlsCertIps
的注释处添加上述说明,以便调用方明确传入格式与校验预期。
plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java (1)

5820-5828: 建议规范化 tlsCertIps 输入,避免空白/重复 IP 进入 SAN。

当前拼接方式可工作,但对 EXTRA_IPS 的空白与重复值不够稳健,建议在赋值前做 trim + 过滤空值 + 去重

♻️ 建议修改
-                        // Build TLS cert IP list: management IP + extra IPs (migration network etc.)
-                        String managementIp = getSelf().getManagementIp();
-                        String extraIps = HostSystemTags.EXTRA_IPS.getTokenByResourceUuid(
-                                self.getUuid(), HostSystemTags.EXTRA_IPS_TOKEN);
-                        if (extraIps != null && !extraIps.isEmpty()) {
-                            deployArguments.setTlsCertIps(managementIp + "," + extraIps);
-                        } else {
-                            deployArguments.setTlsCertIps(managementIp);
-                        }
+                        // Build TLS cert IP list: management IP + normalized extra IPs (migration network etc.)
+                        String managementIp = getSelf().getManagementIp();
+                        String extraIps = HostSystemTags.EXTRA_IPS.getTokenByResourceUuid(
+                                self.getUuid(), HostSystemTags.EXTRA_IPS_TOKEN);
+                        List<String> tlsCertIps = new ArrayList<>();
+                        tlsCertIps.add(managementIp);
+                        if (StringUtils.isNotBlank(extraIps)) {
+                            Arrays.stream(extraIps.split(","))
+                                    .map(String::trim)
+                                    .filter(StringUtils::isNotBlank)
+                                    .filter(ip -> !managementIp.equals(ip))
+                                    .distinct()
+                                    .forEach(tlsCertIps::add);
+                        }
+                        deployArguments.setTlsCertIps(String.join(",", tlsCertIps));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java` around lines 5820 -
5828, The TLS SAN construction in KVMHost currently concatenates management IP
and HostSystemTags.EXTRA_IPS raw string, which can introduce blank or duplicate
entries; update the logic around getSelf().getManagementIp() and
HostSystemTags.EXTRA_IPS.getTokenByResourceUuid(self.getUuid(),
HostSystemTags.EXTRA_IPS_TOKEN) to: split the EXTRA_IPS string by comma, trim
each entry, filter out empty strings, remove duplicates while preserving order
(ensuring the management IP is present and first), then join with commas and
pass the normalized result to deployArguments.setTlsCertIps(...).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java`:
- Around line 5820-5828: The TLS SAN construction in KVMHost currently
concatenates management IP and HostSystemTags.EXTRA_IPS raw string, which can
introduce blank or duplicate entries; update the logic around
getSelf().getManagementIp() and
HostSystemTags.EXTRA_IPS.getTokenByResourceUuid(self.getUuid(),
HostSystemTags.EXTRA_IPS_TOKEN) to: split the EXTRA_IPS string by comma, trim
each entry, filter out empty strings, remove duplicates while preserving order
(ensuring the management IP is present and first), then join with commas and
pass the normalized result to deployArguments.setTlsCertIps(...).

In `@plugin/kvm/src/main/java/org/zstack/kvm/KVMHostDeployArguments.java`:
- Around line 140-146: 为 KVMHostDeployArguments 类的 tlsCertIps 访问器补充一行
Javadoc,说明该字段是用何种格式表示“IP 列表”的(例如分隔符为逗号或分号)、是否允许空值/空字符串表示“无 IP”、是否支持
IPv6(是否需要方括号或纯文本形式)、以及一个短示例;在 getTlsCertIps 和 setTlsCertIps
的注释处添加上述说明,以便调用方明确传入格式与校验预期。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)

Review profile: CHILL

Plan: Pro

Run ID: 8eb5611a-11f0-4037-9c40-662ac0aa5c2c

📥 Commits

Reviewing files that changed from the base of the PR and between 5e7f24f and 9d7034e.

📒 Files selected for processing (2)
  • plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java
  • plugin/kvm/src/main/java/org/zstack/kvm/KVMHostDeployArguments.java

@MatheMatrix MatheMatrix force-pushed the sync/yingzhe.hu/ZSTAC-81343@@2 branch from 1701b41 to 82f907d Compare March 17, 2026 07:15

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
conf/tools/install.sh (1)

98-138: ⚠️ Potential issue | 🟡 Minor

建议将 /usr/bin/ansible/usr/bin/ansible-playbook 的存在性纳入重建条件。

当前仅校验 venv 内 ansible 可执行与版本;若系统包装脚本丢失但 venv 正常,会跳过重建,导致后续通过 /usr/bin/ansible* 调用失败。建议把包装脚本检查也加入条件,保证安装流程幂等。

建议修改
-    if [ ! -x "$SYS_VIRENV_PATH/bin/ansible" ] || ! "$SYS_VIRENV_PATH/bin/ansible" --version 2>/dev/null | grep -q 'core 2.16.14'; then
+    if [ ! -x "$SYS_VIRENV_PATH/bin/ansible" ] \
+        || ! "$SYS_VIRENV_PATH/bin/ansible" --version 2>/dev/null | grep -q 'core 2.16.14' \
+        || [ ! -x "/usr/bin/ansible" ] \
+        || [ ! -x "/usr/bin/ansible-playbook" ]; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@conf/tools/install.sh` around lines 98 - 138, The current venv-recreate
conditional only checks "$SYS_VIRENV_PATH/bin/ansible" and its version, but not
the wrapper scripts /usr/bin/ansible and /usr/bin/ansible-playbook, so if those
wrappers are missing the block is skipped and calls break; update the if
condition to also test the presence/executability of the wrapper scripts (e.g.
add checks like [ ! -x /usr/bin/ansible ] || [ ! -x /usr/bin/ansible-playbook ]
into the combined condition) so the venv and wrappers are rebuilt when either
the venv binary, its version, or either wrapper is absent or non-executable;
keep the existing rebuild steps (rm -rf $SYS_VIRENV_PATH, python3.11 -m venv,
pip install, and the cat > /usr/bin/ansible* wrapper creation) unchanged.
🧹 Nitpick comments (8)
header/src/main/java/org/zstack/header/cluster/APICreateClusterMsg.java (1)

68-73: 请同步更新 @choices 注释,避免与实际校验值不一致。

Line 73 已允许 baremetal2xdragonbaremetal2Dpu,但 Lines 68-72 的注释仍是旧列表,容易误导 API 使用方。

建议修改
-     * `@choices` - KVM
-     * - Simulator
-     * - baremetal
+     * `@choices` - KVM
+     * - Simulator
+     * - baremetal
+     * - baremetal2
+     * - xdragon
+     * - baremetal2Dpu

As per coding guidelines, “对于较长的注释,需要仔细校对并随代码更新,确保内容正确”。

🤖 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/cluster/APICreateClusterMsg.java`
around lines 68 - 73, 更新 APICreateClusterMsg 类中与字段 'hypervisorType' 相关的 Javadoc
注释,使 `@choices` 列表与 `@APIParam`(validValues = {"KVM", "Simulator", "baremetal",
"baremetal2", "xdragon", "baremetal2Dpu"}) 保持一致;具体操作是在 APICreateClusterMsg 的
hypervisorType 注释(当前第68-72行)补充或替换旧的选项,加入
baremetal2、xdragon、baremetal2Dpu,确保注释文本与 `@APIParam` 的 validValues 完全匹配以避免误导 API
使用者。
test/src/test/groovy/org/zstack/test/integration/networkservice/provider/flat/securitygroup/AddSecurityGroupRuleOptimizedCase.groovy (1)

594-617: 测试更新正确,但缺少对新添加规则的断言验证。

移除 expect(AssertionError) 包装器的改动正确反映了新的范围校验逻辑。但在 Lines 611-615 添加 rule_12ingressRule 后,测试方法直接结束,没有验证这些规则是否成功创建。

建议添加类似 Line 599 的断言来验证规则是否以预期的优先级被创建:

💡 建议的修复
         sg3 = addSecurityGroupRule {
             securityGroupUuid = sg3.uuid
             rules = [rule_12, ingressRule]
             priority = 12
         }
 
+        assert sg3.rules.find { it.dstIpRange == rule_12.dstIpRange && it.priority == 12 } != null
+        assert sg3.rules.find { it.dstPortRange == ingressRule.dstPortRange && it.type == "Ingress" } != null
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@test/src/test/groovy/org/zstack/test/integration/networkservice/provider/flat/securitygroup/AddSecurityGroupRuleOptimizedCase.groovy`
around lines 594 - 617, After adding rule_12 and ingressRule to sg3 via the
addSecurityGroupRule call, add assertions that verify the new rules were created
with the expected fields and priority: assert that sg3.rules contains an entry
with dstIpRange == rule_12.dstIpRange and priority == 12 (for rule_12), and
assert that sg3.rules contains an entry with protocol == ingressRule.protocol,
dstPortRange == ingressRule.dstPortRange and priority == 12 (for ingressRule);
locate the check near the existing assertion that validated rule_13 and mirror
its style using sg3, rule_12, ingressRule and the addSecurityGroupRule call.
plugin/securityGroup/src/main/java/org/zstack/network/securitygroup/SecurityGroupApiInterceptor.java (1)

1181-1186: 错误消息重复,建议合并逻辑。

两个条件检查的错误消息内容完全相同,但使用了不同的错误码(10120 和 10121)。考虑到逻辑可读性和一致性,建议将两个检查合并:

♻️ 建议的重构
-        if (msg.getPriority() > SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT.value(Integer.class) && toCreateIngressRuleCount > 0) {
-            throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SECURITYGROUP_10120, "could not add security group rule, because priority[%d] exceeds the maximum allowed priority [%d]", msg.getPriority(), SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT.value(Integer.class)));
-        }
-        if (msg.getPriority() > SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT.value(Integer.class) && toCreateEgressRuleCount > 0) {
-            throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SECURITYGROUP_10121, "could not add security group rule, because priority[%d] exceeds the maximum allowed priority [%d]", msg.getPriority(), SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT.value(Integer.class)));
-        }
+        if (msg.getPriority() > SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT.value(Integer.class)) {
+            throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SECURITYGROUP_10120, "could not add security group rule, because priority[%d] exceeds the maximum allowed priority [%d]", msg.getPriority(), SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT.value(Integer.class)));
+        }

当前拆分检查的条件 toCreateIngressRuleCount > 0toCreateEgressRuleCount > 0 实际上是冗余的,因为在 Line 963-965 已经检查了 rules.isEmpty(),所以至少有一种规则类型的数量 > 0。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@plugin/securityGroup/src/main/java/org/zstack/network/securitygroup/SecurityGroupApiInterceptor.java`
around lines 1181 - 1186, Combine the two duplicate priority checks in
SecurityGroupApiInterceptor into a single condition: check if msg.getPriority()
> SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT.value(Integer.class)
and (toCreateIngressRuleCount > 0 || toCreateEgressRuleCount > 0), then throw a
single ApiMessageInterceptionException with a unified error message; use one
consistent error code (e.g., ORG_ZSTACK_NETWORK_SECURITYGROUP_10120) and
reference msg.getPriority() and
SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT in the thrown message.
plugin/loadBalancer/src/main/java/org/zstack/network/service/lb/LoadBalancerApiInterceptor.java (1)

868-875: 验证逻辑正确,与现有模式一致。

这段新增代码阻止用户通过 system tag 直接设置 httpCompressAlgos::disable,与 Lines 1136-1156 中通过 API 字段处理的逻辑形成互补,防止绕过。错误信息使用英文,符合编码规范。

可选改进:考虑对提取的值进行 trim 处理

根据 Interceptor 相关编码规范,用户从浏览器复制粘贴的数据可能带有空格。虽然文件中现有的类似模式(如 Lines 849-867)也未使用 trim,但如果希望更严格地匹配,可以考虑:

             if (LoadBalancerSystemTags.HTTP_COMPRESS_ALGOS.isMatch(tag)) {
                 String compressAlgos = LoadBalancerSystemTags.HTTP_COMPRESS_ALGOS.getTokenByTag(tag,
                         LoadBalancerSystemTags.HTTP_COMPRESS_ALGOS_TOKEN);
-                if (DisableLbSupportHttpCompressAlgos.equals(compressAlgos)) {
+                if (compressAlgos != null && DisableLbSupportHttpCompressAlgos.equals(compressAlgos.trim())) {
                     throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SERVICE_LB_10172,
                             "could not create the loadbalancer listener with systemTag httpCompressAlgos::disable, please remove this tag"));
                 }
             }

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@plugin/loadBalancer/src/main/java/org/zstack/network/service/lb/LoadBalancerApiInterceptor.java`
around lines 868 - 875, The new interceptor block correctly blocks the system
tag value "httpCompressAlgos::disable", but to be robust against
leading/trailing spaces from copy/paste, trim the extracted token before
comparison: call getTokenByTag(...) and apply trim() to the result, then compare
against DisableLbSupportHttpCompressAlgos; keep throwing
ApiMessageInterceptionException with argerr when matched (same behavior around
LoadBalancerSystemTags.HTTP_COMPRESS_ALGOS and the surrounding tag-checking
block).
plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java (1)

5821-5829: 建议规范化 tlsCertIps,避免脏数据进入 SAN 列表

当前直接拼接 extraIps,若标签里有空白/空项/重复值,会把无效项透传到部署参数。建议在组装时做 trim、去空、去重。

♻️ 建议修改
-                        String managementIp = getSelf().getManagementIp();
-                        String extraIps = HostSystemTags.EXTRA_IPS.getTokenByResourceUuid(
-                                self.getUuid(), HostSystemTags.EXTRA_IPS_TOKEN);
-                        if (extraIps != null && !extraIps.isEmpty()) {
-                            deployArguments.setTlsCertIps(managementIp + "," + extraIps);
-                        } else {
-                            deployArguments.setTlsCertIps(managementIp);
-                        }
+                        String managementIp = getSelf().getManagementIp();
+                        String extraIps = HostSystemTags.EXTRA_IPS.getTokenByResourceUuid(
+                                self.getUuid(), HostSystemTags.EXTRA_IPS_TOKEN);
+                        List<String> tlsCertIps = new ArrayList<>();
+                        tlsCertIps.add(managementIp);
+                        if (extraIps != null) {
+                            Arrays.stream(extraIps.split(","))
+                                    .map(String::trim)
+                                    .filter(ip -> !ip.isEmpty())
+                                    .filter(ip -> !ip.equals(managementIp))
+                                    .distinct()
+                                    .forEach(tlsCertIps::add);
+                        }
+                        deployArguments.setTlsCertIps(String.join(",", tlsCertIps));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java` around lines 5821 -
5829, The tlsCertIps string is built by directly concatenating extraIps which
may contain blanks, empty items or duplicates; in KVMHost (use
getSelf().getManagementIp(),
HostSystemTags.EXTRA_IPS.getTokenByResourceUuid(...) and
deployArguments.setTlsCertIps(...)) split extraIps by comma, trim each entry,
filter out empty strings, remove duplicates (preserve order), prepend the
management IP if not already present, then join with commas and pass the cleaned
result to deployArguments.setTlsCertIps; ensure null/empty extraIps is handled
by setting just the management IP.
conf/db/upgrade/beforeMigrate.sql (1)

70-86: 表名缺少反引号包裹

根据编码规范,所有表名和列名必须使用反引号包裹,以避免 MySQL 8.0 / GreatSQL 保留关键字冲突。cleanupUsedIpVO 存储过程中的表名未使用反引号。

♻️ 建议修复
-        SELECT COUNT(*) INTO vipCount FROM VipVO WHERE usedIpUuid = curUsedIpUuid;
+        SELECT COUNT(*) INTO vipCount FROM `VipVO` WHERE `usedIpUuid` = curUsedIpUuid;
         IF (vipCount > 0) THEN
             ITERATE read_loop;
         END IF;

-        SELECT COUNT(*) INTO vmNicCount FROM VmNicVO WHERE usedIpUuid = curUsedIpUuid;
+        SELECT COUNT(*) INTO vmNicCount FROM `VmNicVO` WHERE `usedIpUuid` = curUsedIpUuid;
         IF (vmNicCount > 0) THEN
             ITERATE read_loop;
         END IF;

-        SELECT COUNT(*) INTO dhcpCount FROM SystemTagVO WHERE resourceType='L3NetworkVO'
+        SELECT COUNT(*) INTO dhcpCount FROM `SystemTagVO` WHERE `resourceType`='L3NetworkVO'
          AND tag LIKE CONCAT('flatNetwork::DhcpServer::%::ipUuid::', curUsedIpUuid,  '%');
         IF (dhcpCount > 0) THEN
             ITERATE read_loop;
         END IF;

-        DELETE FROM UsedIpVO WHERE uuid = curUsedIpUuid;
+        DELETE FROM `UsedIpVO` WHERE `uuid` = curUsedIpUuid;

As per coding guidelines: "所有表名和列名必须使用反引号包裹(例如:WHERE system = 1),以避免 MySQL 8.0 / GreatSQL 保留关键字冲突导致的语法错误"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@conf/db/upgrade/beforeMigrate.sql` around lines 70 - 86, The SQL uses
unquoted table and column identifiers inside the cleanupUsedIpVO logic (queries
against VipVO, VmNicVO, SystemTagVO, UsedIpVO and columns like usedIpUuid, uuid,
resourceType, tag), which can break on MySQL 8+/GreatSQL; update each SQL
statement in the shown block to wrap all table and column names with backticks
(e.g., `VipVO`, `usedIpUuid`, `VmNicVO`, `SystemTagVO`, `resourceType`, `tag`,
`UsedIpVO`, `uuid`) while keeping the same control flow (IF checks, ITERATE
read_loop, DELETE) and references to the variable curUsedIpUuid and the
read_loop label unchanged.
conf/db/upgrade/V5.5.12__schema.sql (1)

112-124: 外键操作缺少幂等性检查

ALTER TABLE ... DROP FOREIGN KEY 在约束不存在时会失败。如果升级脚本需要重复执行(例如升级失败后重试),这可能导致问题。

建议使用存储过程或条件检查来确保幂等性:

-- 可以考虑封装为存储过程,先检查约束是否存在
DROP PROCEDURE IF EXISTS `DROP_FK_IF_EXISTS`;
DELIMITER $$
CREATE PROCEDURE `DROP_FK_IF_EXISTS`(IN tb_name VARCHAR(64), IN fk_name VARCHAR(64))
BEGIN
    IF EXISTS (SELECT 1 FROM information_schema.TABLE_CONSTRAINTS 
               WHERE TABLE_SCHEMA = 'zstack' AND TABLE_NAME = tb_name 
               AND CONSTRAINT_NAME = fk_name AND CONSTRAINT_TYPE = 'FOREIGN KEY') THEN
        SET `@sql` = CONCAT('ALTER TABLE zstack.', tb_name, ' DROP FOREIGN KEY ', fk_name);
        PREPARE stmt FROM `@sql`;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END IF;
END$$
DELIMITER ;

Based on learnings: "ZStack 数据库升级脚本中的 DDL 操作应该通过 information_schema 检查存在性来确保脚本可以安全重复执行。"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@conf/db/upgrade/V5.5.12__schema.sql` around lines 112 - 124, The ALTER TABLE
drops are not idempotent; before calling ALTER TABLE ... DROP FOREIGN KEY for
fkBareMetal2InstanceVOGatewayVO and fkBareMetal2InstanceVOGatewayVO1 on
BareMetal2InstanceVO, add an existence check against
information_schema.TABLE_CONSTRAINTS (TABLE_SCHEMA='zstack',
TABLE_NAME='BareMetal2InstanceVO', CONSTRAINT_NAME=<fk>) and only execute the
DROP if the row exists (you can implement a small stored procedure like
DROP_FK_IF_EXISTS(tb_name,fk_name) or inline prepared statement logic); likewise
guard the ADD CONSTRAINT blocks by checking that those foreign keys do not
already exist before adding them to ensure the upgrade script is safe to re-run.
core/src/main/java/org/zstack/core/db/DatabaseFacade.java (1)

88-88: 给新接口补一段 Javadoc,明确卸载语义。

entityClass == null 是否表示“对所有实体类卸载”、以及 evt / cb 是否允许为 null,现在只能从实现里反推。把契约写在接口上,后续调用方才不容易误用。

📝 建议补充
+    /**
+     * Uninstall a previously installed entity lifecycle callback.
+     * If entityClass is null, the callback is removed from all registered entity classes.
+     */
     void uninstallEntityLifeCycleCallback(Class entityClass, EntityEvent evt, EntityLifeCycleCallback cb);

As per coding guidelines, "接口方法不应有多余的修饰符(例如 public),且必须配有有效的 Javadoc 注释。"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/org/zstack/core/db/DatabaseFacade.java` at line 88, 为
uninstallEntityLifeCycleCallback 方法补一段 Javadoc,明确卸载语义:说明参数 entityClass 为 null
时是否表示“对所有实体类卸载”,evt(EntityEvent)和 cb(EntityLifeCycleCallback)是否允许为 null 及其含义(例如
evt 为 null 表示卸载该回调对所有事件,cb 为 null
表示移除所有回调),并注明方法的副作用/并发行为(是否线程安全、是否即时生效或延迟生效)和返回/异常契约;在注释中引用方法名
uninstallEntityLifeCycleCallback 及参数名 entityClass、evt、cb 以便调用方明确用法。
🤖 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/host/HostManagerImpl.java`:
- Around line 476-477: 更新注释以匹配实际逻辑:当前注释只提到 baremetal2,但方法实际基于
SKIP_ARCH_CHECK_HYPERVISOR_TYPES 对 cluster.getHypervisorType() 做判断(包含
baremetal2Dpu 等项);请修改该注释为通用描述,例如说明“跳过对集群架构和 hypervisor 类型的校验,对于在
SKIP_ARCH_CHECK_HYPERVISOR_TYPES 列表中的 hypervisor 类型(例如 baremetal2、baremetal2Dpu
等)不进行校验”,以确保注释与 SKIP_ARCH_CHECK_HYPERVISOR_TYPES 和 cluster.getHypervisorType()
的行为一致。

In `@core/src/main/java/org/zstack/core/db/DatabaseFacadeImpl.java`:
- Around line 910-915: The uninstallEntityLifeCycleCallback currently silently
no-ops when entityInfoMap.get(clz) returns null; change it to mirror
installEntityLifeCycleCallback by asserting or throwing when EntityInfo is
missing so wrong class arguments are not swallowed. Locate
uninstallEntityLifeCycleCallback and replace the silent path that ignores a null
EntityInfo with the same guard used in installEntityLifeCycleCallback (check
entityInfoMap for clz and assert/throw if null) before calling
info.uninstallLifeCycleCallback(evt, cb), referencing EntityInfo, entityInfoMap,
EntityEvent, and EntityLifeCycleCallback.

---

Outside diff comments:
In `@conf/tools/install.sh`:
- Around line 98-138: The current venv-recreate conditional only checks
"$SYS_VIRENV_PATH/bin/ansible" and its version, but not the wrapper scripts
/usr/bin/ansible and /usr/bin/ansible-playbook, so if those wrappers are missing
the block is skipped and calls break; update the if condition to also test the
presence/executability of the wrapper scripts (e.g. add checks like [ ! -x
/usr/bin/ansible ] || [ ! -x /usr/bin/ansible-playbook ] into the combined
condition) so the venv and wrappers are rebuilt when either the venv binary, its
version, or either wrapper is absent or non-executable; keep the existing
rebuild steps (rm -rf $SYS_VIRENV_PATH, python3.11 -m venv, pip install, and the
cat > /usr/bin/ansible* wrapper creation) unchanged.

---

Nitpick comments:
In `@conf/db/upgrade/beforeMigrate.sql`:
- Around line 70-86: The SQL uses unquoted table and column identifiers inside
the cleanupUsedIpVO logic (queries against VipVO, VmNicVO, SystemTagVO, UsedIpVO
and columns like usedIpUuid, uuid, resourceType, tag), which can break on MySQL
8+/GreatSQL; update each SQL statement in the shown block to wrap all table and
column names with backticks (e.g., `VipVO`, `usedIpUuid`, `VmNicVO`,
`SystemTagVO`, `resourceType`, `tag`, `UsedIpVO`, `uuid`) while keeping the same
control flow (IF checks, ITERATE read_loop, DELETE) and references to the
variable curUsedIpUuid and the read_loop label unchanged.

In `@conf/db/upgrade/V5.5.12__schema.sql`:
- Around line 112-124: The ALTER TABLE drops are not idempotent; before calling
ALTER TABLE ... DROP FOREIGN KEY for fkBareMetal2InstanceVOGatewayVO and
fkBareMetal2InstanceVOGatewayVO1 on BareMetal2InstanceVO, add an existence check
against information_schema.TABLE_CONSTRAINTS (TABLE_SCHEMA='zstack',
TABLE_NAME='BareMetal2InstanceVO', CONSTRAINT_NAME=<fk>) and only execute the
DROP if the row exists (you can implement a small stored procedure like
DROP_FK_IF_EXISTS(tb_name,fk_name) or inline prepared statement logic); likewise
guard the ADD CONSTRAINT blocks by checking that those foreign keys do not
already exist before adding them to ensure the upgrade script is safe to re-run.

In `@core/src/main/java/org/zstack/core/db/DatabaseFacade.java`:
- Line 88: 为 uninstallEntityLifeCycleCallback 方法补一段 Javadoc,明确卸载语义:说明参数
entityClass 为 null 时是否表示“对所有实体类卸载”,evt(EntityEvent)和
cb(EntityLifeCycleCallback)是否允许为 null 及其含义(例如 evt 为 null 表示卸载该回调对所有事件,cb 为 null
表示移除所有回调),并注明方法的副作用/并发行为(是否线程安全、是否即时生效或延迟生效)和返回/异常契约;在注释中引用方法名
uninstallEntityLifeCycleCallback 及参数名 entityClass、evt、cb 以便调用方明确用法。

In `@header/src/main/java/org/zstack/header/cluster/APICreateClusterMsg.java`:
- Around line 68-73: 更新 APICreateClusterMsg 类中与字段 'hypervisorType' 相关的 Javadoc
注释,使 `@choices` 列表与 `@APIParam`(validValues = {"KVM", "Simulator", "baremetal",
"baremetal2", "xdragon", "baremetal2Dpu"}) 保持一致;具体操作是在 APICreateClusterMsg 的
hypervisorType 注释(当前第68-72行)补充或替换旧的选项,加入
baremetal2、xdragon、baremetal2Dpu,确保注释文本与 `@APIParam` 的 validValues 完全匹配以避免误导 API
使用者。

In `@plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java`:
- Around line 5821-5829: The tlsCertIps string is built by directly
concatenating extraIps which may contain blanks, empty items or duplicates; in
KVMHost (use getSelf().getManagementIp(),
HostSystemTags.EXTRA_IPS.getTokenByResourceUuid(...) and
deployArguments.setTlsCertIps(...)) split extraIps by comma, trim each entry,
filter out empty strings, remove duplicates (preserve order), prepend the
management IP if not already present, then join with commas and pass the cleaned
result to deployArguments.setTlsCertIps; ensure null/empty extraIps is handled
by setting just the management IP.

In
`@plugin/loadBalancer/src/main/java/org/zstack/network/service/lb/LoadBalancerApiInterceptor.java`:
- Around line 868-875: The new interceptor block correctly blocks the system tag
value "httpCompressAlgos::disable", but to be robust against leading/trailing
spaces from copy/paste, trim the extracted token before comparison: call
getTokenByTag(...) and apply trim() to the result, then compare against
DisableLbSupportHttpCompressAlgos; keep throwing ApiMessageInterceptionException
with argerr when matched (same behavior around
LoadBalancerSystemTags.HTTP_COMPRESS_ALGOS and the surrounding tag-checking
block).

In
`@plugin/securityGroup/src/main/java/org/zstack/network/securitygroup/SecurityGroupApiInterceptor.java`:
- Around line 1181-1186: Combine the two duplicate priority checks in
SecurityGroupApiInterceptor into a single condition: check if msg.getPriority()
> SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT.value(Integer.class)
and (toCreateIngressRuleCount > 0 || toCreateEgressRuleCount > 0), then throw a
single ApiMessageInterceptionException with a unified error message; use one
consistent error code (e.g., ORG_ZSTACK_NETWORK_SECURITYGROUP_10120) and
reference msg.getPriority() and
SecurityGroupGlobalConfig.SECURITY_GROUP_RULES_NUM_LIMIT in the thrown message.

In
`@test/src/test/groovy/org/zstack/test/integration/networkservice/provider/flat/securitygroup/AddSecurityGroupRuleOptimizedCase.groovy`:
- Around line 594-617: After adding rule_12 and ingressRule to sg3 via the
addSecurityGroupRule call, add assertions that verify the new rules were created
with the expected fields and priority: assert that sg3.rules contains an entry
with dstIpRange == rule_12.dstIpRange and priority == 12 (for rule_12), and
assert that sg3.rules contains an entry with protocol == ingressRule.protocol,
dstPortRange == ingressRule.dstPortRange and priority == 12 (for ingressRule);
locate the check near the existing assertion that validated rule_13 and mirror
its style using sg3, rule_12, ingressRule and the addSecurityGroupRule call.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: http://open.zstack.ai:20001/code-reviews/zstack-cloud.yaml (via .coderabbit.yaml)

Review profile: CHILL

Plan: Pro

Run ID: d3e8a1fc-872d-438c-a2be-4ad96376b402

📥 Commits

Reviewing files that changed from the base of the PR and between 9d7034e and 1701b41.

⛔ Files ignored due to path filters (33)
  • conf/i18n/globalErrorCodeMapping/global-error-de-DE.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-en_US.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-fr-FR.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-id-ID.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-ja-JP.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-ko-KR.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-ru-RU.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-th-TH.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-zh_CN.json is excluded by !**/*.json
  • conf/i18n/globalErrorCodeMapping/global-error-zh_TW.json is excluded by !**/*.json
  • sdk/src/main/java/SourceClassMap.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/AddBareMetal2DpuChassisAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/BareMetal2DpuChassisInventory.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/BareMetal2DpuHostInventory.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/CreateBareMetal2InstanceAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/CreateClusterAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/GpuVendor.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/LongJobProgressDetail.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/StartBareMetal2InstanceAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/TaskProgressInventory.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/ZSClient.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/DeleteResNotifySubscriptionAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/DeleteResNotifySubscriptionResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/QueryResNotifySubscriptionAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/QueryResNotifySubscriptionResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/ResNotifySubscriptionInventory.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/ResNotifySubscriptionState.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/ResNotifyType.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/ResNotifyWebhookRefInventory.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/SubscribeResNotifyAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/SubscribeResNotifyResult.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/UpdateResNotifySubscriptionAction.java is excluded by !sdk/**
  • sdk/src/main/java/org/zstack/sdk/zwatch/resnotify/UpdateResNotifySubscriptionResult.java is excluded by !sdk/**
📒 Files selected for processing (26)
  • VERSION
  • compute/src/main/java/org/zstack/compute/host/HostManagerImpl.java
  • compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java
  • conf/db/upgrade/V5.5.12__schema.sql
  • conf/db/upgrade/beforeMigrate.sql
  • conf/tools/install.sh
  • core/src/main/java/org/zstack/core/db/DatabaseFacade.java
  • core/src/main/java/org/zstack/core/db/DatabaseFacadeImpl.java
  • core/src/main/java/org/zstack/core/errorcode/LocaleUtils.java
  • core/src/main/java/org/zstack/core/progress/ProgressReportService.java
  • header/src/main/java/org/zstack/header/cluster/APICreateClusterMsg.java
  • header/src/main/java/org/zstack/header/cluster/APICreateClusterMsgDoc_zh_cn.groovy
  • header/src/main/java/org/zstack/header/core/progress/APIGetTaskProgressReply.java
  • header/src/main/java/org/zstack/header/core/progress/LongJobProgressDetail.java
  • header/src/main/java/org/zstack/header/core/progress/LongJobProgressDetailBuilder.java
  • header/src/main/java/org/zstack/header/core/progress/TaskProgressInventory.java
  • header/src/main/java/org/zstack/header/errorcode/ErrorCode.java
  • header/src/main/java/org/zstack/header/longjob/LongJobProgressNotificationMessage.java
  • plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java
  • plugin/loadBalancer/src/main/java/org/zstack/network/service/lb/LoadBalancerApiInterceptor.java
  • plugin/securityGroup/src/main/java/org/zstack/network/securitygroup/SecurityGroupApiInterceptor.java
  • test/src/test/groovy/org/zstack/test/integration/core/ErrorCodeI18nCase.groovy
  • test/src/test/groovy/org/zstack/test/integration/networkservice/provider/flat/securitygroup/AddSecurityGroupRuleOptimizedCase.groovy
  • test/src/test/groovy/org/zstack/test/integration/networkservice/provider/flat/securitygroup/ChangeSecurityGroupRuleCase.groovy
  • testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy
  • utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java

Comment thread compute/src/main/java/org/zstack/compute/host/HostManagerImpl.java
Comment on lines +910 to +915
public void uninstallEntityLifeCycleCallback(Class clz, EntityEvent evt, EntityLifeCycleCallback cb) {
if (clz != null) {
EntityInfo info = entityInfoMap.get(clz);
if (info != null) {
info.uninstallLifeCycleCallback(evt, cb);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

按类卸载时不要静默吞掉 EntityInfo 缺失。

这里和 installEntityLifeCycleCallback() 不对称:安装时会 Assert,卸载时却直接 no-op。传错类时,回调实际上不会被卸掉,还会继续响应后续 entity event,问题会被悄悄吞掉。

🧩 建议修改
     public void uninstallEntityLifeCycleCallback(Class clz, EntityEvent evt, EntityLifeCycleCallback cb) {
         if (clz != null) {
             EntityInfo info = entityInfoMap.get(clz);
-            if (info != null) {
-                info.uninstallLifeCycleCallback(evt, cb);
-            }
+            DebugUtils.Assert(info != null, String.format("cannot find EntityInfo for the class[%s]", clz));
+            info.uninstallLifeCycleCallback(evt, cb);
         } else {
             for (EntityInfo info : entityInfoMap.values()) {
                 info.uninstallLifeCycleCallback(evt, cb);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/org/zstack/core/db/DatabaseFacadeImpl.java` around lines
910 - 915, The uninstallEntityLifeCycleCallback currently silently no-ops when
entityInfoMap.get(clz) returns null; change it to mirror
installEntityLifeCycleCallback by asserting or throwing when EntityInfo is
missing so wrong class arguments are not swallowed. Locate
uninstallEntityLifeCycleCallback and replace the silent path that ignores a null
EntityInfo with the same guard used in installEntityLifeCycleCallback (check
entityInfoMap for clz and assert/throw if null) before calling
info.uninstallLifeCycleCallback(evt, cb), referencing EntityInfo, entityInfoMap,
EntityEvent, and EntityLifeCycleCallback.

@MatheMatrix MatheMatrix force-pushed the sync/yingzhe.hu/ZSTAC-81343@@2 branch 7 times, most recently from 6629b8f to d6f16dc Compare March 18, 2026 02:43
Add libvirt.tls.enabled GlobalConfig and useTls field in MigrateVmCmd to support TLS-encrypted libvirt connections for migration and V2V.

Resolves: ZSTAC-81343

Change-Id: I391fa36c0dd63c25c5d85d102bc3579c8eb3d685
@MatheMatrix MatheMatrix force-pushed the sync/yingzhe.hu/ZSTAC-81343@@2 branch from d6f16dc to 3feb9e9 Compare March 18, 2026 03:12
@MatheMatrix MatheMatrix deleted the sync/yingzhe.hu/ZSTAC-81343@@2 branch March 18, 2026 11:52
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