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
39 changes: 34 additions & 5 deletions server/src/main/java/com/cloud/server/StatsCollector.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
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;
Expand Down Expand Up @@ -113,6 +114,8 @@
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;
Expand Down Expand Up @@ -202,6 +205,11 @@
@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;
Expand Down Expand Up @@ -267,9 +275,9 @@ public String toString() {
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,
Expand Down Expand Up @@ -1581,9 +1589,9 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
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) {
Expand Down Expand Up @@ -2139,6 +2147,27 @@ protected boolean isCurrentVmDiskStatsDifferentFromPrevious(VmDiskStatisticsVO p
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);
}

Comment thread
weizhouapache marked this conversation as resolved.
/**
* Returns true if all the VmDiskStatsEntry are Zeros (Bytes read, Bytes write, IO read, and IO write must be all equals to zero)
*/
Expand Down
88 changes: 88 additions & 0 deletions server/src/test/java/com/cloud/server/StatsCollectorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
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;
Expand All @@ -38,6 +39,7 @@
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;
Expand All @@ -64,7 +66,12 @@
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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -701,6 +717,78 @@ public void testGsonDateFormatDeserializationWithDifferentDateFormat() throws Ex
*/
}

// -----------------------------------------------------------------------
// 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;
Expand Down
Loading