server: export granular volume bytes and iops metrics (#3259)

Problem: The VM metrics has aggregated volume bytes read/write and iops metrics but not on per volume basis.
Root Cause: The volume stats sub-system is not used to export the metrics, the support is not available for VMware.
Solution: Use the volume stats sub-system and DB table to export the metrics via the listVolumes and listVolumeMetrics API, and implement support for VMware and fix issue with network and disk metrics in the VM metrics view.

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2019-06-27 09:18:10 +05:30 committed by GitHub
parent 9f4f2c5348
commit 14bff7bd03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 461 additions and 167 deletions

View File

@ -91,6 +91,11 @@ public class ApiConstants {
public static final String DIRECT_DOWNLOAD = "directdownload";
public static final String DISK_OFFERING_ID = "diskofferingid";
public static final String NEW_DISK_OFFERING_ID = "newdiskofferingid";
public static final String DISK_KBS_READ = "diskkbsread";
public static final String DISK_KBS_WRITE = "diskkbswrite";
public static final String DISK_IO_READ = "diskioread";
public static final String DISK_IO_WRITE = "diskiowrite";
public static final String DISK_IO_PSTOTAL = "diskiopstotal";
public static final String DISK_SIZE = "disksize";
public static final String UTILIZATION = "utilization";
public static final String DRIVER = "driver";

View File

@ -188,11 +188,11 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
@Param(description = "the outgoing network traffic on the host")
private Long networkKbsWrite;
@SerializedName("diskkbsread")
@SerializedName(ApiConstants.DISK_KBS_READ)
@Param(description = "the read (bytes) of disk on the vm")
private Long diskKbsRead;
@SerializedName("diskkbswrite")
@SerializedName(ApiConstants.DISK_KBS_WRITE)
@Param(description = "the write (bytes) of disk on the vm")
private Long diskKbsWrite;
@ -208,11 +208,11 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
@Param(description = "the target memory in vm")
private Long memoryTargetKBs;
@SerializedName("diskioread")
@SerializedName(ApiConstants.DISK_IO_READ)
@Param(description = "the read (io) of disk on the vm")
private Long diskIORead;
@SerializedName("diskiowrite")
@SerializedName(ApiConstants.DISK_IO_WRITE)
@Param(description = "the write (io) of disk on the vm")
private Long diskIOWrite;

View File

@ -16,17 +16,18 @@
// under the License.
package org.apache.cloudstack.api.response;
import com.cloud.serializer.Param;
import com.cloud.storage.Volume;
import com.google.gson.annotations.SerializedName;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponseWithTagInformation;
import org.apache.cloudstack.api.EntityReference;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
import com.cloud.serializer.Param;
import com.cloud.storage.Volume;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = Volume.class)
@SuppressWarnings("unused")
@ -152,13 +153,29 @@ public class VolumeResponse extends BaseResponseWithTagInformation implements Co
private Long bytesWriteRate;
@SerializedName("diskIopsReadRate")
@Param(description = "io requests read rate of the disk volume")
@Param(description = "io requests read rate of the disk volume per the disk offering")
private Long iopsReadRate;
@SerializedName("diskIopsWriteRate")
@Param(description = "io requests write rate of the disk volume")
@Param(description = "io requests write rate of the disk volume per the disk offering")
private Long iopsWriteRate;
@SerializedName(ApiConstants.DISK_KBS_READ)
@Param(description = "the read (bytes) of disk on the vm")
private Long diskKbsRead;
@SerializedName(ApiConstants.DISK_KBS_WRITE)
@Param(description = "the write (bytes) of disk on the vm")
private Long diskKbsWrite;
@SerializedName(ApiConstants.DISK_IO_READ)
@Param(description = "the read (io) of disk on the vm")
private Long diskIORead;
@SerializedName(ApiConstants.DISK_IO_WRITE)
@Param(description = "the write (io) of disk on the vm")
private Long diskIOWrite;
@SerializedName(ApiConstants.HYPERVISOR)
@Param(description = "Hypervisor the volume belongs to")
private String hypervisor;
@ -395,10 +412,42 @@ public class VolumeResponse extends BaseResponseWithTagInformation implements Co
this.iopsWriteRate = iopsWriteRate;
}
public Long getDiskKbsRead() {
return diskKbsRead;
}
public void setDiskKbsRead(Long diskKbsRead) {
this.diskKbsRead = diskKbsRead;
}
public Long getDiskKbsWrite() {
return diskKbsWrite;
}
public void setDiskKbsWrite(Long diskKbsWrite) {
this.diskKbsWrite = diskKbsWrite;
}
public Long getIopsWriteRate() {
return iopsWriteRate;
}
public Long getDiskIORead() {
return diskIORead;
}
public void setDiskIORead(Long diskIORead) {
this.diskIORead = diskIORead;
}
public Long getDiskIOWrite() {
return diskIOWrite;
}
public void setDiskIOWrite(Long diskIOWrite) {
this.diskIOWrite = diskIOWrite;
}
public void setHypervisor(String hypervisor) {
this.hypervisor = hypervisor;
}

