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
8 changes: 7 additions & 1 deletion conf/i18n/globalErrorCodeMapping/global-error-en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -4734,5 +4734,11 @@
"ORG_ZSTACK_AI_10162": "VM[name:%s, uuid:%s] must be running to mount/unmount model. Current state: %s",
"ORG_ZSTACK_AI_10163": "VM[name:%s, uuid:%s] is not running on any host",
"ORG_ZSTACK_AI_10164": "Model[name:%s, uuid:%s] is not shared to the account that owns this VM (or to public). Mount requires the model to be accessible under the same sharing rules as the VM.",
"ORG_ZSTACK_AI_10165": "ModelCenter[uuid:%s] not found for Model[name:%s, uuid:%s]"
"ORG_ZSTACK_AI_10165": "ModelCenter[uuid:%s] not found for Model[name:%s, uuid:%s]",
"ORG_ZSTACK_NETWORK_ZNS_10043": "failed to allocate DHCPv4 server IP for ZNS L3[uuid:%s]",
"ORG_ZSTACK_NETWORK_ZNS_10044": "cannot enable DHCP: L3[uuid:%s] has no eligible IpRange (SLAAC excluded)",
"ORG_ZSTACK_NETWORK_ZNS_10045": "cannot enable DHCP: L3[uuid:%s] has no Cloud-reserved DHCPv4 server IP",
"ORG_ZSTACK_NETWORK_ZNS_10046": "DHCP service already exists on segment[uuid:%s] but GET returned empty",
"ORG_ZSTACK_NETWORK_ZNS_10047": "cannot update DHCP: L3[uuid:%s] has no Cloud-reserved DHCPv4 server IP",
"ORG_ZSTACK_NETWORK_ZNS_10048": "failed to allocate DHCPv4 server IP for ZNS L3[uuid:%s]"
}
8 changes: 7 additions & 1 deletion conf/i18n/globalErrorCodeMapping/global-error-zh_CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -4741,5 +4741,11 @@
"ORG_ZSTACK_AI_10162": "虚拟机「%s」(UUID: %s) 必须处于运行状态才能挂载/卸载模型,当前状态: %s",
"ORG_ZSTACK_AI_10163": "虚拟机「%s」(UUID: %s) 未运行在任何主机上",
"ORG_ZSTACK_AI_10164": "模型「%s」(UUID: %s) 与该虚拟机所属账户的共享规则不匹配,无法挂载。\n请确认模型已共享给该账户或设为公开。",
"ORG_ZSTACK_AI_10165": "模型中心 (UUID: %s) 未找到(关联模型: 「%s」UUID: %s)。\n请检查模型中心是否已被删除。"
"ORG_ZSTACK_AI_10165": "模型中心 (UUID: %s) 未找到(关联模型: 「%s」UUID: %s)。\n请检查模型中心是否已被删除。",
"ORG_ZSTACK_NETWORK_ZNS_10043": "为 ZNS 三层网络[uuid:%s]分配 DHCPv4 服务 IP 失败",
"ORG_ZSTACK_NETWORK_ZNS_10044": "无法启用 DHCP:三层网络[uuid:%s]没有可用的 IP 范围(不包含 SLAAC)",
"ORG_ZSTACK_NETWORK_ZNS_10045": "无法启用 DHCP:三层网络[uuid:%s]没有云端预留的 DHCPv4 服务 IP",
"ORG_ZSTACK_NETWORK_ZNS_10046": "网段[uuid:%s]上已存在 DHCP 服务,但 GET 返回为空",
"ORG_ZSTACK_NETWORK_ZNS_10047": "无法更新 DHCP:三层网络[uuid:%s]没有云端预留的 DHCPv4 服务 IP",
"ORG_ZSTACK_NETWORK_ZNS_10048": "为 ZNS 三层网络[uuid:%s]分配 DHCPv4 服务 IP 失败"
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.zstack.header.network.l3.L3NetworkConstant;
import org.zstack.header.network.l3.L3NetworkMessage;
import org.zstack.header.network.l3.L3NetworkVO;
import org.zstack.header.rest.APINoSee;
import org.zstack.header.rest.RestRequest;

