ZSTAC-86567: select target-aware MN endpoint#4554
Conversation
Use configured family-specific node and HA endpoints. Reject missing same-family endpoints before KVM side effects. Resolves: ZSTAC-86567 Change-Id: I71789399f44edcbb742b77360182299eef00253c
|
Warning
|
| Layer / File(s) | Summary |
|---|---|
HA 地址族与端点选择模型 utils/src/main/java/org/zstack/utils/zsha2/ZSha2Info.java, utils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.java, core/src/main/java/org/zstack/core/ManagementEndpointData.java |
新增 IPv4/IPv6 HA 配置结构、端点错误码,以及按目标地址族选择 NODE、CANONICAL_NODE 和 VIP 的逻辑。 |
Platform 管理端点解析 core/src/main/java/org/zstack/core/Platform.java |
Platform 通过端点数据选择默认或目标感知的管理节点 IP、VIP 和规范节点 IP,并按配置构建 IPv4/IPv6 地址集合。 |
部署与 KVM 回调接入 core/src/main/java/org/zstack/core/ansible/AnsibleRunner.java, plugin/kvm/src/main/java/org/zstack/kvm/KVMHost.java |
AnsibleRunner 和 KVMHost 使用目标感知的管理节点 IP 配置部署参数、回调检查器及错误传播流程。 |
地址族与 HA 选择验证 test/src/test/groovy/org/zstack/test/integration/core/*, test/src/test/groovy/org/zstack/test/integration/kvm/host/DualStackAddKvmHostCase.groovy |
新增并调整测试,覆盖地址族隔离、IPv4 默认优先、HA 端点类型、配置校验、Ansible 参数及 IPv6 回调命令。 |
Estimated code review effort: 4 (Complex) | ~60 minutes
Sequence Diagram(s)
sequenceDiagram
participant KVMHost
participant Platform
participant ManagementEndpointData
participant AnsibleRunner
KVMHost->>Platform: 按目标 IP 获取管理节点 IP
Platform->>ManagementEndpointData: selectForTarget
ManagementEndpointData-->>Platform: 返回目标地址族端点
Platform-->>KVMHost: 返回 callbackIp
KVMHost->>AnsibleRunner: 设置管理节点 IP
AnsibleRunner->>AnsibleRunner: 生成部署地址参数
Poem
我是兔子蹦蹦跳,
IPv4、IPv6 都收好。
HA 端点排成队,
KVM 回调不迷路。
新逻辑上线,胡萝卜庆祝!
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | 标题概括了按目标 IP 选择管理节点端点这一主要改动,且与变更内容一致。 |
| Description check | ✅ Passed | 描述准确说明了按目标地址族选择管理节点端点、HA 端点读取和 KVM/Ansible 回调改动,并包含验证信息。 |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
sync/zstackio/shixin-ZSTAC-86567-impl
Comment @coderabbitai help to get the list of available commands.
There was a problem hiding this comment.
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)
core/src/main/java/org/zstack/core/ansible/AnsibleRunner.java (1)
391-410: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win在部署判定前解析管理端点。
Line 393 先执行
isNeedRun();它可能执行远端端口/checker 检查,而返回false时 Line 404-410 根本不会运行。未设置managementNodeIp的调用方因此不能保证缺失同地址族端点会被提前拒绝。建议修复
public void run(ReturnValueCompletion<Boolean> completion) { try { + String selectedManagementNodeIp = managementNodeIp == null ? restf.getHostName() : managementNodeIp; + if (managementNodeIp == null && NetworkUtils.isIpAddress(targetIp)) { + ErrorableValue<String> managementNodeEndpoint = Platform.getManagementServerIp(targetIp); + if (!managementNodeEndpoint.isSuccess()) { + completion.fail(managementNodeEndpoint.error); + return; + } + selectedManagementNodeIp = managementNodeEndpoint.result; + } + if (!forceRun && !isNeedRun()) { completion.success(false); return; } int port = new URI(restf.getBaseUrl()).getPort(); - String selectedManagementNodeIp = managementNodeIp; - // existing endpoint selection block🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@core/src/main/java/org/zstack/core/ansible/AnsibleRunner.java` around lines 391 - 410, 在 AnsibleRunner.run 中将管理端点解析逻辑移到 forceRun/isNeedRun() 判定之前,确保未设置 managementNodeIp 且 targetIp 为 IP 时先调用 Platform.getManagementServerIp 并在失败时 completion.fail 后立即返回。保留成功解析后的 selectedManagementNodeIp 供后续流程使用,避免 isNeedRun() 提前返回导致校验被跳过。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@core/src/main/java/org/zstack/core/ManagementEndpointData.java`:
- Around line 37-50: Update ManagementEndpointData’s HA fallback logic so
nestedHaFamilies.isEmpty() does not globally suppress legacy endpoints when a
family object exists but is disabled or invalid. Make addHaFamily validate
enabled status and IP before registering the family, and apply nodeip/dbvip
fallback per IPv4/IPv6 family so unconfigured families still receive their
legacy endpoints.
In `@core/src/main/java/org/zstack/core/Platform.java`:
- Around line 1280-1295: Update getConfiguredManagementNodeIps to include the
management endpoint from the ZSTACK_MANAGEMENT_SERVER_IP environment variable,
using the existing resolution/normalization behavior and avoiding duplicate
entries when the JVM property is also set. Preserve the existing IPv4 and IPv6
secondary-property handling.
---
Outside diff comments:
In `@core/src/main/java/org/zstack/core/ansible/AnsibleRunner.java`:
- Around line 391-410: 在 AnsibleRunner.run 中将管理端点解析逻辑移到 forceRun/isNeedRun()
判定之前,确保未设置 managementNodeIp 且 targetIp 为 IP 时先调用 Platform.getManagementServerIp
并在失败时 completion.fail 后立即返回。保留成功解析后的 selectedManagementNodeIp 供后续流程使用,避免
isNeedRun() 提前返回导致校验被跳过。
🪄 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: bd9f0d17-3a7f-4f4b-987f-cc6a5f6efab3
📒 Files selected for processing (7)
core/src/main/java/org/zstack/core/ManagementEndpointData.javacore/src/main/java/org/zstack/core/Platform.javacore/src/main/java/org/zstack/core/ansible/AnsibleRunner.javaplugin/kvm/src/main/java/org/zstack/kvm/KVMHost.javatest/src/test/groovy/org/zstack/test/integration/core/ManagementNetworkIpv6Case.groovyutils/src/main/java/org/zstack/utils/clouderrorcode/CloudOperationsErrorCode.javautils/src/main/java/org/zstack/utils/zsha2/ZSha2Info.java
| public ManagementEndpointData(Collection<String> nodeIps, ZSha2Info info) { | ||
| this.ha = info != null; | ||
| for (String ip : nodeIps) { | ||
| put(this.nodeIps, ip); | ||
| } | ||
| if (info != null) { | ||
| addHaFamily(IPv6Constants.IPv4, info.getIpv4()); | ||
| addHaFamily(IPv6Constants.IPv6, info.getIpv6()); | ||
| if (nestedHaFamilies.isEmpty()) { | ||
| addLegacyHaEndpoint(haNodeIps, info.getNodeip()); | ||
| addLegacyHaEndpoint(haVips, info.getDbvip()); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 检查 ZSha2Info 的 ipv4/ipv6 是如何被赋值的(例如反序列化来源),确认未配置时是否严格为 null
rg -n -A5 -B5 'setIpv4|setIpv6' --type=java
rg -n 'ZSha2Info' --type=java -g '!**/test/**' -lRepository: MatheMatrix/zstack
Length of output: 156
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the relevant classes and nearby usages
git ls-files | rg 'ManagementEndpointData\.java|ZSha2Info\.java|Sha2Info\.java|ManagementEndpointData|ZSha2'
# Show outlines to target small slices
for f in $(git ls-files | rg 'ManagementEndpointData\.java|ZSha2Info\.java'); do
echo "==== OUTLINE: $f ===="
ast-grep outline "$f" --view expanded || true
done
# Search for constructors, getters, setters, and JSON annotations/usage
rg -n -A4 -B4 'class ZSha2Info|getIpv4\(|getIpv6\(|setIpv4\(|setIpv6\(|ipv4|ipv6|nodeip|dbvip|nestedHaFamilies|addHaFamily|addLegacyHaEndpoint' --type=java .Repository: MatheMatrix/zstack
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '==== ManagementEndpointData (selected lines) ===='
sed -n '1,160p' core/src/main/java/org/zstack/core/ManagementEndpointData.java
echo
echo '==== ZSha2Info (selected lines) ===='
sed -n '1,220p' utils/src/main/java/org/zstack/utils/zsha2/ZSha2Info.java
echo
echo '==== Usages / construction of ZSha2Info ===='
rg -n -A3 -B3 'new ZSha2Info|setIpv4\(|setIpv6\(|getIpv4\(|getIpv6\(|HaAddressFamily' --type=java .Repository: MatheMatrix/zstack
Length of output: 17387
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '==== Constructors / setters for ZSha2Info.HaAddressFamily ===='
rg -n -A4 -B4 'new ZSha2Info\.HaAddressFamily|setEnabled\(|setVirtualIp\(|setNodeIp\(|setPeerIp\(|setIpv4\(|setIpv6\(' --type=java .
echo
echo '==== Any JSON / bean binding hints around ZSha2Info ===='
rg -n -A3 -B3 'ZSha2Info|HaAddressFamily' utils/src/main/java core/src/main/java | sed -n '1,220p'Repository: MatheMatrix/zstack
Length of output: 23955
不要用 nestedHaFamilies.isEmpty() 统一决定回退
addHaFamily() 只要 ipv4/ipv6 对象存在就会把家族加入 nestedHaFamilies,即使该家族 enabled=false 或 IP 不合法;这会让另一个未配置的家族也跳过 nodeip/dbvip 旧字段回退,导致 HA 端点缺失。建议按家族分别回退,或至少把 nestedHaFamilies.add(...) 放到校验通过之后。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/src/main/java/org/zstack/core/ManagementEndpointData.java` around lines
37 - 50, Update ManagementEndpointData’s HA fallback logic so
nestedHaFamilies.isEmpty() does not globally suppress legacy endpoints when a
family object exists but is disabled or invalid. Make addHaFamily validate
enabled status and IP before registering the family, and apply nodeip/dbvip
fallback per IPv4/IPv6 family so unconfigured families still receive their
legacy endpoints.
| private static List<String> getConfiguredManagementNodeIps() { | ||
| List<String> nodeIps = new ArrayList<>(); | ||
| String primaryIp = System.getProperty(MANAGEMENT_SERVER_IP_PROPERTY); | ||
| if (!StringUtils.isBlank(primaryIp)) { | ||
| nodeIps.add(normalizeManagementIp(primaryIp)); | ||
| } | ||
|
|
||
| String ipv4 = getManagementServerSecondaryIpProperty(MANAGEMENT_SERVER_IP4_PROPERTY, IPv6Constants.IPv4); | ||
| if (ipv4 != null) { | ||
| nodeIps.add(ipv4); | ||
| } | ||
| return getManagementServerIpOnManagementInterface(IPv6Constants.IPv4); | ||
| String ipv6 = getManagementServerSecondaryIpProperty(MANAGEMENT_SERVER_IP6_PROPERTY, IPv6Constants.IPv6); | ||
| if (ipv6 != null) { | ||
| nodeIps.add(ipv6); | ||
| } | ||
| return nodeIps; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
将环境变量管理端点纳入候选集。
Line 1280 仅读取 JVM 属性,但 Line 1199-1203 明确支持 ZSTACK_MANAGEMENT_SERVER_IP。仅通过该环境变量启动时,新的目标感知选择没有候选端点,KVM/Ansible 会将同地址族主机误判为缺少管理端点并拒绝部署。
建议修复
private static List<String> getConfiguredManagementNodeIps() {
List<String> nodeIps = new ArrayList<>();
String primaryIp = System.getProperty(MANAGEMENT_SERVER_IP_PROPERTY);
if (!StringUtils.isBlank(primaryIp)) {
nodeIps.add(normalizeManagementIp(primaryIp));
}
+
+ String environmentIp = System.getenv(ZSTACK_MANAGEMENT_SERVER_IP_ENV);
+ if (!StringUtils.isBlank(environmentIp)) {
+ nodeIps.add(normalizeManagementIp(environmentIp));
+ }
String ipv4 = getManagementServerSecondaryIpProperty(MANAGEMENT_SERVER_IP4_PROPERTY, IPv6Constants.IPv4);📝 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.
| private static List<String> getConfiguredManagementNodeIps() { | |
| List<String> nodeIps = new ArrayList<>(); | |
| String primaryIp = System.getProperty(MANAGEMENT_SERVER_IP_PROPERTY); | |
| if (!StringUtils.isBlank(primaryIp)) { | |
| nodeIps.add(normalizeManagementIp(primaryIp)); | |
| } | |
| String ipv4 = getManagementServerSecondaryIpProperty(MANAGEMENT_SERVER_IP4_PROPERTY, IPv6Constants.IPv4); | |
| if (ipv4 != null) { | |
| nodeIps.add(ipv4); | |
| } | |
| return getManagementServerIpOnManagementInterface(IPv6Constants.IPv4); | |
| String ipv6 = getManagementServerSecondaryIpProperty(MANAGEMENT_SERVER_IP6_PROPERTY, IPv6Constants.IPv6); | |
| if (ipv6 != null) { | |
| nodeIps.add(ipv6); | |
| } | |
| return nodeIps; | |
| private static List<String> getConfiguredManagementNodeIps() { | |
| List<String> nodeIps = new ArrayList<>(); | |
| String primaryIp = System.getProperty(MANAGEMENT_SERVER_IP_PROPERTY); | |
| if (!StringUtils.isBlank(primaryIp)) { | |
| nodeIps.add(normalizeManagementIp(primaryIp)); | |
| } | |
| String environmentIp = System.getenv(ZSTACK_MANAGEMENT_SERVER_IP_ENV); | |
| if (!StringUtils.isBlank(environmentIp)) { | |
| nodeIps.add(normalizeManagementIp(environmentIp)); | |
| } | |
| String ipv4 = getManagementServerSecondaryIpProperty(MANAGEMENT_SERVER_IP4_PROPERTY, IPv6Constants.IPv4); | |
| if (ipv4 != null) { | |
| nodeIps.add(ipv4); | |
| } | |
| String ipv6 = getManagementServerSecondaryIpProperty(MANAGEMENT_SERVER_IP6_PROPERTY, IPv6Constants.IPv6); | |
| if (ipv6 != null) { | |
| nodeIps.add(ipv6); | |
| } | |
| return nodeIps; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@core/src/main/java/org/zstack/core/Platform.java` around lines 1280 - 1295,
Update getConfiguredManagementNodeIps to include the management endpoint from
the ZSTACK_MANAGEMENT_SERVER_IP environment variable, using the existing
resolution/normalization behavior and avoiding duplicate entries when the JVM
property is also set. Preserve the existing IPv4 and IPv6 secondary-property
handling.
Resolves: ZSTAC-86567 Change-Id: Icff182b92f222ded2cbe2466ed104418a6e68497
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
test/src/test/groovy/org/zstack/test/integration/core/ansible/AnsibleRunnerTargetAwareArgumentsCase.groovy (1)
119-143: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff可选:抽取共享的测试辅助方法以消除重复。
withManagementServerIpProperties与resetCachedManagementServerIp在本文件、PlatformManagementEndpointSelectionCase和DualStackAddKvmHostCase中几乎完全重复。可考虑抽取到一个共享的测试工具类/基类,降低后续维护成本。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/src/test/groovy/org/zstack/test/integration/core/ansible/AnsibleRunnerTargetAwareArgumentsCase.groovy` around lines 119 - 143, 可选地,将 AnsibleRunnerTargetAwareArgumentsCase、PlatformManagementEndpointSelectionCase 和 DualStackAddKvmHostCase 中重复的 withManagementServerIpProperties 与 resetCachedManagementServerIp 抽取到共享测试工具类或基类,并更新各测试复用统一实现,保持现有属性清理、恢复及缓存重置行为不变。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@test/src/test/groovy/org/zstack/test/integration/core/PlatformManagementEndpointSelectionCase.groovy`:
- Around line 11-15: 为 PlatformManagementEndpointSelectionCase 和
AnsibleRunnerTargetAwareArgumentsCase 补上可被 Surefire 执行的入口:将类及对应文件重命名为符合默认发现规则的
*Test 或 *TestCase,或把两个类显式加入现有测试 suite 并调用其测试方法;确保其中的 JUnit 测试实际参与构建执行。
---
Nitpick comments:
In
`@test/src/test/groovy/org/zstack/test/integration/core/ansible/AnsibleRunnerTargetAwareArgumentsCase.groovy`:
- Around line 119-143: 可选地,将
AnsibleRunnerTargetAwareArgumentsCase、PlatformManagementEndpointSelectionCase 和
DualStackAddKvmHostCase 中重复的 withManagementServerIpProperties 与
resetCachedManagementServerIp 抽取到共享测试工具类或基类,并更新各测试复用统一实现,保持现有属性清理、恢复及缓存重置行为不变。
🪄 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: b156c077-04a5-4174-b052-b7bb5161f83d
📒 Files selected for processing (7)
core/src/main/java/org/zstack/core/ManagementEndpointData.javacore/src/main/java/org/zstack/core/Platform.javacore/src/main/java/org/zstack/core/ansible/AnsibleRunner.javatest/src/test/groovy/org/zstack/test/integration/core/ManagementNetworkIpv6Case.groovytest/src/test/groovy/org/zstack/test/integration/core/PlatformManagementEndpointSelectionCase.groovytest/src/test/groovy/org/zstack/test/integration/core/ansible/AnsibleRunnerTargetAwareArgumentsCase.groovytest/src/test/groovy/org/zstack/test/integration/kvm/host/DualStackAddKvmHostCase.groovy
🚧 Files skipped from review as they are similar to previous changes (4)
- core/src/main/java/org/zstack/core/ansible/AnsibleRunner.java
- test/src/test/groovy/org/zstack/test/integration/core/ManagementNetworkIpv6Case.groovy
- core/src/main/java/org/zstack/core/ManagementEndpointData.java
- core/src/main/java/org/zstack/core/Platform.java
| class PlatformManagementEndpointSelectionCase { | ||
| private static final String IPV4 = "192.168.1.10" | ||
| private static final String IPV6 = "2001:db8::1" | ||
|
|
||
| @Test |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 定位 test 模块 pom 并检查 surefire/failsafe include 规则及 SubCase 运行方式
fd -g 'pom.xml' test | xargs rg -n -C4 'surefire|failsafe|<include|<exclude|SubCase' 2>/dev/null
# 检查是否存在集中运行 SubCase 的入口
rg -nP -C3 '\bextends\s+SubCase\b' test/src/test/groovy/org/zstack/test/integration/core -g '*.groovy' | head -n 40Repository: MatheMatrix/zstack
Length of output: 7734
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) 找到 test 模块的 pom,并查看 surefire/failsafe 的完整配置片段
pom=$(fd -a 'pom.xml' test | head -n 1)
echo "POM=$pom"
sed -n '500,680p' "$pom"
echo
echo "---- file names ----"
# 2) 看看 integration/core 下测试文件命名分布,确认这些类是否仅靠默认 surefire 命名规则就能被发现
fd -a -t f 'test/src/test/groovy/org/zstack/test/integration/core' | sed -n '1,120p'
echo
echo "---- case/test naming ----"
# 3) 统计该目录下 *Case / *Test / *Spec 文件
fd -a -t f 'test/src/test/groovy/org/zstack/test/integration/core' \
| awk -F/ '{print $NF}' \
| grep -E '([Tt]est|[Cc]ase|[Ss]pec)\.(groovy|java)$' \
| sort
echo
echo "---- direct references ----"
# 4) 搜索是否存在显式把 *Case 作为 JUnit/Surefire 入口的配置或聚合入口
rg -n -C3 'PlatformManagementEndpointSelectionCase|AnsibleRunnerTargetAwareArgumentsCase|<includes>|<include>|failsafe|surefire|SubCase|`@RunWith`|`@Suite`' testRepository: MatheMatrix/zstack
Length of output: 5565
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- pom locations ----"
fd -a 'pom.xml' . | sed -n '1,40p'
echo
echo "---- surefire/failsafe/include refs in all poms ----"
rg -n -C3 'maven-surefire-plugin|maven-failsafe-plugin|<include>|<includes>|<exclude>|<excludes>|includesFile|excludesFile|testFailureIgnore|runOrder|forkCount' . -g 'pom.xml'
echo
echo "---- files under integration/core ----"
fd -a . 'test/src/test/groovy/org/zstack/test/integration/core' | sed -n '1,120p'
echo
echo "---- case/test/spec filenames ----"
fd -a -t f . 'test/src/test/groovy/org/zstack/test/integration/core' \
| awk -F/ '{print $NF}' \
| grep -E '\.(groovy|java)$' \
| sort
echo
echo "---- direct class references and suites ----"
rg -n -C2 'PlatformManagementEndpointSelectionCase|AnsibleRunnerTargetAwareArgumentsCase|extends\s+SubCase|`@RunWith`|`@Suite`|suite\(' test/src/test/groovy test/src/test/javaRepository: MatheMatrix/zstack
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- pom test plugins ----"
rg -n -C2 'maven-surefire-plugin|maven-failsafe-plugin|<includes>|<include>|<excludes>|<exclude>|testng|junit' test/pom.xml
echo
echo "---- target classes ----"
rg -n -C2 'class\s+(PlatformManagementEndpointSelectionCase|AnsibleRunnerTargetAwareArgumentsCase)\b|extends\s+SubCase|`@RunWith`|`@Suite`|suite\(' \
test/src/test/groovy/org/zstack/test/integration/core \
-g '*.groovy' \
--max-count 80
echo
echo "---- exact filenames ----"
fd -a -t f . test/src/test/groovy/org/zstack/test/integration/core \
| grep -E '(PlatformManagementEndpointSelectionCase|AnsibleRunnerTargetAwareArgumentsCase|Suite|Test)\.groovy$' \
| sortRepository: MatheMatrix/zstack
Length of output: 34984
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- CoreLibraryTest.groovy ----"
cat -n test/src/test/groovy/org/zstack/test/integration/core/CoreLibraryTest.groovy
echo
echo "---- BranchCascadeTest.groovy ----"
cat -n test/src/test/groovy/org/zstack/test/integration/core/branchcascade/BranchCascadeTest.groovy
echo
echo "---- target classes annotations/structure ----"
sed -n '1,220p' test/src/test/groovy/org/zstack/test/integration/core/PlatformManagementEndpointSelectionCase.groovy
echo
sed -n '1,220p' test/src/test/groovy/org/zstack/test/integration/core/ansible/AnsibleRunnerTargetAwareArgumentsCase.groovyRepository: MatheMatrix/zstack
Length of output: 12497
补上这两个 JUnit 测试的执行入口(test/src/test/groovy/org/zstack/test/integration/core/PlatformManagementEndpointSelectionCase.groovy、test/src/test/groovy/org/zstack/test/integration/core/ansible/AnsibleRunnerTargetAwareArgumentsCase.groovy)
test/pom.xml 的 surefire 没有额外 includes,默认规则不会发现这类 *Case 纯 JUnit 类;现有 CoreLibraryTest / BranchCascadeTest 也只会 runSubCases()。要么改名成 *Test/*TestCase,要么显式纳入 suite/执行入口。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@test/src/test/groovy/org/zstack/test/integration/core/PlatformManagementEndpointSelectionCase.groovy`
around lines 11 - 15, 为 PlatformManagementEndpointSelectionCase 和
AnsibleRunnerTargetAwareArgumentsCase 补上可被 Surefire 执行的入口:将类及对应文件重命名为符合默认发现规则的
*Test 或 *TestCase,或把两个类显式加入现有测试 suite 并调用其测试方法;确保其中的 JUnit 测试实际参与构建执行。
Root cause: KVM AddHost SSH precheck used RESTFacade's default callback URL, initialized from the primary MN address, and therefore sent IPv4 to an IPv6 host.
Change: select configured MN node endpoint by literal target IP family; reject missing same-family endpoints before KVM SSH or Ansible side effects; read HA canonical-node and VIP from zsha2 nested family records; reuse KVM's selected endpoint for callback checks and Ansible pip/yum/trusted_host.
Verification: mvn -pl core,plugin/kvm -am -DskipTests install; test/ mvn test -Djacoco.skip=true -Dtest=org.zstack.test.integration.core.ManagementNetworkIpv6Case (2 tests, 0 failures).
sync from gitlab !10518