Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6b4521b
<fix>[vm]: use max of virtual and actual size for root disk when no d…
AlanJager Feb 12, 2026
3b5bda3
<fix>[zbs]: enable tryNext and 30s timeout for getActiveClients MDS call
AlanJager Feb 12, 2026
80df074
<fix>[vm]: add Destroying->Stopped state transition
AlanJager Feb 12, 2026
a84a36e
<fix>[ceph]: apply over-provisioning ratio when releasing snapshot ca…
AlanJager Feb 12, 2026
f19223a
<fix>[loadBalancer]: block SLB deletion during grayscale upgrade
AlanJager Feb 13, 2026
24d4f3b
<fix>[i18n]: improve snapshot error message for unattached volume
AlanJager Feb 13, 2026
f563992
<fix>[compute]: add null check for VmNicVO in afterDelIpAddress and a…
AlanJager Feb 13, 2026
6545350
<fix>[network]: filter reserved IPs from GetFreeIp API results
AlanJager Feb 13, 2026
76490a5
Merge branch 'fix/ZSTAC-80620' into '5.5.12'
Feb 16, 2026
461e8a2
Merge branch 'fix/ZSTAC-82153' into '5.5.12'
Feb 16, 2026
32e1e94
Merge branch 'fix/ZSTAC-80595' into '5.5.12'
Feb 16, 2026
addec8c
Merge branch 'fix/ZSTAC-74683' into '5.5.12'
Feb 16, 2026
26b8b1a
<fix>[mn]: synchronize hash ring operations to prevent dual-MN task s…
AlanJager Feb 12, 2026
be53c72
Merge branch 'fix/ZSTAC-81182' into '5.5.12'
Feb 16, 2026
e1dee9f
Merge branch 'fix/ZSTAC-79709' into '5.5.12'
Feb 16, 2026
3bd062b
Merge branch 'fix/ZSTAC-81741' into '5.5.12'
Feb 16, 2026
aaeaf39
<fix>[storage]: desensitize mdsUrls in ExternalPrimaryStorageInventory
AlanJager Feb 13, 2026
f41558d
<fix>[volumebackup]: add backup cancel timeout error code
AlanJager Feb 16, 2026
673be94
Merge branch 'fix/ZSTAC-77711' into '5.5.12'
Feb 16, 2026
7f53f5a
<fix>[thread]: guard Context.current() with telemetry check
PandaWuu Feb 16, 2026
72ce6ef
Merge branch 'bugfix/ZSTAC-82275' into '5.5.12'
PandaWuu Feb 16, 2026
34bceb1
Merge branch 'fix/ZSTAC-78989' into '5.5.12'
Feb 16, 2026
3e02188
Merge branch 'fix/ZSTAC-82195' into '5.5.12'
Feb 17, 2026
799a84f
Merge branch 'fix/ZSTAC-80664' into '5.5.12'
Feb 17, 2026
08aa861
<refactor>[zstack]: Refactor extension points
AlanJager Jan 28, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public void afterAddIpAddress(String vmNicUUid, String usedIpUuid) {
SQL.New(UsedIpVO.class).eq(UsedIpVO_.uuid, usedIpUuid).set(UsedIpVO_.vmNicUuid, vmNicUUid).update();

VmNicVO nic = Q.New(VmNicVO.class).eq(VmNicVO_.uuid, vmNicUUid).find();
if (nic == null) {
logger.debug(String.format("VmNic[uuid:%s] not found, skip afterAddIpAddress", vmNicUUid));
return;
}

UsedIpVO temp = null;
/* if there is ipv4 addresses, we put the first attached ipv4 address to VmNic.ip
Expand Down Expand Up @@ -88,6 +92,10 @@ public void afterAddIpAddress(String vmNicUUid, String usedIpUuid) {
@Override
public void afterDelIpAddress(String vmNicUUid, String usedIpUuid) {
VmNicVO nic = Q.New(VmNicVO.class).eq(VmNicVO_.uuid, vmNicUUid).find();
if (nic == null) {
logger.debug(String.format("VmNic[uuid:%s] not found, skip afterDelIpAddress", vmNicUUid));
return;
}
if (nic.getUsedIpUuid() != null && !nic.getUsedIpUuid().equals(usedIpUuid)) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion conf/i18n/globalErrorCodeMapping/global-error-en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -3374,7 +3374,7 @@
"ORG_ZSTACK_NETWORK_HUAWEI_IMASTER_10019": "delete token of SDN controller [IP:%s] failed because %s",
"ORG_ZSTACK_STORAGE_PRIMARY_BLOCK_10004": "Cannot execute volume mapping to host flow due to invalid volume ID.%s",
"ORG_ZSTACK_NETWORK_SERVICE_PORTFORWARDING_10007": "port forwarding rule [uuid:%s] has not been attached to any virtual machine network interface, cannot detach",
"ORG_ZSTACK_MEVOCO_10088": "cannot take a snapshot for volumes[%s] when volume[uuid: %s] is not attached",
"ORG_ZSTACK_MEVOCO_10088": "cannot create snapshot for volume[uuid:%s] because it is not attached to any VM instance. Please attach the volume to a VM first. Affected volumes: %s",
"ORG_ZSTACK_STORAGE_PRIMARY_BLOCK_10005": "Cannot execute map LUN to host flow due to invalid LUN type: %s",
"ORG_ZSTACK_NETWORK_SERVICE_PORTFORWARDING_10008": "port forwarding rule [uuid:%s] has been associated with vm nic [uuid:%s], cannot be reassigned again",
"ORG_ZSTACK_MEVOCO_10087": "A Running VM[uuid:%s] has no associated Host UUID.",
Expand Down
2 changes: 1 addition & 1 deletion conf/i18n/globalErrorCodeMapping/global-error-zh_CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -3374,7 +3374,7 @@
"ORG_ZSTACK_NETWORK_HUAWEI_IMASTER_10019": "删除 SDN 控制器 [IP:%s] 的令牌失败,因为 %s",
"ORG_ZSTACK_STORAGE_PRIMARY_BLOCK_10004": "无法执行映射LUN到主机流程,无效的LUN ID",
"ORG_ZSTACK_NETWORK_SERVICE_PORTFORWARDING_10007": "端口转发规则 rule[uuid:%s] 没有绑定到任何 VM 的网卡上,无法解除绑定",
"ORG_ZSTACK_MEVOCO_10088": "无法为挂载状态以外的卷[%s]创建快照",
"ORG_ZSTACK_MEVOCO_10088": "无法为云盘[uuid:%s]创建快照,因为该云盘未挂载到任何云主机。请先将云盘挂载到云主机后再创建快照。相关云盘: %s",
"ORG_ZSTACK_STORAGE_PRIMARY_BLOCK_10005": "无法执行映射LUN到主机流程,无效的LUN类型",
"ORG_ZSTACK_NETWORK_SERVICE_PORTFORWARDING_10008": "端口转发规则[uuid:%s]已绑定到VM网卡[uuid:%s],无法再次绑定",
"ORG_ZSTACK_MEVOCO_10087": "如何一个运行中的VM[uuid:%s]没有宿主机uuid?",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,27 @@ public class ResourceDestinationMakerImpl implements ManagementNodeChangeListene
private DatabaseFacade dbf;

@Override
public void nodeJoin(ManagementNodeInventory inv) {
public synchronized void nodeJoin(ManagementNodeInventory inv) {
nodeHash.add(inv.getUuid());
nodes.put(inv.getUuid(), new NodeInfo(inv));
}

@Override
public void nodeLeft(ManagementNodeInventory inv) {
public synchronized void nodeLeft(ManagementNodeInventory inv) {
String nodeId = inv.getUuid();
nodeHash.remove(nodeId);
nodes.remove(nodeId);
}

@Override
public void iAmDead(ManagementNodeInventory inv) {
public synchronized void iAmDead(ManagementNodeInventory inv) {
String nodeId = inv.getUuid();
nodeHash.remove(nodeId);
nodes.remove(nodeId);
}

@Override
public void iJoin(ManagementNodeInventory inv) {
public synchronized void iJoin(ManagementNodeInventory inv) {
List<ManagementNodeVO> lst = Q.New(ManagementNodeVO.class).list();
lst.forEach((ManagementNodeVO node) -> {
nodeHash.add(node.getUuid());
Expand All @@ -56,7 +56,7 @@ public void iJoin(ManagementNodeInventory inv) {
}

@Override
public String makeDestination(String resourceUuid) {
public synchronized String makeDestination(String resourceUuid) {
String nodeUuid = nodeHash.get(resourceUuid);
if (nodeUuid == null) {
throw new CloudRuntimeException("Cannot find any available management node to send message");
Expand All @@ -66,18 +66,18 @@ public String makeDestination(String resourceUuid) {
}

@Override
public boolean isManagedByUs(String resourceUuid) {
public synchronized boolean isManagedByUs(String resourceUuid) {
String nodeUuid = makeDestination(resourceUuid);
return nodeUuid.equals(Platform.getManagementServerId());
}

@Override
public Collection<String> getManagementNodesInHashRing() {
return nodeHash.getNodes();
public synchronized Collection<String> getManagementNodesInHashRing() {
return new ArrayList<>(nodeHash.getNodes());
}

@Override
public NodeInfo getNodeInfo(String nodeUuid) {
public synchronized NodeInfo getNodeInfo(String nodeUuid) {
NodeInfo info = nodes.get(nodeUuid);
if (info == null) {
ManagementNodeVO vo = dbf.findByUuid(nodeUuid, ManagementNodeVO.class);
Expand All @@ -93,17 +93,17 @@ public NodeInfo getNodeInfo(String nodeUuid) {
}

@Override
public Collection<NodeInfo> getAllNodeInfo() {
return nodes.values();
public synchronized Collection<NodeInfo> getAllNodeInfo() {
return new ArrayList<>(nodes.values());
}

@Override
public int getManagementNodeCount() {
return nodes.values().size();
public synchronized int getManagementNodeCount() {
return nodes.size();
}


public boolean isNodeInCircle(String nodeId) {
public synchronized boolean isNodeInCircle(String nodeId) {
return nodeHash.hasNode(nodeId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ private class SyncTaskFuture<T> extends AbstractFuture<T> {

public SyncTaskFuture(SyncTask<T> task) {
super(task);
this.parentContext = Context.current();
this.parentContext = isTelemetryEnabled() ? Context.current() : null;
}

private SyncTask getTask() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import org.zstack.header.storage.primary.PrimaryStorageInventory;
import org.zstack.utils.gson.JSONObjectUtil;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Inventory(mappingVOClass = ExternalPrimaryStorageVO.class)
Expand Down Expand Up @@ -59,6 +61,7 @@ public ExternalPrimaryStorageInventory(ExternalPrimaryStorageVO lvo) {
super(lvo);
identity = lvo.getIdentity();
config = JSONObjectUtil.toObject(lvo.getConfig(), LinkedHashMap.class);
desensitizeConfig(config);
addonInfo = JSONObjectUtil.toObject(lvo.getAddonInfo(), LinkedHashMap.class);
outputProtocols = lvo.getOutputProtocols().stream().map(PrimaryStorageOutputProtocolRefVO::getOutputProtocol).collect(Collectors.toList());
defaultProtocol = lvo.getDefaultProtocol();
Expand All @@ -68,6 +71,35 @@ public static ExternalPrimaryStorageInventory valueOf(ExternalPrimaryStorageVO l
return new ExternalPrimaryStorageInventory(lvo);
}

private static void desensitizeConfig(Map config) {
if (config == null) return;
desensitizeUrlList(config, "mdsUrls");
desensitizeUrlList(config, "mdsInfos");
}

private static void desensitizeUrlList(Map config, String key) {
Object urls = config.get(key);
if (urls instanceof List) {
List<String> desensitized = new ArrayList<>();
for (Object url : (List) urls) {
desensitized.add(desensitizeUrl(String.valueOf(url)));
}
config.put(key, desensitized);
}
}

private static String desensitizeUrl(String url) {
int atIndex = url.lastIndexOf('@');
if (atIndex > 0) {
int schemeIndex = url.indexOf("://");
if (schemeIndex >= 0 && schemeIndex < atIndex) {
return url.substring(0, schemeIndex + 3) + "***" + url.substring(atIndex);
}
return "***" + url.substring(atIndex);
}
return url;
}
Comment on lines +74 to +101
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
# Search for mdsUrls and mdsInfos definitions and usage across multiple file types
rg -n -C5 'mdsUrls|mdsInfos' --type java --type groovy --type json --type xml

Repository: MatheMatrix/zstack

Length of output: 50374


🏁 Script executed:

#!/bin/bash
# Find where desensitizeConfig is called
rg -n 'desensitizeConfig' --type java -B3 -A3

Repository: MatheMatrix/zstack

Length of output: 2188


🏁 Script executed:

#!/bin/bash
# Search for where config is stored and what fields it contains
rg -n '"mdsInfos"' --type java -B2 -A2
# Also check if mdsInfos appears in config JSON strings
rg -n 'mdsInfos' --type groovy | head -30

Repository: MatheMatrix/zstack

Length of output: 1969


🏁 Script executed:

#!/bin/bash
# Check ExternalPrimaryStorageVO to understand what config actually contains
rg -n 'class ExternalPrimaryStorageVO' --type java -A30 | head -50
# Also search for where config is set/stored
rg -n 'setConfig\|getConfig' --type java | grep -i external | head -20

Repository: MatheMatrix/zstack

Length of output: 4733


🏁 Script executed:

#!/bin/bash
# Let's look at the ExternalPrimaryStorageInventory more closely to see all fields
cat -n header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageInventory.java | head -100

Repository: MatheMatrix/zstack

Length of output: 3713


🏁 Script executed:

#!/bin/bash
# Let's check the complete desensitizeUrlList and desensitizeUrl methods
cat -n header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageInventory.java | sed -n '74,101p'

# Also verify what the actual JSON structure looks like for config vs addonInfo
echo "=== Checking actual config structure in tests ==="
rg -n '"config".*mdsUrls' --type groovy | head -5
echo ""
echo "=== Checking actual addonInfo structure in tests ==="
rg -n '"addonInfo".*mdsInfos' --type groovy | head -5

Repository: MatheMatrix/zstack

Length of output: 1377


🏁 Script executed:

#!/bin/bash
# Let's look at actual test data to understand the structure better
echo "=== Config JSON from tests ==="
rg 'config = ' test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy | head -3

echo ""
echo "=== AddonInfo JSON from tests ==="
rg 'addonInfo ==' test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy | head -3

echo ""
echo "=== Check if mdsInfos ever appears in config field ==="
rg '"config".*mdsInfos' test/ --type groovy
rg 'config.*mdsInfos' test/ --type groovy

Repository: MatheMatrix/zstack

Length of output: 868


🏁 Script executed:

#!/bin/bash
# Let's verify the relationship between config and addonInfo more clearly
echo "=== Detailed look at what fields are in config ==="
rg 'config = ' test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy | grep -o '{[^}]*}' | head -10

echo ""
echo "=== Check if addonInfo is ever desensitized ==="
rg 'desensitizeAddon|addonInfo.*desensitize' --type java

echo ""
echo "=== Check if addonInfo contains mdsInfos with sensitive data ==="
cat test/src/test/groovy/org/zstack/test/integration/storage/primary/addon/zbs/ZbsPrimaryStorageCase.groovy | sed -n '534,539p'

Repository: MatheMatrix/zstack

Length of output: 2834


🏁 Script executed:

#!/bin/bash
# Let's confirm mdsInfos never appears in the config field stored in database
echo "=== Search for any place where mdsInfos is set in config ==="
rg 'config.*put.*mdsInfos|setMdsInfos.*config' --type java

echo ""
echo "=== Check if desensitizeConfig is called on addonInfo ==="
rg 'desensitizeConfig.*addon|desensitizeAddonInfo' --type java

echo ""
echo "=== Look at the full constructor again to confirm separation ==="
cat header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageInventory.java | sed -n '60,68p'

Repository: MatheMatrix/zstack

Length of output: 787


desensitizeUrlList(config, "mdsInfos") 是无效代码,且脱敏逻辑不完整,容易导致敏感数据泄露。

根据代码分析,mdsInfos 从不出现在 config 字段中(config 仅包含 mdsUrlslogicalPoolName 等),因此第 77 行的调用是死代码。

更严重的问题是:addonInfo 字段包含真实的 mdsInfos 对象(含 username、password 等敏感字段),但当前代码完全不对 addonInfo 进行脱敏,导致返回给客户端的 API 响应中仍包含明文凭证。建议:

  1. 删除第 77 行无效的 desensitizeUrlList(config, "mdsInfos") 调用。
  2. addonInfo 添加脱敏逻辑,对其中的 mdsInfos 列表元素进行脱敏(仅脱敏字符串类型元素以保证结构一致)。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@header/src/main/java/org/zstack/header/storage/addon/primary/ExternalPrimaryStorageInventory.java`
around lines 74 - 101, Remove the dead desensitizeUrlList(config, "mdsInfos")
call in desensitizeConfig and instead add desensitization for addonInfo: update
desensitizeConfig(Map config) to check for an "addonInfo" entry (expecting a Map
or JSON-like structure), locate any "mdsInfos" list inside addonInfo, and for
each element that is a String replace sensitive portions using the existing
desensitizeUrl(String) helper (or reuse desensitizeUrlList logic tailored to
addonInfo). Keep desensitizeUrlList and desensitizeUrl as-is for mdsUrls, but
ensure addonInfo.mdsInfos is processed so username/password strings are masked
while preserving non-string elements' structure.


public String getIdentity() {
return identity;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@
import org.zstack.header.errorcode.ErrorCode;

/**
* Created by LiangHanYu on 2022/6/9 18:30
* 内存快照验证扩展点
*
* <p>触发时机:创建内存快照前,验证 VM 是否符合条件</p>
* <p>调用位置:VolumeSnapshotGroupCreator.validate()</p>
*
* <h3>使用场景:</h3>
* <p>各模块通过此扩展点检查 VM 的外部设备或网络引用
* 是否与内存快照兼容。</p>
*
* @since 5.0.0
Comment on lines +6 to +15
Copy link

@coderabbitai coderabbitai bot Jan 28, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Javadoc 应使用英文编写

根据编码规范,代码中不应包含中文,包括注释和错误消息都应当使用正确的、无拼写错误的英文来编写。请将此 Javadoc 翻译为英文。

建议的英文 Javadoc
-/**
- * 内存快照验证扩展点
- *
- * <p>触发时机:创建内存快照前,验证 VM 是否符合条件</p>
- * <p>调用位置:VolumeSnapshotGroupCreator.validate()</p>
- *
- * <h3>使用场景:</h3>
- * <p>各模块通过此扩展点检查 VM 的外部设备或网络引用
- * 是否与内存快照兼容。</p>
- *
- * `@since` 5.0.0
- */
+/**
+ * Extension point for validating memory snapshot creation.
+ *
+ * <p>Trigger: Before creating a memory snapshot, validate whether the VM meets the conditions.</p>
+ * <p>Call site: VolumeSnapshotGroupCreator.validate()</p>
+ *
+ * <h3>Usage:</h3>
+ * <p>Modules use this extension point to check whether the VM's external devices
+ * or network references are compatible with memory snapshots.</p>
+ *
+ * `@since` 5.0.0
+ */

根据编码规范:代码里不应当有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写。

🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/storage/snapshot/group/MemorySnapshotValidatorExtensionPoint.java`
around lines 6 - 15, Translate the Javadoc for
MemorySnapshotValidatorExtensionPoint into clear, idiomatic English (replace the
current Chinese text) so it documents the extension point purpose, trigger
timing (before creating a memory snapshot), the invocation site
(VolumeSnapshotGroupCreator.validate()), and usage scenario (modules check VM
external devices or network references for compatibility with memory snapshots);
keep the `@since` tag and ensure no Chinese remains in the comment.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Comment from ye.zou:

Acknowledged. Chinese-to-English Javadoc translation and deprecated reference cleanup will be handled in a follow-up pass. Resolving to unblock merge.

Copy link

Choose a reason for hiding this comment

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

@ZStack-Robot Thank you for the acknowledgment! I understand you'd like to defer the Javadoc translation to a follow-up pass to unblock this merge.

Would you like me to create a follow-up issue to track this work? I can document the need to translate Chinese Javadoc to English across the affected files in this PR.

Please let me know which issue tracking platform you'd prefer:

  • Jira Project: ZSTAC
  • Jira Project: TIC
  • Jira Project: ZBS
  • GitHub

If you'd like to proceed, I'll create an issue that references this PR and comment, and includes the list of files requiring Javadoc translation (primarily MemorySnapshotValidatorExtensionPoint.java and similar files with Chinese documentation).

*/
public interface MemorySnapshotValidatorExtensionPoint {
default ErrorCode checkVmWhereMemorySnapshotExistExternalDevices(String VmInstanceUuid) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.network.l3.L3NetworkInventory;

/**
* @deprecated This interface has no implementations and should be removed.
* Use {@link org.zstack.header.vm.extensions.VmInstanceDetachNicExtensionPoint} instead.
*/
@Deprecated
public interface DetachNicExtensionPoint {
ErrorCode validateDetachNicByDriverTypeAndClusterType(L3NetworkInventory l3, VmInstanceInventory vm);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

import java.util.List;

/**
* 内存快照资源配置归档扩展点
*
* <p>触发时机:创建内存快照时,归档与 VM 相关的资源配置</p>
* <p>调用位置:MemorySnapshotManager.archiveResourceConfig()</p>
*
* <h3>使用场景:</h3>
* <p>当 VM 执行内存快照时,各模块通过此扩展点提供需要归档的资源配置,
* 以便恢复快照时可以同时恢复相关配置状态。</p>
*
* @since 5.0.0
*/
Comment on lines +5 to +16
Copy link

@coderabbitai coderabbitai bot Jan 28, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Javadoc 应使用英文编写

根据编码规范,代码中不应包含中文,包括注释和错误消息都应当使用正确的、无拼写错误的英文来编写。请将此 Javadoc 翻译为英文。

建议的英文 Javadoc
-/**
- * 内存快照资源配置归档扩展点
- *
- * <p>触发时机:创建内存快照时,归档与 VM 相关的资源配置</p>
- * <p>调用位置:MemorySnapshotManager.archiveResourceConfig()</p>
- *
- * <h3>使用场景:</h3>
- * <p>当 VM 执行内存快照时,各模块通过此扩展点提供需要归档的资源配置,
- * 以便恢复快照时可以同时恢复相关配置状态。</p>
- *
- * `@since` 5.0.0
- */
+/**
+ * Extension point for archiving resource configurations during memory snapshot creation.
+ *
+ * <p>Trigger: When creating a memory snapshot, archive VM-related resource configurations.</p>
+ * <p>Call site: MemorySnapshotManager.archiveResourceConfig()</p>
+ *
+ * <h3>Usage:</h3>
+ * <p>When a VM performs a memory snapshot, modules provide resource configurations
+ * to be archived via this extension point, allowing related configuration states
+ * to be restored when the snapshot is recovered.</p>
+ *
+ * `@since` 5.0.0
+ */

根据编码规范:代码里不应当有中文,包括报错、注释等都应当使用正确的、无拼写错误的英文来写。

🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/vm/ResourceConfigMemorySnapshotExtensionPoint.java`
around lines 5 - 16, Translate the Javadoc for the
ResourceConfigMemorySnapshotExtensionPoint interface from Chinese to clear,
idiomatic English while preserving the structure and tags (including the
description, trigger/call location lines, usage scenario paragraph, and the
`@since` 5.0.0 tag); update the comment text to explain that this extension point
archives VM-related resource configuration when creating memory snapshots, is
invoked by MemorySnapshotManager.archiveResourceConfig(), and that modules
should provide configuration to be restored with the snapshot. Ensure no Chinese
remains and keep formatting and annotations intact.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment from ye.zou:

Acknowledged. Chinese-to-English Javadoc translation and deprecated reference cleanup will be handled in a follow-up pass. Resolving to unblock merge.

Copy link

Choose a reason for hiding this comment

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

@zstack-robot-2 Understood. Since this will be addressed in a follow-up, would you like me to create a tracking issue to ensure the Javadoc translation work isn't forgotten? I can open one in your preferred issue tracking system (GitHub, Jira ZSTAC, Jira TIC, Jira ZBS) with a reference to this PR and comment.

public interface ResourceConfigMemorySnapshotExtensionPoint {
List<ArchiveResourceConfigBundle.ResourceConfigBundle> getNeedToArchiveResourceConfig(String resourceUuid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import org.zstack.header.network.l3.L3NetworkInventory;

/**
* Created by xing5 on 2016/4/18.
* @deprecated Use {@link org.zstack.header.vm.extensions.VmInstanceAttachL3NetworkExtensionPoint#afterAttachL3Network} instead.
*/
@Deprecated
public interface VmAfterAttachL3NetworkExtensionPoint {
void vmAfterAttachL3Network(VmInstanceInventory vm, L3NetworkInventory l3);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import org.zstack.header.core.NoErrorCompletion;

/**
* Created by LiangHanYu on 2022/4/13 13:24
* @deprecated Use {@link org.zstack.header.vm.extensions.VmInstanceAttachL3NetworkExtensionPoint#afterAttachL3Network} instead.
*/
@Deprecated
public interface VmAfterAttachNicExtensionPoint {
void afterAttachNic(String nicUuid, VmInstanceInventory vmInstanceInventory, Completion completion);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@


/**
* Created by Mei Lei on 8/23/16.
* @deprecated Use {@link org.zstack.header.vm.extensions.VmExpungeExtensionPoint#afterExpunge} instead.
*/
@Deprecated
public interface VmAfterExpungeExtensionPoint {
void vmAfterExpunge(VmInstanceInventory inv);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import org.zstack.header.network.l3.L3NetworkInventory;

/**
* Created by xing5 on 2016/4/18.
* @deprecated Use {@link org.zstack.header.vm.extensions.VmInstanceAttachL3NetworkExtensionPoint#beforeAttachL3Network} instead.
*/
@Deprecated
public interface VmBeforeAttachL3NetworkExtensionPoint {
void vmBeforeAttachL3Network(VmInstanceInventory vm, L3NetworkInventory l3);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@


/**
* Created by Mei Lei on 8/23/16.
* @deprecated Use {@link org.zstack.header.vm.extensions.VmExpungeExtensionPoint#beforeExpunge} instead.
*/
@Deprecated
public interface VmBeforeExpungeExtensionPoint {
void vmBeforeExpunge(VmInstanceInventory inv);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import org.zstack.header.errorcode.ErrorCode;

/**
* Created by frank on 7/18/2015.
* @deprecated Use {@link org.zstack.header.vm.extensions.VmInstanceDetachNicExtensionPoint} instead.
*/
@Deprecated
public interface VmDetachNicExtensionPoint {
void preDetachNic(VmNicInventory nic);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import org.zstack.header.network.l3.L3NetworkInventory;

/**
* Created by xing5 on 2016/4/18.
* @deprecated Use {@link org.zstack.header.vm.extensions.VmInstanceAttachL3NetworkExtensionPoint#failedToAttachL3Network} instead.
*/
@Deprecated
public interface VmFailToAttachL3NetworkExtensionPoint {
void vmFailToAttachL3Network(VmInstanceInventory vm, L3NetworkInventory l3, ErrorCode error);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package org.zstack.header.vm;

/**
* @deprecated This interface has no implementations and should be removed.
* Use {@link org.zstack.header.vm.extensions.VmInstanceAttachL3NetworkExtensionPoint} instead.
*/
@Deprecated
public interface VmInstanceAttachNicExtensionPoint {
void afterAttachNicToVm(VmNicInventory nic);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import org.zstack.header.errorcode.ErrorCode;

/**
* @deprecated Use {@link org.zstack.header.vm.extensions.VmDestroyExtensionPoint} instead.
*/
@Deprecated
public interface VmInstanceDestroyExtensionPoint {
String preDestroyVm(VmInstanceInventory inv);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,9 @@ public void setBootMode(String bootMode) {

public long getRootDiskAllocateSize() {
if (rootDiskOffering == null) {
return this.getImageSpec().getInventory().getSize();
long virtualSize = this.getImageSpec().getInventory().getSize();
long actualSize = this.getImageSpec().getInventory().getActualSize();
return Math.max(virtualSize, actualSize);
}
return rootDiskOffering.getDiskSize();
}
Comment on lines 848 to 855
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:

# First, let's understand the VmInstanceSpec class structure
fd -e java -p "VmInstanceSpec.java$" | head -5

Repository: MatheMatrix/zstack

Length of output: 191


🏁 Script executed:

# Read the VmInstanceSpec.java file to understand the full context
cat -n header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java | head -150

Repository: MatheMatrix/zstack

Length of output: 5854


🏁 Script executed:

# Look for the ImageSpec class to understand inventory field
fd -e java -p "ImageSpec.java$" | head -5

Repository: MatheMatrix/zstack

Length of output: 44


🏁 Script executed:

# Search for all calls to getRootDiskAllocateSize
rg -n "getRootDiskAllocateSize" --type java -B 3 -A 3

Repository: MatheMatrix/zstack

Length of output: 4266


🏁 Script executed:

# Examine the context in LocalStorageDesignatedAllocateCapacityFlow around line 160
sed -n '140,180p' plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageDesignatedAllocateCapacityFlow.java

Repository: MatheMatrix/zstack

Length of output: 2419


🏁 Script executed:

# Examine the context in LocalStorageDefaultAllocateCapacityFlow around line 158
sed -n '140,180p' plugin/localstorage/src/main/java/org/zstack/storage/primary/local/LocalStorageDefaultAllocateCapacityFlow.java

Repository: MatheMatrix/zstack

Length of output: 2248


🏁 Script executed:

# Examine the context in VmAllocatePrimaryStorageFlow around line 73
sed -n '50,90p' compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java

Repository: MatheMatrix/zstack

Length of output: 2154


🏁 Script executed:

# Check if there are any places where imageSpec or its inventory is set/initialized
rg -n "setInventory|imageSpec\.inventory\s*=" --type java header/src/main/java/org/zstack/header/vm/ -B 2 -A 2

Repository: MatheMatrix/zstack

Length of output: 45460


🏁 Script executed:

# Look for null checks on inventory in related files
rg -n "getInventory().*null|inventory.*null" --type java -i | head -20

Repository: MatheMatrix/zstack

Length of output: 3355


getRootDiskAllocateSize() 方法中存在潜在的空指针异常风险

rootDiskOfferingnull 时,代码直接调用 this.getImageSpec().getInventory().getSize()getActualSize()。但根据代码库中的使用模式(如 PrimaryStorageManagerImpl.java:1020),ImageSpec.inventory 字段可能为 null,这会导致 NullPointerException

建议添加防御性检查:

建议的修复
 public long getRootDiskAllocateSize() {
     if (rootDiskOffering == null) {
+        ImageInventory inventory = this.getImageSpec().getInventory();
+        if (inventory == null) {
+            return 0L;
+        }
-        long virtualSize = this.getImageSpec().getInventory().getSize();
-        long actualSize = this.getImageSpec().getInventory().getActualSize();
+        long virtualSize = inventory.getSize();
+        long actualSize = inventory.getActualSize();
         return Math.max(virtualSize, actualSize);
     }
     return rootDiskOffering.getDiskSize();
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java` around lines
848 - 855, The method getRootDiskAllocateSize() can NPE when rootDiskOffering is
null because it assumes this.getImageSpec() and getImageSpec().getInventory()
are non-null; add defensive null checks: when rootDiskOffering is null, retrieve
ImageSpec via getImageSpec() and its inventory via getInventory() and if either
is null treat virtualSize and actualSize as 0 (or another safe fallback) before
computing Math.max(virtualSize, actualSize); ensure references to
getImageSpec(), getInventory(), getSize(), and getActualSize() are guarded so no
NullPointerException can occur.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ public enum VmInstanceState {
new Transaction(VmInstanceStateEvent.destroyed, VmInstanceState.Destroyed),
new Transaction(VmInstanceStateEvent.destroying, VmInstanceState.Destroying),
new Transaction(VmInstanceStateEvent.running, VmInstanceState.Running),
new Transaction(VmInstanceStateEvent.stopped, VmInstanceState.Stopped),
new Transaction(VmInstanceStateEvent.expunging, VmInstanceState.Expunging)
);
Destroyed.transactions(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package org.zstack.header.vm;

/**
* Created by Qi Le on 2019-08-21
* @deprecated Use {@link org.zstack.header.vm.extensions.VmDbDeleteContext} with a single-phase extension point instead.
*/
@Deprecated
Comment on lines 3 to +6
Copy link

@coderabbitai coderabbitai bot Jan 28, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

弃用引用不完整:与 VmJustBeforeDeleteFromDbExtensionPoint 存在相同问题。

同样引用了上下文类 VmDbDeleteContext 而非具体的扩展点接口。建议统一修复,指向明确的替代扩展点接口。

🤖 Prompt for AI Agents
In
`@header/src/main/java/org/zstack/header/vm/VmJustAfterDeleteFromDbExtensionPoint.java`
around lines 3 - 6, The `@deprecated` Javadoc in
VmJustAfterDeleteFromDbExtensionPoint currently links to the context class
VmDbDeleteContext instead of the actual single-phase extension point interface;
update the `@deprecated` tag to point to the concrete replacement extension point
in org.zstack.header.vm.extensions (replace the VmDbDeleteContext reference with
the correct extension-point interface name), and apply the identical change to
VmJustBeforeDeleteFromDbExtensionPoint so both deprecation comments reference
the explicit replacement interface rather than the context class.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Comment from ye.zou:

Acknowledged. Chinese-to-English Javadoc translation and deprecated reference cleanup will be handled in a follow-up pass. Resolving to unblock merge.

Copy link

Choose a reason for hiding this comment

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

@zstack-robot-1 Understood. I've noted that the deprecation reference cleanup for both VmJustAfterDeleteFromDbExtensionPoint and VmJustBeforeDeleteFromDbExtensionPoint will be addressed in a follow-up pass. Thank you for acknowledging the concern.

public interface VmJustAfterDeleteFromDbExtensionPoint {
void vmJustAfterDeleteFromDbExtensionPoint(VmInstanceInventory inv, String accountUuid);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package org.zstack.header.vm;

/**
* Created by xing5 on 2017/6/26.
* @deprecated Use {@link org.zstack.header.vm.extensions.VmDbDeleteContext} with a single-phase extension point instead.
*/
@Deprecated
public interface VmJustBeforeDeleteFromDbExtensionPoint {
void vmJustBeforeDeleteFromDb(VmInstanceInventory inv);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import org.zstack.header.network.l3.L3NetworkInventory;

/**
* Created by xing5 on 2016/4/18.
* @deprecated Use {@link org.zstack.header.vm.extensions.VmInstanceAttachL3NetworkExtensionPoint#preAttachL3Network} instead.
*/
@Deprecated
public interface VmPreAttachL3NetworkExtensionPoint {
void vmPreAttachL3Network(VmInstanceInventory vm, L3NetworkInventory l3);
}
Loading