import java.util.*;
Expand Down Expand Up @@ -66,6 +67,8 @@ public class APIAttachNetworkServiceToL3NetworkMsg extends APIMessage implements
*/
@APIParam
private Map<String, List<String>> networkServices;
@APINoSee
private transient boolean skipAttach;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Comment from shixin.ruan:

是不是应该加@APINoSee

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Comment from shixin.ruan:

fixed in 3a61b56.\n\nDefect class: API surface hygiene.\nBefore: skipAttach was transient but still had no explicit API hiding annotation.\nAfter: added @APINoSee to skipAttach so this internal control flag is hidden from REST/API field exposure.\nValidation: mvn -pl header,network -DskipTests install passed.


@Override
public String getL3NetworkUuid() {
Expand All @@ -83,6 +86,14 @@ public void setNetworkServices(Map<String, List<String>> networkServices) {
public void setL3NetworkUuid(String l3NetworkUuid) {
this.l3NetworkUuid = l3NetworkUuid;
}

public boolean isSkipAttach() {
return skipAttach;
}

public void setSkipAttach(boolean skipAttach) {
this.skipAttach = skipAttach;
}

public static APIAttachNetworkServiceToL3NetworkMsg __example__() {
APIAttachNetworkServiceToL3NetworkMsg msg = new APIAttachNetworkServiceToL3NetworkMsg();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.zstack.header.network.service;

public interface NetworkServiceAttachExtensionPoint {
boolean skipAttachNetworkService(APIAttachNetworkServiceToL3NetworkMsg msg);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class NetworkServiceProviderType {
private final String typeName;
private boolean createDhcpNameSpace = true;
private boolean allocateDhcpServerIp = true;
private boolean allocateDhcpv6ServerIp = true;

public NetworkServiceProviderType(String typeName) {
this.typeName = typeName;
Expand Down Expand Up @@ -55,6 +56,14 @@ public void setAllocateDhcpServerIp(boolean allocateDhcpServerIp) {
this.allocateDhcpServerIp = allocateDhcpServerIp;
}

public boolean isAllocateDhcpv6ServerIp() {
return allocateDhcpv6ServerIp;
}

public void setAllocateDhcpv6ServerIp(boolean allocateDhcpv6ServerIp) {
this.allocateDhcpv6ServerIp = allocateDhcpv6ServerIp;
}

@Override
public int hashCode() {
return typeName.hashCode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1560,6 +1560,13 @@ public void fail(ErrorCode errorCode) {

private void handle(APIAttachNetworkServiceToL3NetworkMsg msg) {
APIAttachNetworkServiceToL3NetworkEvent evt = new APIAttachNetworkServiceToL3NetworkEvent(msg.getId());
if (msg.isSkipAttach()) {
self = dbf.reload(self);
evt.setInventory(L3NetworkInventory.valueOf(self));
bus.publish(evt);
return;
}

AttachNetworkServiceToL3Msg amsg = new AttachNetworkServiceToL3Msg();
amsg.setL3NetworkUuid(msg.getL3NetworkUuid());
amsg.setNetworkServices(msg.getNetworkServices());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ public void enableNetworkService(L3NetworkVO l3VO, NetworkServiceProviderType pr
SdnControllerEnableDHCPMsg msg = new SdnControllerEnableDHCPMsg();
msg.setL3NetworkUuid(l3VO.getUuid());
msg.setSdnControllerUuid(sdnControllerUuid);
msg.setSystemTags(systemTags);
bus.makeTargetServiceIdByResourceUuid(msg, SdnControllerConstant.SERVICE_ID, sdnControllerUuid);
bus.send(msg, new CloudBusCallBack(completion) {
@Override
Expand Down
12 changes: 10 additions & 2 deletions network/src/main/java/org/zstack/network/service/MtuGetter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.core.Platform;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.Q;
import org.zstack.header.network.l2.*;
Expand All @@ -28,6 +29,13 @@ public class MtuGetter {
@Autowired
private PluginRegistry pluginRgty;

private PluginRegistry getPluginRegistry() {
if (pluginRgty == null) {
pluginRgty = Platform.getComponentLoader().getComponent(PluginRegistry.class);
}
return pluginRgty;
}

public Integer getMtu(String l3NetworkUuid) {
String l2NetworkUuid = Q.New(L3NetworkVO.class).select(L3NetworkVO_.l2NetworkUuid).eq(L3NetworkVO_.uuid, l3NetworkUuid).findValue();

Expand All @@ -43,7 +51,7 @@ public Integer getMtu(String l3NetworkUuid) {
}

L2NetworkVO l2VO = Q.New(L2NetworkVO.class).eq(L2NetworkVO_.uuid, l2NetworkUuid).find();
for (L2NetworkDefaultMtu e : pluginRgty.getExtensionList(L2NetworkDefaultMtu.class)) {
for (L2NetworkDefaultMtu e : getPluginRegistry().getExtensionList(L2NetworkDefaultMtu.class)) {
if (l2VO.getType().equals(e.getL2NetworkType())) {
mtu = e.getDefaultMtu(L2NetworkInventory.valueOf(l2VO));
}
Expand Down Expand Up @@ -82,7 +90,7 @@ public Integer getL2Mtu(L2NetworkInventory l2Inv) {
}

/* compare to default mtu */
for (L2NetworkDefaultMtu e : pluginRgty.getExtensionList(L2NetworkDefaultMtu.class)) {
for (L2NetworkDefaultMtu e : getPluginRegistry().getExtensionList(L2NetworkDefaultMtu.class)) {
if (l2Inv.getType().equals(e.getL2NetworkType())) {
Integer l2mtu = e.getDefaultMtu(l2Inv);
if (mtu == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.zstack.network.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SimpleQuery;
import org.zstack.core.db.SimpleQuery.Op;
Expand Down Expand Up @@ -29,16 +30,22 @@

/**
*/
public class NetworkServiceApiInterceptor implements ApiMessageInterceptor {
private final static CLogger logger = Utils.getLogger(NetworkServiceApiInterceptor.class);
@Autowired
public class NetworkServiceApiInterceptor implements ApiMessageInterceptor {
private final static CLogger logger = Utils.getLogger(NetworkServiceApiInterceptor.class);
@Autowired
private DatabaseFacade dbf;
@Autowired
private PluginRegistry pluginRgty;

@Override
public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionException {
if (msg instanceof APIAttachNetworkServiceToL3NetworkMsg) {
APIAttachNetworkServiceToL3NetworkMsg attachMsg = (APIAttachNetworkServiceToL3NetworkMsg)msg;
attachMsg.setNetworkServices(convertNetworkProviderTypeToUuid(attachMsg.getNetworkServices()));
if (skipAttachNetworkService(attachMsg)) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
attachMsg.setSkipAttach(true);
return msg;
}
validate(attachMsg);
} else if (msg instanceof APIDetachNetworkServiceFromL3NetworkMsg) {
APIDetachNetworkServiceFromL3NetworkMsg detachMsg = (APIDetachNetworkServiceFromL3NetworkMsg)msg;
Expand All @@ -59,6 +66,15 @@ public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionExcepti
return msg;
}

private boolean skipAttachNetworkService(APIAttachNetworkServiceToL3NetworkMsg msg) {
for (NetworkServiceAttachExtensionPoint ext : pluginRgty.getExtensionList(NetworkServiceAttachExtensionPoint.class)) {
if (ext.skipAttachNetworkService(msg)) {
return true;
}
}
return false;
}

private void validate(APIAttachNetworkServiceToL3NetworkMsg msg) {
if (msg.getNetworkServices().isEmpty()) {
throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SERVICE_10006, "networkServices cannot be empty"));
Expand Down Expand Up @@ -157,11 +173,11 @@ public String call(String type) {
}

private Map<String, List<String>> convertNetworkProviderTypeToUuid(Map<String, List<String>> map){
if (map.isEmpty()) {
Map<String, List<String>> mapNew = normalizeNetworkServices(map);
if (mapNew.isEmpty()) {
throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SERVICE_10012, "networkServices cannot be empty"));
}

Map<String, List<String>> mapNew = new HashMap<>(map);
List<NetworkServiceProviderVO> networkServiceProviderVOs = Q.New(NetworkServiceProviderVO.class).list();

for (NetworkServiceProviderVO vo :networkServiceProviderVOs) {
Expand All @@ -172,4 +188,39 @@ private Map<String, List<String>> convertNetworkProviderTypeToUuid(Map<String, L

return mapNew;
}

private Map<String, List<String>> normalizeNetworkServices(Map<String, List<String>> map) {
Map<String, List<String>> ret = new LinkedHashMap<>();
if (map == null) {
return ret;
}

for (Map.Entry<String, List<String>> entry : map.entrySet()) {
if (entry.getKey() == null) {
continue;
}

String provider = entry.getKey().trim();
if (provider.isEmpty()) {
continue;
}

List<String> services = new ArrayList<>();
if (entry.getValue() != null) {
for (String service : entry.getValue()) {
if (service == null) {
continue;
}

String normalized = service.trim();
if (!normalized.isEmpty()) {
services.add(normalized);
}
}
}

ret.computeIfAbsent(provider, k -> new ArrayList<>()).addAll(services);
}
return ret;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ public static Map<String, String> getExistingDhcpServerIp(String l3Uuid, int ipV

@Deferred
private String allocateDhcpIp(String l3Uuid, int ipVersion, boolean allocate_ip, String requiredIp, String excludedIp) {
if (!isAllocateDhcpServerIp(l3Uuid)) {
if (!isAllocateDhcpServerIp(l3Uuid, ipVersion)) {
return null;
Comment on lines 997 to 1000
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 | 🏗️ Heavy lift

不要用 null 静默表示“不支持 DHCPv6 分配”。

这里把“不支持当前 IP 版本分配”折叠成 null 返回后,afterAddIpRange()FlatDhcpAcquireDhcpServerIpMsg 等现有调用方不会把它当成错误处理。这样一来,非 SLAAC 的 IPv6 range 可能成功走完整个流程,但 DHCPv6 server IP/tag 根本没有落下来,L3 会进入部分配置状态。建议把 capability 不支持与普通分配失败区分开,并在 attach / add-range 这类入口上显式报错。

🤖 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
`@plugin/flatNetworkProvider/src/main/java/org/zstack/network/service/flat/FlatDhcpBackend.java`
around lines 997 - 1000, The method allocateDhcpIp currently returns null when
isAllocateDhcpServerIp(l3Uuid, ipVersion) is false which silently treats
“capability not supported” as a normal allocation failure; change this to
fail-fast by throwing a clear exception (e.g., an
OperationFailureException/CloudRuntimeException) when DHCP server IP allocation
is not supported for the given l3Uuid/ipVersion so callers like
afterAddIpRange() and FlatDhcpAcquireDhcpServerIpMsg will treat it as an
explicit error; keep isAllocateDhcpServerIp check but replace the null return
with a descriptive exception message stating DHCPv6 allocation is unsupported
for that L3 and IP version.

}

Expand Down Expand Up @@ -1276,6 +1276,17 @@ private boolean isAllocateDhcpServerIp(String l3Uuid) {
return type.isAllocateDhcpServerIp();
}

private boolean isAllocateDhcpServerIp(String l3Uuid, int ipVersion) {
String providerType = new NetworkProviderFinder().getNetworkProviderTypeByNetworkServiceType(l3Uuid, NetworkServiceType.DHCP.toString());
if (providerType == null) {
return false;
}

NetworkServiceProviderType type = NetworkServiceProviderType.valueOf(providerType);
return type.isAllocateDhcpServerIp()
&& (ipVersion != IPv6Constants.IPv6 || type.isAllocateDhcpv6ServerIp());
}

private boolean isCreateDhcpNameSpace(String l3Uuid) {
String providerType = new NetworkProviderFinder().getNetworkProviderTypeByNetworkServiceType(l3Uuid, NetworkServiceType.DHCP.toString());
if (providerType == null) {
Expand Down Expand Up @@ -2490,7 +2501,10 @@ private void validate(APIDetachNetworkServiceFromL3NetworkMsg msg) {
}

private void validate(APIChangeL3NetworkDhcpIpAddressMsg msg) {
if (!isAllocateDhcpServerIp(msg.getL3NetworkUuid())) {
if ((msg.getDhcpServerIp() != null && !isAllocateDhcpServerIp(msg.getL3NetworkUuid(), IPv6Constants.IPv4))
|| (msg.getDhcpv6ServerIp() != null && !isAllocateDhcpServerIp(msg.getL3NetworkUuid(), IPv6Constants.IPv6))
|| (msg.getDhcpServerIp() == null && msg.getDhcpv6ServerIp() == null
&& !isAllocateDhcpServerIp(msg.getL3NetworkUuid()))) {
throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_NETWORK_SERVICE_FLAT_10044, "could change dhcp server ip, because flat dhcp is not enabled"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12124,6 +12124,12 @@ public class CloudOperationsErrorCode {
// 10040 ZNS did not return Cloud allocated IP version
// 10041 VM NIC MAC update is not supported for ZNS NICs
// 10042 L3Network not found while enabling ZNS DHCP
// 10043 failed to allocate DHCPv4 server IP in ZNS DHCP helper
// 10044 ZNS DHCP enable has no eligible IpRange
// 10045 ZNS DHCP enable has no Cloud-reserved DHCPv4 server IP
// 10046 ZNS DHCP 409 fallback GET returned empty
// 10047 ZNS DHCP update has no Cloud-reserved DHCPv4 server IP
// 10048 failed to allocate DHCPv4 server IP in ZNS DHCP backend
public static final String ORG_ZSTACK_NETWORK_ZNS_10035 = "ORG_ZSTACK_NETWORK_ZNS_10035";
public static final String ORG_ZSTACK_NETWORK_ZNS_10036 = "ORG_ZSTACK_NETWORK_ZNS_10036";
public static final String ORG_ZSTACK_NETWORK_ZNS_10037 = "ORG_ZSTACK_NETWORK_ZNS_10037";
Expand All @@ -12132,6 +12138,12 @@ public class CloudOperationsErrorCode {
public static final String ORG_ZSTACK_NETWORK_ZNS_10040 = "ORG_ZSTACK_NETWORK_ZNS_10040";
public static final String ORG_ZSTACK_NETWORK_ZNS_10041 = "ORG_ZSTACK_NETWORK_ZNS_10041";
public static final String ORG_ZSTACK_NETWORK_ZNS_10042 = "ORG_ZSTACK_NETWORK_ZNS_10042";
public static final String ORG_ZSTACK_NETWORK_ZNS_10043 = "ORG_ZSTACK_NETWORK_ZNS_10043";
public static final String ORG_ZSTACK_NETWORK_ZNS_10044 = "ORG_ZSTACK_NETWORK_ZNS_10044";
public static final String ORG_ZSTACK_NETWORK_ZNS_10045 = "ORG_ZSTACK_NETWORK_ZNS_10045";
public static final String ORG_ZSTACK_NETWORK_ZNS_10046 = "ORG_ZSTACK_NETWORK_ZNS_10046";
public static final String ORG_ZSTACK_NETWORK_ZNS_10047 = "ORG_ZSTACK_NETWORK_ZNS_10047";
public static final String ORG_ZSTACK_NETWORK_ZNS_10048 = "ORG_ZSTACK_NETWORK_ZNS_10048";

public static final String ORG_ZSTACK_PREMIUM_EXTERNALSERVICE_MARKETPLACE_10000 = "ORG_ZSTACK_PREMIUM_EXTERNALSERVICE_MARKETPLACE_10000";

Expand Down