View File

@ -42,68 +42,7 @@ import java.util.TimeZone;
import java.util.UUID;
import javax.naming.ConfigurationException;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.joda.time.Duration;
import com.google.gson.Gson;
import com.vmware.vim25.AboutInfo;
import com.vmware.vim25.BoolPolicy;
import com.vmware.vim25.ComputeResourceSummary;
import com.vmware.vim25.CustomFieldStringValue;
import com.vmware.vim25.DVPortConfigInfo;
import com.vmware.vim25.DVPortConfigSpec;
import com.vmware.vim25.DasVmPriority;
import com.vmware.vim25.DatastoreSummary;
import com.vmware.vim25.DistributedVirtualPort;
import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
import com.vmware.vim25.DistributedVirtualSwitchPortCriteria;
import com.vmware.vim25.DynamicProperty;
import com.vmware.vim25.GuestInfo;
import com.vmware.vim25.HostCapability;
import com.vmware.vim25.HostHostBusAdapter;
import com.vmware.vim25.HostInternetScsiHba;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.ObjectContent;
import com.vmware.vim25.OptionValue;
import com.vmware.vim25.PerfCounterInfo;
import com.vmware.vim25.PerfEntityMetric;
import com.vmware.vim25.PerfEntityMetricBase;
import com.vmware.vim25.PerfMetricId;
import com.vmware.vim25.PerfMetricIntSeries;
import com.vmware.vim25.PerfMetricSeries;
import com.vmware.vim25.PerfQuerySpec;
import com.vmware.vim25.PerfSampleInfo;
import com.vmware.vim25.RuntimeFaultFaultMsg;
import com.vmware.vim25.ToolsUnavailableFaultMsg;
import com.vmware.vim25.VMwareDVSPortSetting;
import com.vmware.vim25.VimPortType;
import com.vmware.vim25.VirtualDevice;
import com.vmware.vim25.VirtualDeviceBackingInfo;
import com.vmware.vim25.VirtualDeviceConfigSpec;
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
import com.vmware.vim25.VirtualDisk;
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
import com.vmware.vim25.VirtualEthernetCard;
import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo;
import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo;
import com.vmware.vim25.VirtualEthernetCardOpaqueNetworkBackingInfo;
import com.vmware.vim25.VirtualMachineConfigSpec;
import com.vmware.vim25.VirtualMachineFileInfo;
import com.vmware.vim25.VirtualMachineFileLayoutEx;
import com.vmware.vim25.VirtualMachineFileLayoutExFileInfo;
import com.vmware.vim25.VirtualMachineGuestOsIdentifier;
import com.vmware.vim25.VirtualMachinePowerState;
import com.vmware.vim25.VirtualMachineRelocateSpec;
import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator;
import com.vmware.vim25.VirtualMachineRuntimeInfo;
import com.vmware.vim25.VirtualMachineToolsStatus;
import com.vmware.vim25.VirtualMachineVideoCard;
import com.vmware.vim25.VirtualUSBController;
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.storage.command.CopyCommand;
@ -114,6 +53,11 @@ import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
import org.apache.cloudstack.storage.to.TemplateObjectTO;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.joda.time.Duration;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
@ -211,6 +155,7 @@ import com.cloud.agent.api.UnregisterVMCommand;
import com.cloud.agent.api.UpgradeSnapshotCommand;
import com.cloud.agent.api.ValidateSnapshotAnswer;
import com.cloud.agent.api.ValidateSnapshotCommand;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.VolumeStatsEntry;
import com.cloud.agent.api.check.CheckSshAnswer;
@ -310,6 +255,60 @@ import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.PowerState;
import com.cloud.vm.VirtualMachineName;
import com.cloud.vm.VmDetailConstants;
import com.google.gson.Gson;
import com.vmware.vim25.AboutInfo;
import com.vmware.vim25.BoolPolicy;
import com.vmware.vim25.ComputeResourceSummary;
import com.vmware.vim25.CustomFieldStringValue;
import com.vmware.vim25.DVPortConfigInfo;
import com.vmware.vim25.DVPortConfigSpec;
import com.vmware.vim25.DasVmPriority;
import com.vmware.vim25.DatastoreSummary;
import com.vmware.vim25.DistributedVirtualPort;
import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
import com.vmware.vim25.DistributedVirtualSwitchPortCriteria;
import com.vmware.vim25.DynamicProperty;
import com.vmware.vim25.GuestInfo;
import com.vmware.vim25.HostCapability;
import com.vmware.vim25.HostHostBusAdapter;
import com.vmware.vim25.HostInternetScsiHba;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.ObjectContent;
import com.vmware.vim25.OptionValue;
import com.vmware.vim25.PerfCounterInfo;
import com.vmware.vim25.PerfEntityMetric;
import com.vmware.vim25.PerfEntityMetricBase;
import com.vmware.vim25.PerfMetricId;
import com.vmware.vim25.PerfMetricIntSeries;
import com.vmware.vim25.PerfMetricSeries;
import com.vmware.vim25.PerfQuerySpec;
import com.vmware.vim25.RuntimeFaultFaultMsg;
import com.vmware.vim25.ToolsUnavailableFaultMsg;
import com.vmware.vim25.VMwareDVSPortSetting;
import com.vmware.vim25.VimPortType;
import com.vmware.vim25.VirtualDevice;
import com.vmware.vim25.VirtualDeviceBackingInfo;
import com.vmware.vim25.VirtualDeviceConfigSpec;
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
import com.vmware.vim25.VirtualDisk;
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
import com.vmware.vim25.VirtualEthernetCard;
import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo;
import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo;
import com.vmware.vim25.VirtualEthernetCardOpaqueNetworkBackingInfo;
import com.vmware.vim25.VirtualMachineConfigSpec;
import com.vmware.vim25.VirtualMachineFileInfo;
import com.vmware.vim25.VirtualMachineFileLayoutEx;
import com.vmware.vim25.VirtualMachineFileLayoutExFileInfo;
import com.vmware.vim25.VirtualMachineGuestOsIdentifier;
import com.vmware.vim25.VirtualMachinePowerState;
import com.vmware.vim25.VirtualMachineRelocateSpec;
import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator;
import com.vmware.vim25.VirtualMachineRuntimeInfo;
import com.vmware.vim25.VirtualMachineToolsStatus;
import com.vmware.vim25.VirtualMachineVideoCard;
import com.vmware.vim25.VirtualUSBController;
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService, VirtualRouterDeployer {
private static final Logger s_logger = Logger.getLogger(VmwareResource.class);
@ -3469,6 +3468,120 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
protected Answer execute(GetVmDiskStatsCommand cmd) {
try {
final VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext());
final ManagedObjectReference perfMgr = getServiceContext().getServiceContent().getPerfManager();
VimPortType service = getServiceContext().getService();
final int intervalSeconds = 300;
final XMLGregorianCalendar startTime = VmwareHelper.getXMLGregorianCalendar(new Date(), intervalSeconds);
final XMLGregorianCalendar endTime = VmwareHelper.getXMLGregorianCalendar(new Date(), 0);
PerfCounterInfo diskReadIOPerfCounterInfo = null;
PerfCounterInfo diskWriteIOPerfCounterInfo = null;
PerfCounterInfo diskReadKbsPerfCounterInfo = null;
PerfCounterInfo diskWriteKbsPerfCounterInfo = null;
// https://pubs.vmware.com/vsphere-5-5/topic/com.vmware.wssdk.apiref.doc/virtual_disk_counters.html
List<PerfCounterInfo> cInfo = getServiceContext().getVimClient().getDynamicProperty(perfMgr, "perfCounter");
for (PerfCounterInfo info : cInfo) {
if ("virtualdisk".equalsIgnoreCase(info.getGroupInfo().getKey()) && "average".equalsIgnoreCase(info.getRollupType().value())) {
if ("numberReadAveraged".equalsIgnoreCase(info.getNameInfo().getKey())) {
diskReadIOPerfCounterInfo = info;
}
if ("numberWriteAveraged".equalsIgnoreCase(info.getNameInfo().getKey())) {
diskWriteIOPerfCounterInfo = info;
}
if ("read".equalsIgnoreCase(info.getNameInfo().getKey())) {
diskReadKbsPerfCounterInfo = info;
}
if ("write".equalsIgnoreCase(info.getNameInfo().getKey())) {
diskWriteKbsPerfCounterInfo = info;
}
}
}
final ManagedObjectReference dcMor = hyperHost.getHyperHostDatacenter();
final DatacenterMO dcMo = new DatacenterMO(getServiceContext(), dcMor);
final HashMap<String, List<VmDiskStatsEntry>> vmStatsMap = new HashMap<>();
for (final String vmName : cmd.getVmNames()) {
final VirtualMachineMO vmMo = dcMo.findVm(vmName);
final List<VmDiskStatsEntry> diskStats = new ArrayList<>();
for (final VirtualDisk disk : vmMo.getAllDiskDevice()) {
final String diskBusName = vmMo.getDeviceBusName(vmMo.getAllDeviceList(), disk);
long readReq = 0;
long readBytes = 0;
long writeReq = 0;
long writeBytes = 0;
final ArrayList<PerfMetricId> perfMetricsIds = new ArrayList<PerfMetricId>();
if (diskReadIOPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(diskReadIOPerfCounterInfo, diskBusName));
}
if (diskWriteIOPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(diskWriteIOPerfCounterInfo, diskBusName));
}
if (diskReadKbsPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(diskReadKbsPerfCounterInfo, diskBusName));
}
if (diskWriteKbsPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(diskWriteKbsPerfCounterInfo, diskBusName));
}
if (perfMetricsIds.size() > 0) {
final PerfQuerySpec qSpec = new PerfQuerySpec();
qSpec.setEntity(vmMo.getMor());
qSpec.setFormat("normal");
qSpec.setIntervalId(intervalSeconds);
qSpec.setStartTime(startTime);
qSpec.setEndTime(endTime);
qSpec.getMetricId().addAll(perfMetricsIds);
for (final PerfEntityMetricBase perfValue : service.queryPerf(perfMgr, Collections.singletonList(qSpec))) {
if (!(perfValue instanceof PerfEntityMetric)) {
continue;
}
final List<PerfMetricSeries> values = ((PerfEntityMetric)perfValue).getValue();
if (values == null || values.isEmpty()) {
continue;
}
for (final PerfMetricSeries value : values) {
if (!(value instanceof PerfMetricIntSeries) || !value.getId().getInstance().equals(diskBusName)) {
continue;
}
final List<Long> perfStats = ((PerfMetricIntSeries)value).getValue();
if (perfStats.size() > 0) {
long sum = 0;
for (long val : perfStats) {
sum += val;
}
long avg = sum / perfStats.size();
if (value.getId().getCounterId() == diskReadIOPerfCounterInfo.getKey()) {
readReq = avg;
} else if (value.getId().getCounterId() == diskWriteIOPerfCounterInfo.getKey()) {
writeReq = avg;
} else if (value.getId().getCounterId() == diskReadKbsPerfCounterInfo.getKey()) {
readBytes = avg * 1024;
} else if (value.getId().getCounterId() == diskWriteKbsPerfCounterInfo.getKey()) {
writeBytes = avg * 1024;
}
}
}
}
}
diskStats.add(new VmDiskStatsEntry(vmName, VmwareHelper.getDiskDeviceFileName(disk), writeReq, readReq, writeBytes, readBytes));
}
if (diskStats.size() > 0) {
vmStatsMap.put(vmName, diskStats);
}
}
if (vmStatsMap.size() > 0) {
return new GetVmDiskStatsAnswer(cmd, "", cmd.getHostName(), vmStatsMap);
}
} catch (Exception e) {
s_logger.error("Unable to execute GetVmDiskStatsCommand due to " + VmwareHelper.getExceptionMessage(e), e);
}
return new GetVmDiskStatsAnswer(cmd, null, null, null);
}
@ -5857,12 +5970,21 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
HashMap<String, VmStatsEntry> vmResponseMap = new HashMap<String, VmStatsEntry>();
ManagedObjectReference perfMgr = getServiceContext().getServiceContent().getPerfManager();
VimPortType service = getServiceContext().getService();
PerfCounterInfo rxPerfCounterInfo = null;
PerfCounterInfo txPerfCounterInfo = null;
PerfCounterInfo diskReadIOPerfCounterInfo = null;
PerfCounterInfo diskWriteIOPerfCounterInfo = null;
PerfCounterInfo diskReadKbsPerfCounterInfo = null;
PerfCounterInfo diskWriteKbsPerfCounterInfo = null;
final int intervalSeconds = 300;
final XMLGregorianCalendar startTime = VmwareHelper.getXMLGregorianCalendar(new Date(), intervalSeconds);
final XMLGregorianCalendar endTime = VmwareHelper.getXMLGregorianCalendar(new Date(), 0);
List<PerfCounterInfo> cInfo = getServiceContext().getVimClient().getDynamicProperty(perfMgr, "perfCounter");
for (PerfCounterInfo info : cInfo) {
if ("net".equalsIgnoreCase(info.getGroupInfo().getKey())) {
if ("net".equalsIgnoreCase(info.getGroupInfo().getKey()) && "average".equalsIgnoreCase(info.getRollupType().value())) {
if ("transmitted".equalsIgnoreCase(info.getNameInfo().getKey())) {
txPerfCounterInfo = info;
}
@ -5870,6 +5992,20 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
rxPerfCounterInfo = info;
}
}
if ("virtualdisk".equalsIgnoreCase(info.getGroupInfo().getKey())) {
if ("numberReadAveraged".equalsIgnoreCase(info.getNameInfo().getKey())) {
diskReadIOPerfCounterInfo = info;
}
if ("numberWriteAveraged".equalsIgnoreCase(info.getNameInfo().getKey())) {
diskWriteIOPerfCounterInfo = info;
}
if ("read".equalsIgnoreCase(info.getNameInfo().getKey())) {
diskReadKbsPerfCounterInfo = info;
}
if ("write".equalsIgnoreCase(info.getNameInfo().getKey())) {
diskWriteKbsPerfCounterInfo = info;
}
}
}
int key = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME);
@ -5885,8 +6021,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
final String memMbStr = "config.hardware.memoryMB";
final String allocatedCpuStr = "summary.runtime.maxCpuUsage";
ObjectContent[] ocs =
hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", numCpuStr, cpuUseStr ,guestMemUseStr ,memLimitStr ,memMbStr,allocatedCpuStr ,instanceNameCustomField});
ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[] {
"name", numCpuStr, cpuUseStr, guestMemUseStr, memLimitStr, memMbStr,allocatedCpuStr, instanceNameCustomField
});
if (ocs != null && ocs.length > 0) {
for (ObjectContent oc : ocs) {
@ -5923,7 +6060,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
maxCpuUsage = (maxCpuUsage/allocatedCpu)*100;
new VirtualMachineMO(hyperHost.getContext(), oc.getObj());
if (vmInternalCSName != null) {
name = vmInternalCSName;
} else {
@ -5937,60 +6073,86 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
ManagedObjectReference vmMor = hyperHost.findVmOnHyperHost(name).getMor();
assert (vmMor != null);
ArrayList<PerfMetricId> vmNetworkMetrics = new ArrayList<PerfMetricId>();
// get all the metrics from the available sample period
List<PerfMetricId> perfMetrics = service.queryAvailablePerfMetric(perfMgr, vmMor, null, null, null);
if (perfMetrics != null) {
for (int index = 0; index < perfMetrics.size(); ++index) {
if (((rxPerfCounterInfo != null) && (perfMetrics.get(index).getCounterId() == rxPerfCounterInfo.getKey()))
|| ((txPerfCounterInfo != null) && (perfMetrics.get(index).getCounterId() == txPerfCounterInfo.getKey()))) {
vmNetworkMetrics.add(perfMetrics.get(index));
}
}
}
double networkReadKBs = 0;
double networkWriteKBs = 0;
long sampleDuration = 0;
double diskReadIops = 0;
double diskWriteIops = 0;
double diskReadKbs = 0;
double diskWriteKbs = 0;
if (vmNetworkMetrics.size() != 0) {
PerfQuerySpec qSpec = new PerfQuerySpec();
final ArrayList<PerfMetricId> perfMetricsIds = new ArrayList<PerfMetricId>();
if (rxPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(rxPerfCounterInfo, ""));
}
if (txPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(txPerfCounterInfo, ""));
}
if (diskReadIOPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(diskReadIOPerfCounterInfo, "*"));
}
if (diskWriteIOPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(diskWriteIOPerfCounterInfo, "*"));
}
if (diskReadKbsPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(diskReadKbsPerfCounterInfo, ""));
}
if (diskWriteKbsPerfCounterInfo != null) {
perfMetricsIds.add(VmwareHelper.createPerfMetricId(diskWriteKbsPerfCounterInfo, ""));
}
if (perfMetricsIds.size() > 0) {
final PerfQuerySpec qSpec = new PerfQuerySpec();
qSpec.setEntity(vmMor);
PerfMetricId[] availableMetricIds = vmNetworkMetrics.toArray(new PerfMetricId[0]);
qSpec.getMetricId().addAll(Arrays.asList(availableMetricIds));
List<PerfQuerySpec> qSpecs = new ArrayList<PerfQuerySpec>();
qSpecs.add(qSpec);
List<PerfEntityMetricBase> values = service.queryPerf(perfMgr, qSpecs);
for (int i = 0; i < values.size(); ++i) {
List<PerfSampleInfo> infos = ((PerfEntityMetric)values.get(i)).getSampleInfo();
if (infos != null && infos.size() > 0) {
int endMs = infos.get(infos.size() - 1).getTimestamp().getSecond() * 1000 + infos.get(infos.size() - 1).getTimestamp().getMillisecond();
int beginMs = infos.get(0).getTimestamp().getSecond() * 1000 + infos.get(0).getTimestamp().getMillisecond();
sampleDuration = (endMs - beginMs) / 1000;
List<PerfMetricSeries> vals = ((PerfEntityMetric)values.get(i)).getValue();
for (int vi = 0; ((vals != null) && (vi < vals.size())); ++vi) {
if (vals.get(vi) instanceof PerfMetricIntSeries) {
PerfMetricIntSeries val = (PerfMetricIntSeries)vals.get(vi);
List<Long> perfValues = val.getValue();
Long sumRate = 0L;
for (int j = 0; j < infos.size(); j++) { // Size of the array matches the size as the PerfSampleInfo
sumRate += perfValues.get(j);
}
Long averageRate = sumRate / infos.size();
if (vals.get(vi).getId().getCounterId() == rxPerfCounterInfo.getKey()) {
networkReadKBs = sampleDuration * averageRate; //get the average RX rate multiplied by sampled duration
}
if (vals.get(vi).getId().getCounterId() == txPerfCounterInfo.getKey()) {
networkWriteKBs = sampleDuration * averageRate;//get the average TX rate multiplied by sampled duration
}
}
qSpec.setFormat("normal");
qSpec.setIntervalId(intervalSeconds);
qSpec.setStartTime(startTime);
qSpec.setEndTime(endTime);
qSpec.getMetricId().addAll(perfMetricsIds);
final List<PerfEntityMetricBase> perfValues = service.queryPerf(perfMgr, Collections.singletonList(qSpec));
for (final PerfEntityMetricBase perfValue : perfValues) {
if (!(perfValue instanceof PerfEntityMetric)) {
continue;
}
final List<PerfMetricSeries> seriesList = ((PerfEntityMetric) perfValue).getValue();
for (final PerfMetricSeries series : seriesList) {
if (!(series instanceof PerfMetricIntSeries)) {
continue;
}
final List<Long> values = ((PerfMetricIntSeries) series).getValue();
double sum = 0;
for (final Long value : values) {
sum += value;
}
double avg = sum / values.size();
if (series.getId().getCounterId() == rxPerfCounterInfo.getKey()) {
networkReadKBs = avg;
}
if (series.getId().getCounterId() == txPerfCounterInfo.getKey()) {
networkWriteKBs = avg;
}
if (series.getId().getCounterId() == diskReadIOPerfCounterInfo.getKey()) {
diskReadIops += avg;
}
if (series.getId().getCounterId() == diskWriteIOPerfCounterInfo.getKey()) {
diskWriteIops += avg;
}
if (series.getId().getCounterId() == diskReadKbsPerfCounterInfo.getKey()) {
diskReadKbs = avg;
}
if (series.getId().getCounterId() == diskWriteKbsPerfCounterInfo.getKey()) {
diskWriteKbs = avg;
}
}
}
}
vmResponseMap.put(name, new VmStatsEntry( NumberUtils.toDouble(memkb)*1024,NumberUtils.toDouble(guestMemusage)*1024,NumberUtils.toDouble(memlimit)*1024,
maxCpuUsage, networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), "vm"));
final VmStatsEntry vmStats = new VmStatsEntry( NumberUtils.toDouble(memkb)*1024,NumberUtils.toDouble(guestMemusage)*1024,NumberUtils.toDouble(memlimit)*1024,
maxCpuUsage, networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), "vm");
vmStats.setDiskReadIOs(diskReadIops);
vmStats.setDiskWriteIOs(diskWriteIops);
vmStats.setDiskReadKBs(diskReadKbs);
vmStats.setDiskWriteKBs(diskWriteKbs);
vmResponseMap.put(name, vmStats);
}
}

