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
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 @@ -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();
}
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
Expand Up @@ -1075,6 +1075,13 @@ private void handle(APIGetFreeIpMsg msg) {
}
limit -= freeIpInventorys.size();
}

Set<ReservedIpRangeVO> reservedIpRanges = self.getReservedIpRanges();
if (reservedIpRanges != null && !reservedIpRanges.isEmpty()) {
freeIpInventorys.removeIf(freeIp -> reservedIpRanges.stream().anyMatch(
r -> NetworkUtils.isInRange(freeIp.getIp(), r.getStartIp(), r.getEndIp())));
}
Comment on lines +1078 to +1083
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

IP 版本不匹配可能导致异常

当前代码在比较 free IP 与 reserved IP range 时,未按 IP 版本过滤。若 free IP 是 IPv4 而 reserved range 是 IPv6(或相反),NetworkUtils.isInRange 内部会调用错误的转换方法(如 ipv4StringToLong 处理 IPv6 地址),可能抛出异常。

参考同文件第 486-487 行的已有模式,应先按 IP 版本过滤 reserved ranges:

🔧 建议修复
         Set<ReservedIpRangeVO> reservedIpRanges = self.getReservedIpRanges();
         if (reservedIpRanges != null && !reservedIpRanges.isEmpty()) {
-            freeIpInventorys.removeIf(freeIp -> reservedIpRanges.stream().anyMatch(
-                    r -> NetworkUtils.isInRange(freeIp.getIp(), r.getStartIp(), r.getEndIp())));
+            freeIpInventorys.removeIf(freeIp -> reservedIpRanges.stream()
+                    .filter(r -> r.getIpVersion() == freeIp.getIpVersion())
+                    .anyMatch(r -> NetworkUtils.isInRange(freeIp.getIp(), r.getStartIp(), r.getEndIp())));
         }
🤖 Prompt for AI Agents
In `@network/src/main/java/org/zstack/network/l3/L3BasicNetwork.java` around lines
1078 - 1083, The removal logic may call NetworkUtils.isInRange with mismatched
IP versions (IPv4 vs IPv6) causing exceptions; update the block that iterates
self.getReservedIpRanges() and freeIpInventorys (the lambda using freeIp and
reservedIpRanges.stream) to first filter reserved ranges by the same IP version
as freeIp (use whatever helper/method the file uses elsewhere for version
checking, consistent with the pattern around lines ~486-487), then call
NetworkUtils.isInRange only for ranges with matching versions so ipv4/ipv6
conversions are not mixed and exceptions are avoided.


reply.setInventories(freeIpInventorys);

