From 14bff7bd034a5697c50a6755c420f121d8a58754 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Thu, 27 Jun 2019 09:18:10 +0530 Subject: [PATCH] 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 --- .../apache/cloudstack/api/ApiConstants.java | 5 + .../api/response/UserVmResponse.java | 8 +- .../api/response/VolumeResponse.java | 65 ++- .../vmware/resource/VmwareResource.java | 386 +++++++++++++----- .../CitrixGetVmDiskStatsCommandWrapper.java | 2 +- .../metrics/MetricsServiceImpl.java | 65 +-- .../response/VmMetricsResponse.java | 9 +- .../response/VolumeMetricsResponse.java | 14 +- .../api/query/dao/VolumeJoinDaoImpl.java | 12 + .../java/com/cloud/server/StatsCollector.java | 4 +- .../java/com/cloud/vm/UserVmManagerImpl.java | 6 +- ui/scripts/metrics.js | 15 + .../vmware/mo/VirtualMachineMO.java | 2 +- .../hypervisor/vmware/util/VmwareHelper.java | 35 ++ 14 files changed, 461 insertions(+), 167 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 7502b18488e..3c1d7bb93c6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -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"; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java index bbf6b6cf614..8a2f1a169d6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java @@ -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; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VolumeResponse.java index d845e414808..01d2c9b3d8f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VolumeResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VolumeResponse.java @@ -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; } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 3d6732c0fbe..c195712e62a 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -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 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> vmStatsMap = new HashMap<>(); + for (final String vmName : cmd.getVmNames()) { + final VirtualMachineMO vmMo = dcMo.findVm(vmName); + final List 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 perfMetricsIds = new ArrayList(); + 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 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 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 vmResponseMap = new HashMap(); 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 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 vmNetworkMetrics = new ArrayList(); - // get all the metrics from the available sample period - List 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 perfMetricsIds = new ArrayList(); + 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 qSpecs = new ArrayList(); - qSpecs.add(qSpec); - List values = service.queryPerf(perfMgr, qSpecs); - - for (int i = 0; i < values.size(); ++i) { - List 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 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 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 perfValues = service.queryPerf(perfMgr, Collections.singletonList(qSpec)); + for (final PerfEntityMetricBase perfValue : perfValues) { + if (!(perfValue instanceof PerfEntityMetric)) { + continue; + } + final List seriesList = ((PerfEntityMetric) perfValue).getValue(); + for (final PerfMetricSeries series : seriesList) { + if (!(series instanceof PerfMetricIntSeries)) { + continue; + } + final List 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); } } diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVmDiskStatsCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVmDiskStatsCommandWrapper.java index 04090ce7436..d15e0a71727 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVmDiskStatsCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetVmDiskStatsCommandWrapper.java @@ -33,4 +33,4 @@ public final class CitrixGetVmDiskStatsCommandWrapper extends CommandWrapper volSearch; @@ -102,6 +106,14 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation 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 hosts = _hostDao.search(sc, null); for (HostVO host : hosts) { List vms = _userVmDao.listRunningByHostId(host.getId()); List vmIds = new ArrayList(); - for (UserVmVO vm : vms) { + for (UserVmVO vm : vms) { if (vm.getType() == VirtualMachine.Type.User) // user vm vmIds.add(vm.getId()); } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 0727a2a8593..f3731ab6ffe 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -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 } } } -} \ No newline at end of file +} diff --git a/ui/scripts/metrics.js b/ui/scripts/metrics.js index c3c68e1e233..2784eab2d8d 100644 --- a/ui/scripts/metrics.js +++ b/ui/scripts/metrics.js @@ -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) { diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index d9d03d1484a..6a42f7f9aea 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -2709,7 +2709,7 @@ public class VirtualMachineMO extends BaseMO { return pathList; } - private String getDeviceBusName(List allDevices, VirtualDevice theDevice) throws Exception { + public String getDeviceBusName(List allDevices, VirtualDevice theDevice) throws Exception { for (VirtualDevice device : allDevices) { if (device.getKey() == theDevice.getControllerKey().intValue()) { if (device instanceof VirtualIDEController) { diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java index bb7f3c5a140..6477eb1ecee 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareHelper.java @@ -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); + } + }