From 498b69b610da7f928c150e8a08bc4d4ea0e4fe69 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Wed, 3 Jun 2026 22:53:01 +0530 Subject: [PATCH 1/3] persist and expose effective network rate for NIC, Network and compute offering --- .../apache/cloudstack/api/ApiConstants.java | 1 + .../api/response/NetworkResponse.java | 12 +++++++++++ .../cloudstack/api/response/NicResponse.java | 12 +++++++++++ .../orchestration/NetworkOrchestrator.java | 7 +++++++ .../main/java/com/cloud/api/ApiDBUtils.java | 10 +++++++++ .../java/com/cloud/api/ApiResponseHelper.java | 11 ++++++++++ .../api/query/dao/UserVmJoinDaoImpl.java | 10 +++++++++ .../com/cloud/network/NetworkServiceImpl.java | 3 +++ .../java/com/cloud/vm/UserVmManagerImpl.java | 21 ++++++++++++++++++- ui/src/config/section/network.js | 2 +- ui/src/config/section/offering.js | 4 ++-- ui/src/views/network/NicsTable.vue | 3 +++ 12 files changed, 92 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 694830ea2f36..29064df8af88 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -1190,6 +1190,7 @@ public class ApiConstants { public static final String NETSCALER_CONTROLCENTER_ID = "netscalercontrolcenterid"; public static final String NETSCALER_SERVICEPACKAGE_ID = "netscalerservicepackageid"; public static final String FETCH_ROUTER_HEALTH_CHECK_RESULTS = "fetchhealthcheckresults"; + public static final String UNLIMITED = "unlimited"; public static final String ZONE_ID_LIST = "zoneids"; public static final String DESTINATION_ZONE_ID_LIST = "destzoneids"; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index 3a3663af2551..bc72dda0e068 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java @@ -311,6 +311,10 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement @Param(description = "MTU configured on the network VR's private interfaces") private Integer privateMtu; + @SerializedName(ApiConstants.NETWORKRATE) + @Param(description = "Network rate (in Mb/s) configured for the Guest interface of this network", since = "4.24.0") + private String networkRate; + @SerializedName(ApiConstants.IP6_DNS1) @Param(description = "The first IPv6 DNS for the network", since = "4.18.0") private String ipv6Dns1; @@ -699,6 +703,14 @@ public void setPrivateMtu(Integer privateMtu) { this.privateMtu = privateMtu; } + public String getNetworkRate() { + return networkRate; + } + + public void setNetworkRate(String networkRate) { + this.networkRate = networkRate; + } + public void setIpv6Dns1(String ipv6Dns1) { this.ipv6Dns1 = ipv6Dns1; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java index 92f25e370fb4..fcbb6ac17d11 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java @@ -138,6 +138,10 @@ public class NicResponse extends BaseResponse { @Param(description = "MTU configured on the NIC", since="4.18.0") private Integer mtu; + @SerializedName(ApiConstants.NETWORKRATE) + @Param(description = "Network rate (in Mb/s) configured for the NIC", since = "4.24.0") + private String networkRate; + @SerializedName(ApiConstants.PUBLIC_IP_ID) @Param(description = "Public IP address ID associated with this NIC via Static NAT rule") private String publicIpId; @@ -409,6 +413,14 @@ public void setMtu(Integer mtu) { this.mtu = mtu; } + public String getNetworkRate() { + return networkRate; + } + + public void setNetworkRate(String networkRate) { + this.networkRate = networkRate; + } + public String getVpcId() { return vpcId; } diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 4262ee701aab..9b99f8a4a0d9 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -744,6 +744,12 @@ private void updateRouterIpInNetworkDetails(Long networkId, String routerIp, Str } } + private void saveNetworkRateInDetails(long networkId, NetworkOffering offering, long dataCenterId) { + Integer rate = _configMgr.getNetworkOfferingNetworkRate(offering.getId(), dataCenterId); + String networkRate = (rate == null || rate <= 0) ? ApiConstants.UNLIMITED : String.valueOf(rate); + networkDetailsDao.addDetail(networkId, ApiConstants.NETWORKRATE, networkRate, true); + } + @Override public List setupNetwork(final Account owner, final NetworkOffering offering, final DeploymentPlan plan, final String name, final String displayText, final boolean isDefault) throws ConcurrentOperationException { @@ -819,6 +825,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } updateRouterIpInNetworkDetails(networkPersisted.getId(), network.getRouterIp(), network.getRouterIpv6()); + saveNetworkRateInDetails(networkPersisted.getId(), offering, plan.getDataCenterId()); if (predefined instanceof NetworkVO && guru instanceof NetworkGuruAdditionalFunctions) { final NetworkGuruAdditionalFunctions functions = (NetworkGuruAdditionalFunctions) guru; diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java index 1d00e9ec16ba..4a40fcd42067 100644 --- a/server/src/main/java/com/cloud/api/ApiDBUtils.java +++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java @@ -338,6 +338,7 @@ import com.cloud.vm.DomainRouterVO; import com.cloud.vm.InstanceGroup; import com.cloud.vm.InstanceGroupVO; +import com.cloud.vm.NicDetailVO; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.VMInstanceDetailVO; @@ -351,6 +352,7 @@ import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicDetailsDao; import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; @@ -496,6 +498,7 @@ public class ApiDBUtils { static BackupOfferingDao s_backupOfferingDao; static BackupRepositoryDao s_backupRepositoryDao; static NicDao s_nicDao; + static NicDetailsDao s_nicDetailsDao; static ResourceManagerUtil s_resourceManagerUtil; static ApiKeyPairDao s_apiKeyPairDao; static SnapshotPolicyDetailsDao s_snapshotPolicyDetailsDao; @@ -760,6 +763,8 @@ public class ApiDBUtils { @Inject private NicDao nicDao; @Inject + private NicDetailsDao nicDetailsDao; + @Inject private ResourceIconDao resourceIconDao; @Inject private ResourceManagerUtil resourceManagerUtil; @@ -890,6 +895,7 @@ void init() { s_clusterDetailsDao = clusterDetailsDao; s_vmSnapshotDao = vmSnapshotDao; s_nicDao = nicDao; + s_nicDetailsDao = nicDetailsDao; s_nicSecondaryIpDao = nicSecondaryIpDao; s_vpcProvSvc = vpcProvSvc; s_affinityGroupDao = affinityGroupDao; @@ -2232,6 +2238,10 @@ public static NicVO findNicById(long nicId) { return s_nicDao.findById(nicId); } + public static NicDetailVO findNicDetailByName(long nicId, String detailName) { + return s_nicDetailsDao.findDetail(nicId, detailName); + } + public static TemplateResponse newTemplateUpdateResponse(TemplateJoinVO vr) { return s_templateJoinDao.newUpdateResponse(vr); } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index a8551b4c6693..4d8784d2dd26 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -454,6 +454,7 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; +import com.cloud.vm.NicDetailVO; import com.cloud.vm.dao.NicExtraDhcpOptionDao; import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.snapshot.VMSnapshot; @@ -2703,6 +2704,10 @@ public NetworkResponse createNetworkResponse(ResponseView view, Network network) response.setNetworkDomain(network.getNetworkDomain()); response.setPublicMtu(network.getPublicMtu()); response.setPrivateMtu(network.getPrivateMtu()); + NetworkDetailVO networkRateDetail = networkDetailsDao.findDetail(network.getId(), ApiConstants.NETWORKRATE); + if (networkRateDetail != null) { + response.setNetworkRate(networkRateDetail.getValue()); + } response.setDns1(profile.getDns1()); response.setDns2(profile.getDns2()); response.setIpv6Dns1(profile.getIp6Dns1()); @@ -4876,6 +4881,12 @@ public NicResponse createNicResponse(Nic result) { } response.setEnabled(result.isEnabled()); + + NicDetailVO nicRateDetail = ApiDBUtils.findNicDetailByName(result.getId(), ApiConstants.NETWORKRATE); + if (nicRateDetail != null) { + response.setNetworkRate(nicRateDetail.getValue()); + } + return response; } diff --git a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index 72690091e40e..bdb49ad53e79 100644 --- a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -87,6 +87,7 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.net.Dhcp; +import com.cloud.vm.NicDetailVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.VMInstanceDetailVO; import com.cloud.vm.VirtualMachine; @@ -404,6 +405,10 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us .collect(Collectors.toList()); nicResponse.setExtraDhcpOptions(nicExtraDhcpOptionResponses); + NicDetailVO nicNetworkRateDetail = ApiDBUtils.findNicDetailByName(userVm.getNicId(), ApiConstants.NETWORKRATE); + if (nicNetworkRateDetail != null) { + nicResponse.setNetworkRate(nicNetworkRateDetail.getValue()); + } userVmResponse.addNic(nicResponse); } } @@ -660,6 +665,11 @@ public UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVm .map(vo -> new NicExtraDhcpOptionResponse(Dhcp.DhcpOptionCode.valueOfInt(vo.getCode()).getName(), vo.getCode(), vo.getValue())) .collect(Collectors.toList()); nicResponse.setExtraDhcpOptions(nicExtraDhcpOptionResponses); + + NicDetailVO nicNetworkRateDetail = ApiDBUtils.findNicDetailByName(uvo.getNicId(), ApiConstants.NETWORKRATE); + if (nicNetworkRateDetail != null) { + nicResponse.setNetworkRate(nicNetworkRateDetail.getValue()); + } userVmData.addNic(nicResponse); } diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index d18fd043f697..935bd8e83002 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -3604,6 +3604,9 @@ public void doInTransactionWithoutResult(TransactionStatus status) { UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), nicIdString, networkOfferingId, null, isDefault, VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplay()); } + Integer rate = _configMgr.getNetworkOfferingNetworkRate(networkOfferingId, network.getDataCenterId()); + String networkRate = (rate == null || rate <= 0) ? ApiConstants.UNLIMITED : String.valueOf(rate); + _networkDetailsDao.addDetail(networkId, ApiConstants.NETWORKRATE, networkRate, true); } }); } else { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index bb55f570927b..4695a05b8056 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -403,6 +403,7 @@ import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicDetailsDao; import com.cloud.vm.dao.NicExtraDhcpOptionDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @@ -499,6 +500,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir @Inject private NicDao _nicDao; @Inject + private NicDetailsDao nicDetailsDao; + @Inject private RulesManager _rulesMgr; @Inject private LoadBalancingRulesManager _lbMgr; @@ -1532,6 +1535,7 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV saveExtraDhcpOptions(guestNic.getId(), cmd.getDhcpOptionsMap()); _networkMgr.configureExtraDhcpOptions(network, guestNic.getId(), cmd.getDhcpOptionsMap()); cleanUp = false; + saveNetworkRateInDetails(guestNic.getId(), guestNic.getNetworkRate()); } catch (ResourceUnavailableException e) { throw new CloudRuntimeException("Unable to add NIC to " + vmInstance + ": " + e); } catch (InsufficientCapacityException e) { @@ -1552,6 +1556,18 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV return _vmDao.findById(vmInstance.getId()); } + private void saveNetworkRateInDetails(long nicId, Integer rate) { + String networkRate = (rate == null || rate <= 0) ? ApiConstants.UNLIMITED : String.valueOf(rate); + nicDetailsDao.addDetail(nicId, ApiConstants.NETWORKRATE, networkRate, true); + } + + private void refreshNicNetworkRates(long vmId) { + List nics = _nicDao.listByVmId(vmId); + for (NicVO nic : nics) { + saveNetworkRateInDetails(nic.getId(), _networkModel.getNetworkRate(nic.getNetworkId(), vmId)); + } + } + /** * Set NIC as default if VM has no default NIC * @param vmInstance VM instance to be checked @@ -3466,7 +3482,10 @@ public UserVm startVirtualMachine(StartVMCmd cmd) throws ExecutionException, Con additonalParams.put(VirtualMachineProfile.Param.ConsiderLastHost, cmd.getConsiderLastHost().toString()); } - return startVirtualMachine(cmd.getId(), cmd.getPodId(), cmd.getClusterId(), cmd.getHostId(), additonalParams, cmd.getDeploymentPlanner()).first(); + UserVm vm = startVirtualMachine(cmd.getId(), cmd.getPodId(), cmd.getClusterId(), cmd.getHostId(), additonalParams, cmd.getDeploymentPlanner()).first(); + // Refresh nic_details with current network rates — the network offering may have changed since the VM was last running + refreshNicNetworkRates(vm.getId()); + return vm; } @Override diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index 50c2ff4250b0..7fb0a2af76c0 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -49,7 +49,7 @@ export default { return fields }, details: () => { - const fields = ['name', 'id', 'description', 'type', 'traffictype', 'vpcid', 'vlan', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'asnumber', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 'redundantrouter', 'networkdomain', 'egressdefaultpolicy', 'zonename', 'account', 'domainpath', 'associatednetwork', 'associatednetworkid', 'ip4routing', 'ip6firewall', 'ip6routing', 'ip6routes', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'publicmtu', 'privatemtu'] + const fields = ['name', 'id', 'description', 'type', 'traffictype', 'vpcid', 'vlan', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'asnumber', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 'redundantrouter', 'networkdomain', 'egressdefaultpolicy', 'zonename', 'account', 'domainpath', 'associatednetwork', 'associatednetworkid', 'ip4routing', 'ip6firewall', 'ip6routing', 'ip6routes', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'publicmtu', 'privatemtu', 'networkrate'] if (isAdmin()) { const vlanIndex = fields.findIndex(detail => detail === 'vlan') fields.splice(vlanIndex + 1, 0, 'broadcasturi') diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index 9d7b743a70aa..ee9f5d8649c4 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -39,9 +39,9 @@ export default { return params }, filters: ['active', 'inactive'], - columns: ['name', 'displaytext', 'state', 'cpunumber', 'cpuspeed', 'memory', 'gpu', 'domain', 'zone', 'order'], + columns: ['name', 'displaytext', 'state', 'cpunumber', 'cpuspeed', 'memory', 'gpu', 'domain', 'zone', 'order', 'networkrate'], details: () => { - var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'iscustomizediops', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'storageaccessgroups', 'storagetags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness', 'encryptroot', 'purgeresources', 'leaseduration', 'gpucardid', 'gpucardname', 'vgpuprofileid', 'vgpuprofilename', 'gpucount', 'gpudisplay', 'leaseexpiryaction', 'externaldetails'] + var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'iscustomizediops', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'storageaccessgroups', 'storagetags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness', 'encryptroot', 'purgeresources', 'leaseduration', 'gpucardid', 'gpucardname', 'vgpuprofileid', 'vgpuprofilename', 'gpucount', 'gpudisplay', 'leaseexpiryaction', 'externaldetails', 'networkrate'] if (store.getters.apis.createServiceOffering && store.getters.apis.createServiceOffering.params.filter(x => x.name === 'storagepolicy').length > 0) { fields.splice(6, 0, 'vspherestoragepolicy') diff --git a/ui/src/views/network/NicsTable.vue b/ui/src/views/network/NicsTable.vue index 11ba135e39a2..8a036e7b9088 100644 --- a/ui/src/views/network/NicsTable.vue +++ b/ui/src/views/network/NicsTable.vue @@ -57,6 +57,9 @@ {{ record.isolationuri }} + + {{ record.networkrate }} + From adbdec2c511e9bab10c9fd79f42f6a8fda055cd8 Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Fri, 4 Sep 2026 16:25:51 +0530 Subject: [PATCH 2/3] server,engine,api: persist and expose NIC network rate from nics column - Add network_rate column to nics table (schema-42300to42400.sql) - Add DB upgrade path: Upgrade42300to42400 registered in DatabaseUpgradeChecker - Add network_rate field and getter/setter to NicVO - Set network_rate on NicVO in NetworkOrchestrator.allocateNic() where rate is already computed, eliminating secondary per-NIC update calls - Add getNetworkRate() to Nic interface so ApiResponseHelper.createNicResponse can call result.getNetworkRate() without casting or extra DB queries - Add nic_network_rate to user_vm_view and UserVmJoinVO so listVirtualMachines reads rate from the join without extra per-NIC findNicById calls - Update UserVmJoinDaoImpl to use uvo.getNicNetworkRate() directly - Expose network_rate in NicResponse as Integer (null = unlimited) - Refresh NIC rates on VM start via refreshNicNetworkRates in UserVmManagerImpl --- api/src/main/java/com/cloud/vm/Nic.java | 2 + .../cloudstack/api/response/NicResponse.java | 8 +-- .../orchestration/NetworkOrchestrator.java | 3 +- .../cloud/upgrade/DatabaseUpgradeChecker.java | 2 + .../upgrade/dao/Upgrade42300to42400.java | 54 +++++++++++++++++++ .../src/main/java/com/cloud/vm/NicVO.java | 11 ++++ .../META-INF/db/schema-42300to42400.sql | 20 +++++++ .../META-INF/db/views/cloud.user_vm_view.sql | 1 + .../java/com/cloud/api/ApiResponseHelper.java | 6 +-- .../api/query/dao/UserVmJoinDaoImpl.java | 11 +--- .../com/cloud/api/query/vo/UserVmJoinVO.java | 7 +++ .../java/com/cloud/vm/UserVmManagerImpl.java | 13 ++--- 12 files changed, 109 insertions(+), 29 deletions(-) create mode 100644 engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42300to42400.java create mode 100644 engine/schema/src/main/resources/META-INF/db/schema-42300to42400.sql diff --git a/api/src/main/java/com/cloud/vm/Nic.java b/api/src/main/java/com/cloud/vm/Nic.java index 3722e5769c92..08ef5ea82469 100644 --- a/api/src/main/java/com/cloud/vm/Nic.java +++ b/api/src/main/java/com/cloud/vm/Nic.java @@ -168,5 +168,7 @@ public enum ReservationStrategy { Integer getMtu(); + Integer getNetworkRate(); + boolean isEnabled(); } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java index 6613c11ab87d..314d26b2ebfd 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java @@ -139,8 +139,8 @@ public class NicResponse extends BaseResponse { private Integer mtu; @SerializedName(ApiConstants.NETWORKRATE) - @Param(description = "Network rate (in Mb/s) configured for the NIC", since = "4.24.0") - private String networkRate; + @Param(description = "Network rate (in Mb/s) configured for the NIC; absent if unlimited", since = "4.24.0") + private Integer networkRate; @SerializedName(ApiConstants.PUBLIC_IP_ID) @Param(description = "Public IP address ID associated with this NIC via Static NAT rule") @@ -417,11 +417,11 @@ public void setMtu(Integer mtu) { this.mtu = mtu; } - public String getNetworkRate() { + public Integer getNetworkRate() { return networkRate; } - public void setNetworkRate(String networkRate) { + public void setNetworkRate(Integer networkRate) { this.networkRate = networkRate; } diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 95f4f943aae1..982c8ab2097d 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -1234,14 +1234,15 @@ public Pair allocateNic(final NicProfile requested, final N NicVO vo = checkForRaceAndAllocateNic(requested, network, isDefaultNic, deviceId, vm); final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId()); + vo.setNetworkRate(networkRate != null && networkRate > 0 ? networkRate : null); final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); if (vm.getType() == Type.DomainRouter) { Pair networks = getGuestNetworkRouterAndVpcDetails(vm.getId()); setMtuDetailsInVRNic(networks, network, vo); - _nicDao.update(vo.getId(), vo); setMtuInVRNicProfile(networks, network.getTrafficType(), vmNic); } + _nicDao.update(vo.getId(), vo); return new Pair<>(vmNic, Integer.valueOf(deviceId)); } diff --git a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java index c3a982aa70e5..0e40d7b7401c 100644 --- a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -96,6 +96,7 @@ import com.cloud.upgrade.dao.Upgrade420to421; import com.cloud.upgrade.dao.Upgrade421to430; import com.cloud.upgrade.dao.Upgrade42210to42300; +import com.cloud.upgrade.dao.Upgrade42300to42400; import com.cloud.upgrade.dao.Upgrade430to440; import com.cloud.upgrade.dao.Upgrade431to440; import com.cloud.upgrade.dao.Upgrade432to440; @@ -248,6 +249,7 @@ public DatabaseUpgradeChecker() { .next("4.21.0.0", new Upgrade42100to42200()) .next("4.22.0.0", new Upgrade42200to42210()) .next("4.22.1.0", new Upgrade42210to42300()) + .next("4.23.0.0", new Upgrade42300to42400()) .build(); } diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42300to42400.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42300to42400.java new file mode 100644 index 000000000000..ac617060eebd --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42300to42400.java @@ -0,0 +1,54 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.upgrade.dao; + +import java.io.InputStream; +import java.sql.Connection; + +import com.cloud.utils.exception.CloudRuntimeException; + +public class Upgrade42300to42400 extends DbUpgradeAbstractImpl implements DbUpgrade { + + @Override + public String[] getUpgradableVersionRange() { + return new String[]{"4.23.0.0", "4.24.0.0"}; + } + + @Override + public String getUpgradedVersion() { + return "4.24.0.0"; + } + + @Override + public InputStream[] getPrepareScripts() { + final String scriptFile = "META-INF/db/schema-42300to42400.sql"; + final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile); + if (script == null) { + throw new CloudRuntimeException("Unable to find " + scriptFile); + } + return new InputStream[]{script}; + } + + @Override + public void performDataMigration(Connection conn) { + } + + @Override + public InputStream[] getCleanupScripts() { + return null; + } +} diff --git a/engine/schema/src/main/java/com/cloud/vm/NicVO.java b/engine/schema/src/main/java/com/cloud/vm/NicVO.java index 65946b8d8210..dd405381cb9b 100644 --- a/engine/schema/src/main/java/com/cloud/vm/NicVO.java +++ b/engine/schema/src/main/java/com/cloud/vm/NicVO.java @@ -131,6 +131,9 @@ protected NicVO() { @Column(name = "mtu") Integer mtu; + @Column(name = "network_rate") + Integer networkRate; + @Column(name = "enabled") boolean enabled; @@ -426,4 +429,12 @@ public Integer getMtu() { public void setMtu(Integer mtu) { this.mtu = mtu; } + + public Integer getNetworkRate() { + return networkRate; + } + + public void setNetworkRate(Integer networkRate) { + this.networkRate = networkRate; + } } diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42300to42400.sql b/engine/schema/src/main/resources/META-INF/db/schema-42300to42400.sql new file mode 100644 index 000000000000..ea0c8e62ca0f --- /dev/null +++ b/engine/schema/src/main/resources/META-INF/db/schema-42300to42400.sql @@ -0,0 +1,20 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. + +-- Schema upgrade from 4.23.0.0 to 4.24.0.0 + +ALTER TABLE `cloud`.`nics` ADD COLUMN `network_rate` int unsigned DEFAULT NULL COMMENT 'effective network rate in Mb/s for this NIC'; diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.user_vm_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.user_vm_view.sql index fbf126608eae..5f6c31043596 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.user_vm_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.user_vm_view.sql @@ -144,6 +144,7 @@ SELECT `nics`.`broadcast_uri` AS `broadcast_uri`, `nics`.`isolation_uri` AS `isolation_uri`, `nics`.`enabled` AS `is_nic_enabled`, + `nics`.`network_rate` AS `nic_network_rate`, `nic_details`.`value` AS `nic_dns_name`, `vpc`.`id` AS `vpc_id`, `vpc`.`uuid` AS `vpc_uuid`, diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index f350ca262237..7977291d76d6 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -454,7 +454,6 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; -import com.cloud.vm.NicDetailVO; import com.cloud.vm.dao.NicExtraDhcpOptionDao; import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.snapshot.VMSnapshot; @@ -4910,10 +4909,7 @@ public NicResponse createNicResponse(Nic result) { response.setEnabled(result.isEnabled()); - NicDetailVO nicRateDetail = ApiDBUtils.findNicDetailByName(result.getId(), ApiConstants.NETWORKRATE); - if (nicRateDetail != null) { - response.setNetworkRate(nicRateDetail.getValue()); - } + response.setNetworkRate(result.getNetworkRate()); return response; } diff --git a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java index d3887c1a7db8..2d5cde339616 100644 --- a/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/UserVmJoinDaoImpl.java @@ -97,7 +97,6 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.net.Dhcp; -import com.cloud.vm.NicDetailVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.VMInstanceDetailVO; import com.cloud.vm.VirtualMachine; @@ -448,10 +447,7 @@ public UserVmResponse newUserVmResponse(ResponseView view, String objectName, Us .collect(Collectors.toList()); nicResponse.setExtraDhcpOptions(nicExtraDhcpOptionResponses); - NicDetailVO nicNetworkRateDetail = ApiDBUtils.findNicDetailByName(userVm.getNicId(), ApiConstants.NETWORKRATE); - if (nicNetworkRateDetail != null) { - nicResponse.setNetworkRate(nicNetworkRateDetail.getValue()); - } + nicResponse.setNetworkRate(userVm.getNicNetworkRate()); userVmResponse.addNic(nicResponse); } } @@ -750,10 +746,7 @@ public UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVm .collect(Collectors.toList()); nicResponse.setExtraDhcpOptions(nicExtraDhcpOptionResponses); - NicDetailVO nicNetworkRateDetail = ApiDBUtils.findNicDetailByName(uvo.getNicId(), ApiConstants.NETWORKRATE); - if (nicNetworkRateDetail != null) { - nicResponse.setNetworkRate(nicNetworkRateDetail.getValue()); - } + nicResponse.setNetworkRate(uvo.getNicNetworkRate()); userVmData.addNic(nicResponse); } diff --git a/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java index 6f84bd9b1e3e..5e63e4383e09 100644 --- a/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/UserVmJoinVO.java @@ -355,6 +355,9 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro @Column(name = "is_nic_enabled") private boolean isNicEnabled; + @Column(name = "nic_network_rate") + private Integer nicNetworkRate; + @Column(name = "ip_address") private String ipAddress; @@ -1115,6 +1118,10 @@ public boolean isNicEnabled() { return isNicEnabled; } + public Integer getNicNetworkRate() { + return nicNetworkRate; + } + public String getNicDnsName() { return nicDnsName; } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 23dfb12b24c6..5f814cd192b9 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -421,7 +421,6 @@ import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.InstanceGroupVMMapDao; import com.cloud.vm.dao.NicDao; -import com.cloud.vm.dao.NicDetailsDao; import com.cloud.vm.dao.NicExtraDhcpOptionDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @@ -525,8 +524,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir @Inject private NicDao _nicDao; @Inject - private NicDetailsDao nicDetailsDao; - @Inject private RulesManager _rulesMgr; @Inject private LoadBalancingRulesManager _lbMgr; @@ -1576,7 +1573,6 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV saveExtraDhcpOptions(guestNic.getId(), cmd.getDhcpOptionsMap()); _networkMgr.configureExtraDhcpOptions(network, guestNic.getId(), cmd.getDhcpOptionsMap()); cleanUp = false; - saveNetworkRateInDetails(guestNic.getId(), guestNic.getNetworkRate()); } catch (ResourceUnavailableException e) { throw new CloudRuntimeException("Unable to add NIC to " + vmInstance + ": " + e); } catch (InsufficientCapacityException e) { @@ -1598,15 +1594,12 @@ public UserVm addNicToVirtualMachine(AddNicToVMCmd cmd) throws InvalidParameterV return _vmDao.findById(vmInstance.getId()); } - private void saveNetworkRateInDetails(long nicId, Integer rate) { - String networkRate = (rate == null || rate <= 0) ? ApiConstants.UNLIMITED : String.valueOf(rate); - nicDetailsDao.addDetail(nicId, ApiConstants.NETWORKRATE, networkRate, true); - } - private void refreshNicNetworkRates(long vmId) { List nics = _nicDao.listByVmId(vmId); for (NicVO nic : nics) { - saveNetworkRateInDetails(nic.getId(), _networkModel.getNetworkRate(nic.getNetworkId(), vmId)); + Integer rate = _networkModel.getNetworkRate(nic.getNetworkId(), vmId); + nic.setNetworkRate(rate != null && rate > 0 ? rate : null); + _nicDao.update(nic.getId(), nic); } } From b684b88ab249ee2d6c2179038b9196d210ebe6ab Mon Sep 17 00:00:00 2001 From: Manoj Kumar Date: Mon, 7 Sep 2026 16:44:41 +0530 Subject: [PATCH 3/3] fix ui build due to merge conflict --- ui/src/config/section/offering.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/src/config/section/offering.js b/ui/src/config/section/offering.js index ee3de0486f14..6180d1467d2b 100644 --- a/ui/src/config/section/offering.js +++ b/ui/src/config/section/offering.js @@ -43,7 +43,6 @@ export default { } return [] }, - filters: ['active', 'inactive'], columns: ['name', 'displaytext', 'state', 'cpunumber', 'cpuspeed', 'memory', 'gpu', 'domain', 'zone', 'order', 'networkrate'], details: () => { var fields = ['name', 'id', 'displaytext', 'offerha', 'provisioningtype', 'storagetype', 'iscustomized', 'iscustomizediops', 'limitcpuuse', 'cpunumber', 'cpuspeed', 'memory', 'hosttags', 'tags', 'storageaccessgroups', 'storagetags', 'domain', 'zone', 'created', 'dynamicscalingenabled', 'diskofferingstrictness', 'encryptroot', 'purgeresources', 'leaseduration', 'gpucardid', 'gpucardname', 'vgpuprofileid', 'vgpuprofilename', 'gpucount', 'gpudisplay', 'leaseexpiryaction', 'externaldetails', 'networkrate']