View File

@ -33,4 +33,4 @@ public final class CitrixGetVmDiskStatsCommandWrapper extends CommandWrapper<Get
public Answer execute(final GetVmDiskStatsCommand command, final CitrixResourceBase citrixResourceBase) {
return new GetVmDiskStatsAnswer(command, null, null, null);
}
}
}

View File

@ -17,6 +17,39 @@
package org.apache.cloudstack.metrics;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ListClustersMetricsCmd;
import org.apache.cloudstack.api.ListHostsMetricsCmd;
import org.apache.cloudstack.api.ListInfrastructureCmd;
import org.apache.cloudstack.api.ListStoragePoolsMetricsCmd;
import org.apache.cloudstack.api.ListVMsMetricsCmd;
import org.apache.cloudstack.api.ListVolumesMetricsCmd;
import org.apache.cloudstack.api.ListZonesMetricsCmd;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.response.ClusterMetricsResponse;
import org.apache.cloudstack.response.HostMetricsResponse;
import org.apache.cloudstack.response.InfrastructureResponse;
import org.apache.cloudstack.response.StoragePoolMetricsResponse;
import org.apache.cloudstack.response.VmMetricsResponse;
import org.apache.cloudstack.response.VolumeMetricsResponse;
import org.apache.cloudstack.response.ZoneMetricsResponse;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.commons.beanutils.BeanUtils;
import com.cloud.alert.AlertManager;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.query.dao.HostJoinDao;
@ -45,37 +78,6 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ListClustersMetricsCmd;
import org.apache.cloudstack.api.ListHostsMetricsCmd;
import org.apache.cloudstack.api.ListInfrastructureCmd;
import org.apache.cloudstack.api.ListStoragePoolsMetricsCmd;
import org.apache.cloudstack.api.ListVMsMetricsCmd;
import org.apache.cloudstack.api.ListVolumesMetricsCmd;
import org.apache.cloudstack.api.ListZonesMetricsCmd;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.response.ClusterMetricsResponse;
import org.apache.cloudstack.response.HostMetricsResponse;
import org.apache.cloudstack.response.InfrastructureResponse;
import org.apache.cloudstack.response.StoragePoolMetricsResponse;
import org.apache.cloudstack.response.VmMetricsResponse;
import org.apache.cloudstack.response.VolumeMetricsResponse;
import org.apache.cloudstack.response.ZoneMetricsResponse;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.commons.beanutils.BeanUtils;
import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
public class MetricsServiceImpl extends ComponentLifecycleBase implements MetricsService {
@ -163,6 +165,7 @@ public class MetricsServiceImpl extends ComponentLifecycleBase implements Metric
}
metricsResponse.setDiskSizeGB(volumeResponse.getSize());
metricsResponse.setDiskIopsTotal(volumeResponse.getDiskIORead(), volumeResponse.getDiskIOWrite());
Account account = CallContext.current().getCallingAccount();
if (accountMgr.isAdmin(account.getAccountId())) {
metricsResponse.setStorageType(volumeResponse.getStorageType(), volumeResponse.getVolumeType());

View File

@ -17,13 +17,14 @@
package org.apache.cloudstack.response;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import java.util.Set;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import java.util.Set;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
public class VmMetricsResponse extends UserVmResponse {
@SerializedName(ApiConstants.IP_ADDRESS)
@ -54,7 +55,7 @@ public class VmMetricsResponse extends UserVmResponse {
@Param(description = "disk write in MiB")
private String diskWrite;
@SerializedName("diskiopstotal")
@SerializedName(ApiConstants.DISK_IO_PSTOTAL)
@Param(description = "the total disk iops")
private Long diskIopsTotal;

View File

@ -17,16 +17,22 @@
package org.apache.cloudstack.response;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.response.VolumeResponse;
import com.cloud.serializer.Param;
import com.google.common.base.Strings;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.response.VolumeResponse;
public class VolumeMetricsResponse extends VolumeResponse {
@SerializedName("sizegb")
@Param(description = "disk size in GiB")
private String diskSizeGB;
@SerializedName(ApiConstants.DISK_IO_PSTOTAL)
@Param(description = "the total disk iops")
private Long diskIopsTotal;
public void setStorageType(final String storageType, final String volumeType) {
if (!Strings.isNullOrEmpty(storageType) && !Strings.isNullOrEmpty(volumeType)) {
this.setStorageType(String.format("%s (%s)", storageType.substring(0, 1).toUpperCase() + storageType.substring(1), volumeType));
@ -38,4 +44,10 @@ public class VolumeMetricsResponse extends VolumeResponse {
this.diskSizeGB = String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0));
}
}
public void setDiskIopsTotal(final Long diskIoRead, final Long diskIoWrite) {
if (diskIoRead != null && diskIoWrite != null) {
this.diskIopsTotal = diskIoRead + diskIoWrite;
}
}
}

View File

@ -36,6 +36,8 @@ import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.Volume;
import com.cloud.user.AccountManager;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.user.dao.VmDiskStatisticsDao;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@ -47,6 +49,8 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation<VolumeJo
private ConfigurationDao _configDao;
@Inject
public AccountManager _accountMgr;
@Inject
private VmDiskStatisticsDao vmDiskStatsDao;
private final SearchBuilder<VolumeJoinVO> volSearch;
@ -102,6 +106,14 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation<VolumeJo
} else {
volResponse.setVirtualMachineDisplayName(volume.getVmName());
}
VmDiskStatisticsVO diskStats = vmDiskStatsDao.findBy(volume.getAccountId(), volume.getDataCenterId(), instanceId, volume.getId());
if (diskStats != null) {
volResponse.setDiskIORead(diskStats.getCurrentIORead());
volResponse.setDiskIOWrite(diskStats.getCurrentIOWrite());
volResponse.setDiskKbsRead((long) (diskStats.getCurrentBytesRead() / 1024.0));
volResponse.setDiskKbsWrite((long) (diskStats.getCurrentBytesWrite() / 1024.0));
}
}
if (volume.getProvisioningType() != null) {

View File

@ -690,14 +690,14 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
s_logger.debug("VmDiskStatsTask is running...");
SearchCriteria<HostVO> sc = createSearchCriteriaForHostTypeRoutingStateUpAndNotInMaintenance();
sc.addAnd("hypervisorType", SearchCriteria.Op.EQ, HypervisorType.KVM); // support KVM only util 2013.06.25
sc.addAnd("hypervisorType", SearchCriteria.Op.IN, HypervisorType.KVM, HypervisorType.VMware);
List<HostVO> hosts = _hostDao.search(sc, null);
for (HostVO host : hosts) {
List<UserVmVO> vms = _userVmDao.listRunningByHostId(host.getId());
List<Long> vmIds = new ArrayList<Long>();
for (UserVmVO vm : vms) {
for (UserVmVO vm : vms) {
if (vm.getType() == VirtualMachine.Type.User) // user vm
vmIds.add(vm.getId());
}

View File

@ -4670,8 +4670,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override
public void collectVmDiskStatistics(final UserVm userVm) {
// support KVM only util 2013.06.25
if (!userVm.getHypervisorType().equals(HypervisorType.KVM)) {
// Only supported for KVM and VMware
if (!(userVm.getHypervisorType().equals(HypervisorType.KVM) || userVm.getHypervisorType().equals(HypervisorType.VMware))) {
return;
}
s_logger.debug("Collect vm disk statistics from host before stopping Vm");
@ -6684,4 +6684,4 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
}
}
}

View File

@ -607,6 +607,21 @@
},
storage: {
label: 'label.metrics.storagepool'
},
disk: {
label: 'label.metrics.disk.usage',
collapsible: true,
columns: {
diskioread: {
label: 'label.metrics.disk.read'
},
diskiowrite: {
label: 'label.metrics.disk.write'
},
diskiopstotal: {
label: 'label.metrics.disk.iops.total'
}
}
}
},
dataProvider: function(args) {

View File

@ -2709,7 +2709,7 @@ public class VirtualMachineMO extends BaseMO {
return pathList;
}
private String getDeviceBusName(List<VirtualDevice> allDevices, VirtualDevice theDevice) throws Exception {
public String getDeviceBusName(List<VirtualDevice> allDevices, VirtualDevice theDevice) throws Exception {
for (VirtualDevice device : allDevices) {
if (device.getKey() == theDevice.getControllerKey().intValue()) {
if (device instanceof VirtualIDEController) {

View File

@ -25,11 +25,16 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
@ -41,6 +46,8 @@ import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.MethodFault;
import com.vmware.vim25.ObjectContent;
import com.vmware.vim25.OptionValue;
import com.vmware.vim25.PerfCounterInfo;
import com.vmware.vim25.PerfMetricId;
import com.vmware.vim25.ResourceAllocationInfo;
import com.vmware.vim25.VirtualCdrom;
import com.vmware.vim25.VirtualCdromIsoBackingInfo;
@ -637,6 +644,25 @@ public class VmwareHelper {
return usbController;
}
public static PerfMetricId createPerfMetricId(PerfCounterInfo counterInfo, String instance) {
PerfMetricId metricId = new PerfMetricId();
metricId.setCounterId(counterInfo.getKey());
metricId.setInstance(instance);
return metricId;
}
public static String getDiskDeviceFileName(VirtualDisk diskDevice) {
VirtualDeviceBackingInfo backingInfo = diskDevice.getBacking();
if (backingInfo instanceof VirtualDiskFlatVer2BackingInfo) {
final String vmdkName = ((VirtualDiskFlatVer2BackingInfo)backingInfo).getFileName().replace(".vmdk", "");
if (vmdkName.contains("/")) {
return vmdkName.split("/", 2)[1];
}
return vmdkName;
}
return null;
}
public static ManagedObjectReference getDiskDeviceDatastore(VirtualDisk diskDevice) throws Exception {
VirtualDeviceBackingInfo backingInfo = diskDevice.getBacking();
assert (backingInfo instanceof VirtualDiskFlatVer2BackingInfo);
@ -773,4 +799,13 @@ public class VmwareHelper {
return DiskControllerType.getType(dataDiskController) == DiskControllerType.osdefault;
}
public static XMLGregorianCalendar getXMLGregorianCalendar(final Date date, final int offsetSeconds) throws DatatypeConfigurationException {
if (offsetSeconds > 0) {
date.setTime(date.getTime() - offsetSeconds * 1000);
}
final GregorianCalendar gregorianCalendar = new GregorianCalendar();
gregorianCalendar.setTime(date);
return DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
}
}