bus.reply(msg, reply);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5446,7 +5446,7 @@ private void deleteSnapshotOnPrimaryStorage(final DeleteSnapshotOnPrimaryStorage
httpCall(DELETE_SNAPSHOT_PATH, cmd, DeleteSnapshotRsp.class, new ReturnValueCompletion<DeleteSnapshotRsp>(msg) {
@Override
public void success(DeleteSnapshotRsp returnValue) {
osdHelper.releaseAvailableCapacity(msg.getSnapshot().getPrimaryStorageInstallPath(), msg.getSnapshot().getSize());
osdHelper.releaseAvailableCapWithRatio(msg.getSnapshot().getPrimaryStorageInstallPath(), msg.getSnapshot().getSize());
bus.reply(msg, reply);
completion.done();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,10 +682,34 @@ public void fail(ErrorCode errorCode) {
private void handle(APICreatePortForwardingRuleMsg msg) {
final APICreatePortForwardingRuleEvent evt = new APICreatePortForwardingRuleEvent(msg.getId());

int vipPortEnd = msg.getVipPortEnd() == null ? msg.getVipPortStart() : msg.getVipPortEnd();
int privatePortEnd = msg.getPrivatePortEnd() == null ? msg.getPrivatePortStart() : msg.getPrivatePortEnd();
thdf.chainSubmit(new ChainTask(msg) {
@Override
public String getSyncSignature() {
return String.format("portforwardingrule-vip-%s", msg.getVipUuid());
}

VipVO vip = dbf.findByUuid(msg.getVipUuid(), VipVO.class);
@Override
public void run(SyncTaskChain chain) {
int vipPortEnd = msg.getVipPortEnd() == null ? msg.getVipPortStart() : msg.getVipPortEnd();
int privatePortEnd = msg.getPrivatePortEnd() == null ? msg.getPrivatePortStart() : msg.getPrivatePortEnd();

// re-check VIP port overlap under sync to prevent concurrent duplicate rules
boolean overlap = Q.New(PortForwardingRuleVO.class)
.eq(PortForwardingRuleVO_.vipUuid, msg.getVipUuid())
.eq(PortForwardingRuleVO_.protocolType, PortForwardingProtocolType.valueOf(msg.getProtocolType()))
.lte(PortForwardingRuleVO_.vipPortStart, vipPortEnd)
.gte(PortForwardingRuleVO_.vipPortEnd, msg.getVipPortStart())
.isExists();
if (overlap) {
evt.setError(operr(ORG_ZSTACK_NETWORK_SERVICE_PORTFORWARDING_10017,
"vip port range[vipStartPort:%s, vipEndPort:%s] overlaps with an existing port forwarding rule on vip[uuid:%s]",
msg.getVipPortStart(), vipPortEnd, msg.getVipUuid()));
bus.publish(evt);
chain.next();
return;
}

VipVO vip = dbf.findByUuid(msg.getVipUuid(), VipVO.class);
final PortForwardingRuleVO vo = new PortForwardingRuleVO();
if (msg.getResourceUuid() != null) {
vo.setUuid(msg.getResourceUuid());
Expand Down Expand Up @@ -713,8 +737,8 @@ protected void scripts() {
}
}.execute();

FlowChain chain = FlowChainBuilder.newShareFlowChain();
chain.setName("create-portforwading");
FlowChain flowChain = FlowChainBuilder.newShareFlowChain();
flowChain.setName("create-portforwading");
Comment on lines +740 to +741
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

FlowChain 名称存在拼写错误。

"create-portforwading" 应为 "create-portforwarding"(缺少字母 'r')。

🐛 建议修复
 FlowChain flowChain = FlowChainBuilder.newShareFlowChain();
-flowChain.setName("create-portforwading");
+flowChain.setName("create-portforwarding");
📝 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.

Suggested change
FlowChain flowChain = FlowChainBuilder.newShareFlowChain();
flowChain.setName("create-portforwading");
FlowChain flowChain = FlowChainBuilder.newShareFlowChain();
flowChain.setName("create-portforwarding");
🤖 Prompt for AI Agents
In
`@plugin/portForwarding/src/main/java/org/zstack/network/service/portforwarding/PortForwardingManagerImpl.java`
around lines 740 - 741, The FlowChain name in PortForwardingManagerImpl is
misspelled as "create-portforwading"; update the string passed to
flowChain.setName(...) (the FlowChain created via
FlowChainBuilder.newShareFlowChain() and stored in variable flowChain) to the
correct spelling "create-portforwarding" so the chain name is accurate.

VipInventory vipInventory = VipInventory.valueOf(vip);
if (msg.getVmNicUuid() == null) {
ModifyVipAttributesStruct struct = new ModifyVipAttributesStruct();
Expand All @@ -727,13 +751,15 @@ protected void scripts() {
public void success() {
evt.setInventory(PortForwardingRuleInventory.valueOf(vo));
bus.publish(evt);
chain.next();
}

@Override
public void fail(ErrorCode errorCode) {
dbf.remove(vo);
evt.setError(errorCode);
bus.publish(evt);
chain.next();
}
});

Expand All @@ -757,20 +783,22 @@ public void fail(ErrorCode errorCode) {
public void success() {
evt.setInventory(PortForwardingRuleInventory.valueOf(vo));
bus.publish(evt);
chain.next();
}

@Override
public void fail(ErrorCode errorCode) {
dbf.remove(vo);
evt.setError(errorCode);
bus.publish(evt);
chain.next();
}
});

return;
}

chain.then(new ShareFlow() {
flowChain.then(new ShareFlow() {
@Override
public void setup() {
vo.setVmNicUuid(vmNic.getUuid());
Expand Down Expand Up @@ -853,20 +881,29 @@ public void fail(ErrorCode errorCode) {
});


chain.done(new FlowDoneHandler(msg) {
flowChain.done(new FlowDoneHandler(msg) {
@Override
public void handle(Map data) {
evt.setInventory(PortForwardingRuleInventory.valueOf(dbf.reload(vo)));
bus.publish(evt);
chain.next();
}
}).error(new FlowErrorHandler(msg) {
@Override
public void handle(ErrorCode errCode, Map data) {
dbf.remove(vo);
evt.setError(errCode);
bus.publish(evt);
chain.next();
}
}).start();
}

@Override
public String getName() {
return String.format("api-create-portforwardingrule-vip-%s", msg.getVipUuid());
}
});
}

private void populateExtensions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,10 @@ public List<ActiveVolumeClient> getActiveClients(String installPath, String prot
if (VolumeProtocol.CBD.toString().equals(protocol)) {
GetVolumeClientsCmd cmd = new GetVolumeClientsCmd();
cmd.setPath(installPath);
GetVolumeClientsRsp rsp = syncHttpCall(GET_VOLUME_CLIENTS_PATH, cmd, GetVolumeClientsRsp.class);
GetVolumeClientsRsp rsp = new HttpCaller<>(GET_VOLUME_CLIENTS_PATH, cmd, GetVolumeClientsRsp.class,
null, TimeUnit.SECONDS, 30, true)
.setTryNext(true)
.syncCall();
List<ActiveVolumeClient> clients = new ArrayList<>();

if (!rsp.isSuccess()) {
Expand Down Expand Up @@ -1411,6 +1414,11 @@ public class HttpCaller<T extends AgentResponse> {

private boolean tryNext = false;

HttpCaller<T> setTryNext(boolean tryNext) {
this.tryNext = tryNext;
return this;
}

public HttpCaller(String path, AgentCommand cmd, Class<T> retClass, ReturnValueCompletion<T> callback) {
this(path, cmd, retClass, callback, null, 0, false);
}
Expand Down