This is an automated email from the ASF dual-hosted git repository.

harikrishna-patnala pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.22 by this push:
     new 434df401b08 Routed: get vm network statistics on Routed network 
(#13105)
434df401b08 is described below

commit 434df401b0878b1d9eeac4eafcafcba4609081a5
Author: Wei Zhou <[email protected]>
AuthorDate: Thu Sep 10 11:01:24 2026 +0200

    Routed: get vm network statistics on Routed network (#13105)
    
    * Routed: get vm network statistics on Routed network
    
    * Potential fix for pull request finding
    
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
    
    * Create method isNetworkEligibleForNetworkStats and add unit tests
    
    ---------
    
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
---
 .../main/java/com/cloud/server/StatsCollector.java | 39 ++++++++--
 .../java/com/cloud/server/StatsCollectorTest.java  | 88 ++++++++++++++++++++++
 2 files changed, 122 insertions(+), 5 deletions(-)

diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java 
b/server/src/main/java/com/cloud/server/StatsCollector.java
index 917e05a3c98..3eec27d4f54 100644
--- a/server/src/main/java/com/cloud/server/StatsCollector.java
+++ b/server/src/main/java/com/cloud/server/StatsCollector.java
@@ -57,6 +57,7 @@ import org.apache.cloudstack.framework.config.Configurable;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.management.ManagementServerHost;
+import org.apache.cloudstack.network.RoutedIpv4Manager;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
@@ -113,6 +114,8 @@ import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.network.as.AutoScaleManager;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
 import com.cloud.org.Cluster;
 import com.cloud.resource.ResourceManager;
 import com.cloud.resource.ResourceState;
@@ -203,6 +206,11 @@ import com.sun.management.OperatingSystemMXBean;
 @Component
 public class StatsCollector extends ManagerBase implements 
ComponentMethodInterceptable, Configurable, DbStatsCollection {
 
+    @Inject
+    private NetworkDao networkDao;
+    @Inject
+    private RoutedIpv4Manager routedIpv4Manager;
+
     public static enum ExternalStatsProtocol {
         NONE("none"), GRAPHITE("graphite"), INFLUXDB("influxdb");
         String _type;
@@ -268,9 +276,9 @@ public class StatsCollector extends ManagerBase implements 
ComponentMethodInterc
     private static final ConfigKey<Integer> vmDiskStatsIntervalMin = new 
ConfigKey<>("Advanced", Integer.class, "vm.disk.stats.interval.min", "300",
             "Minimal interval (in seconds) to report vm disk statistics. If 
vm.disk.stats.interval is smaller than this, use this to report vm disk 
statistics.", false);
     private static final ConfigKey<Integer> vmNetworkStatsInterval = new 
ConfigKey<>("Advanced", Integer.class, "vm.network.stats.interval", "0",
-            "Interval (in seconds) to report vm network statistics (for Shared 
networks). Vm network statistics will be disabled if this is set to 0 or less 
than 0.", false);
+            "Interval (in seconds) to report vm network statistics (for Shared 
and Routed networks). Vm network statistics will be disabled if this is set to 
0 or less than 0.", false);
     private static final ConfigKey<Integer> vmNetworkStatsIntervalMin = new 
ConfigKey<>("Advanced", Integer.class, "vm.network.stats.interval.min", "300",
-            "Minimal Interval (in seconds) to report vm network statistics 
(for Shared networks). If vm.network.stats.interval is smaller than this, use 
this to report vm network statistics.",
+            "Minimal Interval (in seconds) to report vm network statistics 
(for Shared and Routed networks). If vm.network.stats.interval is smaller than 
this, use this to report vm network statistics.",
             false);
     private static final ConfigKey<Integer> StatsTimeout = new 
ConfigKey<>("Advanced", Integer.class, "stats.timeout", "60000",
             "The timeout for stats call in milli seconds.", true,
@@ -1601,9 +1609,9 @@ public class StatsCollector extends ManagerBase 
implements ComponentMethodInterc
                                     SearchCriteria<NicVO> sc_nic = 
_nicDao.createSearchCriteria();
                                     sc_nic.addAnd("macAddress", 
SearchCriteria.Op.EQ, vmNetworkStatEntry.getMacAddress());
                                     NicVO nic = _nicDao.search(sc_nic, 
null).get(0);
-                                    List<VlanVO> vlan = 
_vlanDao.listVlansByNetworkId(nic.getNetworkId());
-                                    if (vlan == null || vlan.size() == 0 || 
vlan.get(0).getVlanType() != VlanType.DirectAttached)
-                                        continue; // only get network 
statistics for DirectAttached network (shared networks in Basic zone and 
Advanced zone with/without SG)
+                                    if 
(!isNetworkEligibleForNetworkStats(nic.getNetworkId())) {
+                                        continue; // only get network 
statistics for Shared or Routed network
+                                    }
                                     UserStatisticsVO previousvmNetworkStats = 
_userStatsDao.findBy(userVm.getAccountId(), userVm.getDataCenterId(), 
nic.getNetworkId(),
                                             nic.getIPv4Address(), vmId, 
"UserVm");
                                     if (previousvmNetworkStats == null) {
@@ -2159,6 +2167,27 @@ public class StatsCollector extends ManagerBase 
implements ComponentMethodInterc
         return true;
     }
 
+    /**
+     * Returns {@code true} if the given network is eligible for VM network 
statistics collection.
+     * Only Shared (DirectAttached) networks and Routed networks qualify.
+     *
+     * @param networkId the network id to evaluate
+     * @return {@code true} when the network is routed or direct-attached, 
{@code false} otherwise
+     */
+    protected boolean isNetworkEligibleForNetworkStats(Long networkId) {
+        if (networkId == null) {
+            return false;
+        }
+        List<VlanVO> vlans = _vlanDao.listVlansByNetworkId(networkId);
+        boolean isDirectAttachedNetwork = CollectionUtils.isNotEmpty(vlans)
+                && vlans.get(0).getVlanType() == VlanType.DirectAttached;
+        if (isDirectAttachedNetwork) {
+            return true;
+        }
+        NetworkVO networkVO = networkDao.findById(networkId);
+        return networkVO != null && 
routedIpv4Manager.isRoutedNetwork(networkVO);
+    }
+
     /**
      * Returns true if all the VmDiskStatsEntry are Zeros (Bytes read, Bytes 
write, IO read, and IO write must be all equals to zero)
      */
diff --git a/server/src/test/java/com/cloud/server/StatsCollectorTest.java 
b/server/src/test/java/com/cloud/server/StatsCollectorTest.java
index 46449a9cb6e..cb00d1652c9 100644
--- a/server/src/test/java/com/cloud/server/StatsCollectorTest.java
+++ b/server/src/test/java/com/cloud/server/StatsCollectorTest.java
@@ -26,6 +26,7 @@ import java.net.URISyntaxException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -38,6 +39,7 @@ import java.util.concurrent.TimeUnit;
 import com.cloud.utils.DateUtil;
 import com.google.gson.JsonSyntaxException;
 import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.network.RoutedIpv4Manager;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.commons.collections.CollectionUtils;
 import org.influxdb.InfluxDB;
@@ -64,7 +66,12 @@ import com.cloud.agent.api.GetStorageStatsAnswer;
 import com.cloud.agent.api.GetStorageStatsCommand;
 import com.cloud.agent.api.VmDiskStatsEntry;
 import com.cloud.agent.api.VmStatsEntry;
+import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.VlanDao;
 import com.cloud.hypervisor.Hypervisor;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
 import com.cloud.server.StatsCollector.ExternalStatsProtocol;
 import com.cloud.storage.StorageStats;
 import com.cloud.storage.VolumeStatsVO;
@@ -118,6 +125,15 @@ public class StatsCollectorTest {
     @Mock
     private StoragePoolVO mockPool;
 
+    @Mock
+    private RoutedIpv4Manager routedIpv4Manager;
+
+    @Mock
+    private NetworkDao networkDao;
+
+    @Mock
+    private VlanDao vlanDao;
+
     private static Gson gson = new Gson();
 
     private Gson msStatsGson;
@@ -744,6 +760,78 @@ public class StatsCollectorTest {
          */
     }
 
+    // -----------------------------------------------------------------------
+    // Tests for isNetworkEligibleForNetworkStats
+    // -----------------------------------------------------------------------
+
+    private VlanVO buildVlan(VlanType type) {
+        VlanVO vlan = Mockito.mock(VlanVO.class);
+        Mockito.when(vlan.getVlanType()).thenReturn(type);
+        return vlan;
+    }
+
+    @Test
+    public void isNetworkEligibleForNetworkStats_RoutedNetwork_ReturnsTrue() {
+        Long networkId = 1L;
+        NetworkVO networkVO = Mockito.mock(NetworkVO.class);
+        Mockito.when(networkDao.findById(networkId)).thenReturn(networkVO);
+        
Mockito.when(vlanDao.listVlansByNetworkId(networkId)).thenReturn(Collections.emptyList());
+        
Mockito.when(routedIpv4Manager.isRoutedNetwork(networkVO)).thenReturn(true);
+
+        
Assert.assertTrue(statsCollector.isNetworkEligibleForNetworkStats(networkId));
+    }
+
+    @Test
+    public void 
isNetworkEligibleForNetworkStats_DirectAttachedNetwork_ReturnsTrue() {
+        Long networkId = 1L;
+        NetworkVO networkVO = Mockito.mock(NetworkVO.class);
+        Mockito.when(networkDao.findById(networkId)).thenReturn(networkVO);
+        
Mockito.when(routedIpv4Manager.isRoutedNetwork(networkVO)).thenReturn(false);
+        List<VlanVO> vlans = 
Collections.singletonList(buildVlan(VlanType.DirectAttached));
+        
Mockito.when(vlanDao.listVlansByNetworkId(networkId)).thenReturn(vlans);
+
+        
Assert.assertTrue(statsCollector.isNetworkEligibleForNetworkStats(networkId));
+    }
+
+    @Test
+    public void 
isNetworkEligibleForNetworkStats_NeitherRoutedNorDirectAttached_ReturnsFalse() {
+        Long networkId = 1L;
+        NetworkVO networkVO = Mockito.mock(NetworkVO.class);
+        Mockito.when(networkDao.findById(networkId)).thenReturn(networkVO);
+        
Mockito.when(routedIpv4Manager.isRoutedNetwork(networkVO)).thenReturn(false);
+        List<VlanVO> vlans = 
Collections.singletonList(buildVlan(VlanType.VirtualNetwork));
+        
Mockito.when(vlanDao.listVlansByNetworkId(networkId)).thenReturn(vlans);
+
+        
Assert.assertFalse(statsCollector.isNetworkEligibleForNetworkStats(networkId));
+    }
+
+    @Test
+    public void 
isNetworkEligibleForNetworkStats_NullNetworkAndEmptyVlans_ReturnsFalse() {
+        Long networkId = 1L;
+        Mockito.when(networkDao.findById(networkId)).thenReturn(null);
+        
Mockito.when(vlanDao.listVlansByNetworkId(networkId)).thenReturn(Collections.emptyList());
+
+        
Assert.assertFalse(statsCollector.isNetworkEligibleForNetworkStats(networkId));
+    }
+
+    @Test
+    public void 
isNetworkEligibleForNetworkStats_NullNetworkButDirectAttached_ReturnsTrue() {
+        Long networkId = 1L;
+        Mockito.when(networkDao.findById(networkId)).thenReturn(null);
+        List<VlanVO> vlans = 
Collections.singletonList(buildVlan(VlanType.DirectAttached));
+        
Mockito.when(vlanDao.listVlansByNetworkId(networkId)).thenReturn(vlans);
+
+        
Assert.assertTrue(statsCollector.isNetworkEligibleForNetworkStats(networkId));
+        Mockito.verify(routedIpv4Manager, 
Mockito.never()).isRoutedNetwork(Mockito.any());
+    }
+
+    @Test
+    public void isNetworkEligibleForNetworkStats_NullNetworkId_ReturnsFalse() {
+        
Assert.assertFalse(statsCollector.isNetworkEligibleForNetworkStats(null));
+        Mockito.verify(networkDao, 
Mockito.never()).findById(Mockito.anyLong());
+        Mockito.verify(vlanDao, 
Mockito.never()).listVlansByNetworkId(Mockito.anyLong());
+    }
+
     private static class TestClass {
         private String str;
         private int num;

Reply via email to