Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions conf/db/upgrade/V5.5.12__schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
CREATE TABLE IF NOT EXISTS `zstack`.`HaNetworkGroupVO` (
`uuid` VARCHAR(32) NOT NULL UNIQUE COMMENT 'uuid',
`name` VARCHAR(255) NOT NULL,
`description` VARCHAR(2048) DEFAULT NULL,
`clusterUuid` VARCHAR(32) NOT NULL,
`type` VARCHAR(128) NOT NULL,
`minAvailableCount` INT(10) NOT NULL DEFAULT 1,
`configVersion` BIGINT UNSIGNED NOT NULL DEFAULT 0,
`state` VARCHAR(32) NOT NULL DEFAULT 'Enabled',
`lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`uuid`),
CONSTRAINT `fkHaNetworkGroupVOClusterEO` FOREIGN KEY (`clusterUuid`) REFERENCES `zstack`.`ClusterEO` (`uuid`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `zstack`.`HaNetworkGroupL3NetworkRefVO` (
`uuid` VARCHAR(32) NOT NULL UNIQUE COMMENT 'uuid',
`haNetworkGroupUuid` VARCHAR(32) NOT NULL,
`l3NetworkUuid` VARCHAR(32) NOT NULL,
`lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`uuid`),
INDEX `idxHaNetworkGroupL3NetworkRefVOhaNetworkGroupUuid` (`haNetworkGroupUuid`),
INDEX `idxHaNetworkGroupL3NetworkRefVOl3NetworkUuid` (`l3NetworkUuid`),
CONSTRAINT `fkHaNetworkGroupL3NetworkRefVOHaNetworkGroupVO` FOREIGN KEY (`haNetworkGroupUuid`) REFERENCES `zstack`.`HaNetworkGroupVO` (`uuid`) ON DELETE CASCADE,
CONSTRAINT `fkHaNetworkGroupL3NetworkRefVOL3NetworkEO` FOREIGN KEY (`l3NetworkUuid`) REFERENCES `zstack`.`L3NetworkEO` (`uuid`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `zstack`.`HostHaNetworkGroupStatusVO` (
`uuid` VARCHAR(32) NOT NULL UNIQUE COMMENT 'uuid',
`hostUuid` VARCHAR(32) NOT NULL,
`networkGroupUuid` VARCHAR(32) NOT NULL,
`status` VARCHAR(32) NOT NULL DEFAULT 'Unknown',
`lastOpDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`uuid`),
INDEX `idxHostHaNetworkGroupStatusVOhostUuid` (`hostUuid`),
INDEX `idxHostHaNetworkGroupStatusVOnetworkGroupUuid` (`networkGroupUuid`),
CONSTRAINT `fkHostHaNetworkGroupStatusVOHostEO` FOREIGN KEY (`hostUuid`) REFERENCES `zstack`.`HostEO` (`uuid`) ON DELETE CASCADE,
CONSTRAINT `fkHostHaNetworkGroupStatusVOHaNetworkGroupVO` FOREIGN KEY (`networkGroupUuid`) REFERENCES `zstack`.`HaNetworkGroupVO` (`uuid`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
45 changes: 45 additions & 0 deletions plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,41 @@ public static class SetVmConsolePasswordLiveCmd extends AgentCommand implements
public void setPassword(String password) { this.password = password; }
}

public static class UpdateVmEnableHaLiveCmd extends AgentCommand implements Serializable {
private String vmUuid;
@GrayVersion(value = "5.5.12")
private Boolean enableHa = false;

public String getVmUuid() {
return vmUuid;
}

public void setVmUuid(String vmUuid) {
this.vmUuid = vmUuid;
}

public Boolean getEnableHa() {
return enableHa;
}

public void setEnableHa(Boolean enableHa) {
this.enableHa = enableHa == null ? false : enableHa;
}
}

public static class ReconcileVmEnableHaOnHostCmd extends AgentCommand implements Serializable {
@GrayVersion(value = "5.5.12")
private List<String> neverStopVmUuids;

public List<String> getNeverStopVmUuids() {
return neverStopVmUuids;
}

public void setNeverStopVmUuids(List<String> neverStopVmUuids) {
this.neverStopVmUuids = neverStopVmUuids;
}
}

public static class UpdateL2NetworkCmd extends AgentCommand {
private String physicalInterfaceName;
private String bridgeName;
Expand Down Expand Up @@ -2236,6 +2271,8 @@ public static class StartVmCmd extends vdiCmd implements VmAddOnsCmd {
private String nestedVirtualization;
@GrayVersion(value = "5.0.0")
private String hostManagementIp;
@GrayVersion(value = "5.5.12")
private Boolean enableHa = false;
Comment on lines +2274 to +2275
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== StartVmCmd enableHa block =="
rg -n "enableHa|@GrayVersion" plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java -C2

echo
echo "== 该文件中的 5.5.x GrayVersion 分布 =="
rg -n "@GrayVersion\(value = \"5\.5\.[0-9]+\"\)" plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java

echo
echo "== 仓库内 POM 版本线(抽样前10个)== "
fd pom.xml -x head -20 {} \; 2>/dev/null | grep -E "version|revision" | head -30 || true

Repository: MatheMatrix/zstack

Length of output: 48882


🏁 Script executed:

#!/bin/bash
# 检查目标分支信息和当前版本配置
echo "== 检查git分支信息 =="
git branch -a 2>/dev/null | grep -E "5\.[0-9]+\.[0-9]+" || echo "未找到版本相关分支"

echo
echo "== 检查启用HA相关的版本标注 =="
rg -n "enableHa|@GrayVersion" plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java -B1 -A1 | head -40

Repository: MatheMatrix/zstack

Length of output: 1696


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== UpdateVmEnableHaLiveCmd 完整定义 =="
rg -n "class UpdateVmEnableHaLiveCmd" plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java -A15

echo
echo "== ReconcileVmEnableHaOnHostCmd 完整定义 =="
rg -n "class ReconcileVmEnableHaOnHostCmd" plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java -A15

echo
echo "== 检查这些新增命令类是否被关联的消息类引用 =="
rg -r "UpdateVmEnableHaLiveCmd|ReconcileVmEnableHaOnHostCmd" . --type java | head -20

echo
echo "== 查看 StartVmCmd 的 getter/setter 完整实现 =="
rg -n "setEnableHa|getEnableHa" plugin/kvm/src/main/java/org/zstack/kvm/KVMAgentCommands.java -B1 -A3

Repository: MatheMatrix/zstack

Length of output: 30493


新增命令类缺少版本标注,且 enableHa 处理逻辑不一致。

  1. UpdateVmEnableHaLiveCmdReconcileVmEnableHaOnHostCmd 均缺少 @GrayVersion 注解。新增的命令类应遵循项目规范,明确标注其首次可用版本。

  2. StartVmCmd.enableHa 标注为 @GrayVersion("5.5.12"),但项目当前版本为 5.5.0,且同文件其他 5.5.x 特性标注为 5.5.0 或 5.5.6。版本号应与实际功能首次可用版本对齐,避免灰度阶段低版本 agent 接收不到该字段。

  3. UpdateVmEnableHaLiveCmd.setEnableHa() 无 null 处理,而 StartVmCmd.setEnableHa() 做了 enableHa == null ? false : enableHa 的转换。两者应保持一致的 null 处理策略,以确保灰度下的行为预期一致。

🤖 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/KVMAgentCommands.java` around lines
2272 - 2273, Add `@GrayVersion` to the two new command classes
(UpdateVmEnableHaLiveCmd and ReconcileVmEnableHaOnHostCmd) to match project
convention, change StartVmCmd.enableHa's `@GrayVersion` from "5.5.12" to the
correct initial rollout version (use "5.5.0" to align with project current
version), and make null handling consistent by updating
UpdateVmEnableHaLiveCmd.setEnableHa(...) to mirror StartVmCmd.setEnableHa(...)
(convert null to false via enableHa == null ? false : enableHa) so both setter
behaviors are identical.

@GrayVersion(value = "5.0.0")
private String clock;
@GrayVersion(value = "5.0.0")
Expand Down Expand Up @@ -2714,6 +2751,14 @@ public void setHostManagementIp(String hostManagementIp) {
this.hostManagementIp = hostManagementIp;
}

public Boolean getEnableHa() {
return enableHa;
}

public void setEnableHa(Boolean enableHa) {
this.enableHa = enableHa == null ? false : enableHa;
}

public VolumeTO getRootVolume() {
return rootVolume;
}
Expand Down
2 changes: 2 additions & 0 deletions plugin/kvm/src/main/java/org/zstack/kvm/KVMConstant.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ public interface KVMConstant {
String KVM_BLOCK_PULL_VOLUME_PATH = "/vm/volume/blockpull";
String TAKE_VM_CONSOLE_SCREENSHOT_PATH = "/vm/console/screenshot";
String UPDATE_VM_CONSOLE_PASSWORD_PATH = "/host/vm/updateConsolePassword/live";
String UPDATE_VM_ENABLE_HA_LIVE_PATH = "/host/vm/updateEnableHa/live";
String RECONCILE_VM_ENABLE_HA_LIVE_PATH = "/host/vm/reconcileEnableHa/live";

String KVM_HOST_IPSET_ATTACH_NIC_PATH = "/network/ipset/attach";
String KVM_HOST_IPSET_DETACH_NIC_PATH = "/network/ipset/detach";
Expand Down
2 changes: 2 additions & 0 deletions sdk/src/main/java/SourceClassMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ public class SourceClassMap {
put("org.zstack.guesttools.GuestVmScriptInventory", "org.zstack.sdk.GuestVmScriptInventory");
put("org.zstack.guesttools.InvocationRecord", "org.zstack.sdk.InvocationRecord");
put("org.zstack.guesttools.InvocationRecordDetail", "org.zstack.sdk.InvocationRecordDetail");
put("org.zstack.ha.HaNetworkGroupInventory", "org.zstack.sdk.HaNetworkGroupInventory");
put("org.zstack.ha.HaStrategyConditionInventory", "org.zstack.sdk.HaStrategyConditionInventory");
put("org.zstack.header.acl.AccessControlListEntryInventory", "org.zstack.sdk.AccessControlListEntryInventory");
put("org.zstack.header.acl.AccessControlListInventory", "org.zstack.sdk.AccessControlListInventory");
Expand Down Expand Up @@ -1092,6 +1093,7 @@ public class SourceClassMap {
put("org.zstack.sdk.GuestVmScriptExecutedRecordInventory", "org.zstack.guesttools.GuestVmScriptExecutedRecordInventory");
put("org.zstack.sdk.GuestVmScriptInventory", "org.zstack.guesttools.GuestVmScriptInventory");
put("org.zstack.sdk.H3cSdnControllerTenantInventory", "org.zstack.sdnController.header.H3cSdnControllerTenantInventory");
put("org.zstack.sdk.HaNetworkGroupInventory", "org.zstack.ha.HaNetworkGroupInventory");
put("org.zstack.sdk.HaStrategyConditionInventory", "org.zstack.ha.HaStrategyConditionInventory");
put("org.zstack.sdk.HaiTaiSecretResourcePoolInventory", "org.zstack.crypto.securitymachine.thirdparty.haitai.HaiTaiSecretResourcePoolInventory");
put("org.zstack.sdk.HardwareL2VxlanNetworkInventory", "org.zstack.sdnController.header.HardwareL2VxlanNetworkInventory");
Expand Down
104 changes: 104 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/ChangeHaNetworkGroupStateAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package org.zstack.sdk;

import java.util.HashMap;
import java.util.Map;
import org.zstack.sdk.*;

public class ChangeHaNetworkGroupStateAction extends AbstractAction {

private static final HashMap<String, Parameter> parameterMap = new HashMap<>();

private static final HashMap<String, Parameter> nonAPIParameterMap = new HashMap<>();

public static class Result {
public ErrorCode error;
public org.zstack.sdk.ChangeHaNetworkGroupStateResult value;

public Result throwExceptionIfError() {
if (error != null) {
throw new ApiException(
String.format("error[code: %s, description: %s, details: %s, globalErrorCode: %s]", error.code, error.description, error.details, error.globalErrorCode)
);
}

return this;
}
}

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String uuid;

@Param(required = true, validValues = {"enable","disable"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String stateEvent;

@Param(required = false)
public java.util.List systemTags;

@Param(required = false)
public java.util.List userTags;

@Param(required = false)
public String sessionId;

@Param(required = false)
public String accessKeyId;

@Param(required = false)
public String accessKeySecret;

@Param(required = false)
public String requestIp;

@NonAPIParam
public long timeout = -1;

@NonAPIParam
public long pollingInterval = -1;


private Result makeResult(ApiResult res) {
Result ret = new Result();
if (res.error != null) {
ret.error = res.error;
return ret;
}

org.zstack.sdk.ChangeHaNetworkGroupStateResult value = res.getResult(org.zstack.sdk.ChangeHaNetworkGroupStateResult.class);
ret.value = value == null ? new org.zstack.sdk.ChangeHaNetworkGroupStateResult() : value;

return ret;
}

public Result call() {
ApiResult res = ZSClient.call(this);
return makeResult(res);
}

public void call(final Completion<Result> completion) {
ZSClient.call(this, new InternalCompletion() {
@Override
public void complete(ApiResult res) {
completion.complete(makeResult(res));
}
});
}

protected Map<String, Parameter> getParameterMap() {
return parameterMap;
}

protected Map<String, Parameter> getNonAPIParameterMap() {
return nonAPIParameterMap;
}

protected RestInfo getRestInfo() {
RestInfo info = new RestInfo();
info.httpMethod = "PUT";
info.path = "/ha/network-groups/{uuid}/actions";
info.needSession = true;
info.needPoll = true;
info.parameterName = "changeHaNetworkGroupState";
return info;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.zstack.sdk;

import org.zstack.sdk.HaNetworkGroupInventory;

public class ChangeHaNetworkGroupStateResult {
public HaNetworkGroupInventory inventory;
public void setInventory(HaNetworkGroupInventory inventory) {
this.inventory = inventory;
}
public HaNetworkGroupInventory getInventory() {
return this.inventory;
}

}
122 changes: 122 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/CreateHaNetworkGroupAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package org.zstack.sdk;

import java.util.HashMap;
import java.util.Map;
import org.zstack.sdk.*;

public class CreateHaNetworkGroupAction extends AbstractAction {

private static final HashMap<String, Parameter> parameterMap = new HashMap<>();

private static final HashMap<String, Parameter> nonAPIParameterMap = new HashMap<>();

public static class Result {
public ErrorCode error;
public org.zstack.sdk.CreateHaNetworkGroupResult value;

public Result throwExceptionIfError() {
if (error != null) {
throw new ApiException(
String.format("error[code: %s, description: %s, details: %s, globalErrorCode: %s]", error.code, error.description, error.details, error.globalErrorCode)
);
}

return this;
}
}

@Param(required = true, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String name;

@Param(required = false, maxLength = 2048, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String description;

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String clusterUuid;

@Param(required = true, validValues = {"Flat","Public"}, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.lang.String type;

@Param(required = true, nonempty = false, nullElements = false, emptyString = true, numberRange = {1L,2147483647L}, noTrim = false)
public int minAvailableCount = 0;

@Param(required = true, nonempty = true, nullElements = false, emptyString = true, noTrim = false)
public java.util.List l3NetworkUuids;

@Param(required = false)
public java.lang.String resourceUuid;

@Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false)
public java.util.List tagUuids;

@Param(required = false)
public java.util.List systemTags;

@Param(required = false)
public java.util.List userTags;

@Param(required = false)
public String sessionId;

@Param(required = false)
public String accessKeyId;

@Param(required = false)
public String accessKeySecret;

@Param(required = false)
public String requestIp;

@NonAPIParam
public long timeout = -1;

@NonAPIParam
public long pollingInterval = -1;


private Result makeResult(ApiResult res) {
Result ret = new Result();
if (res.error != null) {
ret.error = res.error;
return ret;
}

org.zstack.sdk.CreateHaNetworkGroupResult value = res.getResult(org.zstack.sdk.CreateHaNetworkGroupResult.class);
ret.value = value == null ? new org.zstack.sdk.CreateHaNetworkGroupResult() : value;

return ret;
}

public Result call() {
ApiResult res = ZSClient.call(this);
return makeResult(res);
}

public void call(final Completion<Result> completion) {
ZSClient.call(this, new InternalCompletion() {
@Override
public void complete(ApiResult res) {
completion.complete(makeResult(res));
}
});
}

protected Map<String, Parameter> getParameterMap() {
return parameterMap;
}

protected Map<String, Parameter> getNonAPIParameterMap() {
return nonAPIParameterMap;
}

protected RestInfo getRestInfo() {
RestInfo info = new RestInfo();
info.httpMethod = "POST";
info.path = "/ha/network-groups";
info.needSession = true;
info.needPoll = true;
info.parameterName = "params";
return info;
}

}
14 changes: 14 additions & 0 deletions sdk/src/main/java/org/zstack/sdk/CreateHaNetworkGroupResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.zstack.sdk;

import org.zstack.sdk.HaNetworkGroupInventory;

public class CreateHaNetworkGroupResult {
public HaNetworkGroupInventory inventory;
public void setInventory(HaNetworkGroupInventory inventory) {
this.inventory = inventory;
}
public HaNetworkGroupInventory getInventory() {
return this.inventory;
}

}
Loading