mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Persistence of VM stats (#5984)
* Add persistence of VM stats * Fix API 'since' attribute * Add license * Address GutoVeronezi's reviews * Fix the order of VM stats in the API response * Fix msid in VM stats data * Fix disk stats and add minor improvements * Add log message * Build string using ReflectionToStringBuilderUtils * Rerun checks Co-authored-by: joseflauzino <jose@scclouds.com.br>
This commit is contained in:
		
							parent
							
								
									1b46635947
								
							
						
					
					
						commit
						16f2896940
					
				| @ -18,6 +18,18 @@ | |||||||
| package org.apache.cloudstack.api; | package org.apache.cloudstack.api; | ||||||
| 
 | 
 | ||||||
| public enum ApiArgValidator { | public enum ApiArgValidator { | ||||||
|     NotNullOrEmpty, // does StringUtils.isEmpty check |     /** | ||||||
|     PositiveNumber, // does != null and > 0 check |      * Validates if the parameter is null or empty with the method {@link Strings#isNullOrEmpty(String)}. | ||||||
|  |      */ | ||||||
|  |     NotNullOrEmpty, | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Validates if the parameter is different from null (parameter != null) and greater than zero (parameter > 0). | ||||||
|  |      */ | ||||||
|  |     PositiveNumber, | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Validates if the parameter is an UUID with the method {@link UuidUtils#validateUUID(String)}. | ||||||
|  |      */ | ||||||
|  |     UuidString, | ||||||
| } | } | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ public class ApiConstants { | |||||||
|     public static final String ACCOUNTS = "accounts"; |     public static final String ACCOUNTS = "accounts"; | ||||||
|     public static final String ACCOUNT_TYPE = "accounttype"; |     public static final String ACCOUNT_TYPE = "accounttype"; | ||||||
|     public static final String ACCOUNT_ID = "accountid"; |     public static final String ACCOUNT_ID = "accountid"; | ||||||
|  |     public static final String ACCUMULATE = "accumulate"; | ||||||
|     public static final String ACTIVITY = "activity"; |     public static final String ACTIVITY = "activity"; | ||||||
|     public static final String ADAPTER_TYPE = "adaptertype"; |     public static final String ADAPTER_TYPE = "adaptertype"; | ||||||
|     public static final String ADDRESS = "address"; |     public static final String ADDRESS = "address"; | ||||||
|  | |||||||
| @ -137,6 +137,11 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd { | |||||||
|             description = "flag to display the resource icon for VMs", since = "4.16.0.0") |             description = "flag to display the resource icon for VMs", since = "4.16.0.0") | ||||||
|     private Boolean showIcon; |     private Boolean showIcon; | ||||||
| 
 | 
 | ||||||
|  |     @Parameter(name = ApiConstants.ACCUMULATE, type = CommandType.BOOLEAN, | ||||||
|  |             description = "Accumulates the VM metrics data instead of returning only the most recent data collected. The default behavior is set by the global configuration vm.stats.increment.metrics.", | ||||||
|  |             since = "4.17.0") | ||||||
|  |     private Boolean accumulate; | ||||||
|  | 
 | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|     /////////////////// Accessors /////////////////////// |     /////////////////// Accessors /////////////////////// | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
| @ -245,6 +250,10 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd { | |||||||
|         return showIcon != null ? showIcon : false; |         return showIcon != null ? showIcon : false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public Boolean getAccumulate() { | ||||||
|  |         return accumulate; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|     /////////////// API Implementation/////////////////// |     /////////////// API Implementation/////////////////// | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|  | |||||||
| @ -0,0 +1,147 @@ | |||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | package org.apache.cloudstack.api.response; | ||||||
|  | 
 | ||||||
|  | import java.util.Date; | ||||||
|  | 
 | ||||||
|  | import org.apache.cloudstack.api.ApiConstants; | ||||||
|  | import org.apache.cloudstack.api.BaseResponse; | ||||||
|  | 
 | ||||||
|  | import com.cloud.serializer.Param; | ||||||
|  | import com.google.gson.annotations.SerializedName; | ||||||
|  | 
 | ||||||
|  | public class StatsResponse extends BaseResponse { | ||||||
|  | 
 | ||||||
|  |     @SerializedName("timestamp") | ||||||
|  |     @Param(description = "the time when the VM stats were collected. The format is \"yyyy-MM-dd hh:mm:ss\"") | ||||||
|  |     private Date timestamp; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("cpuused") | ||||||
|  |     @Param(description = "the amount (percentage) of the VM's CPU currently used") | ||||||
|  |     private String cpuUsed; | ||||||
|  | 
 | ||||||
|  |     @SerializedName(ApiConstants.DISK_IO_READ) | ||||||
|  |     @Param(description = "the VM's disk read (IO)") | ||||||
|  |     protected Long diskIORead; | ||||||
|  | 
 | ||||||
|  |     @SerializedName(ApiConstants.DISK_IO_WRITE) | ||||||
|  |     @Param(description = "the VM's disk write (IO)") | ||||||
|  |     protected Long diskIOWrite; | ||||||
|  | 
 | ||||||
|  |     @SerializedName(ApiConstants.DISK_IO_PSTOTAL) | ||||||
|  |     @Param(description = "the total disk iops") | ||||||
|  |     protected Long diskIopsTotal = 0L; | ||||||
|  | 
 | ||||||
|  |     @SerializedName(ApiConstants.DISK_KBS_READ) | ||||||
|  |     @Param(description = "the VM's disk read (bytes)") | ||||||
|  |     private Long diskKbsRead; | ||||||
|  | 
 | ||||||
|  |     @SerializedName(ApiConstants.DISK_KBS_WRITE) | ||||||
|  |     @Param(description = "the VM's disk write (bytes)") | ||||||
|  |     private Long diskKbsWrite; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("memoryintfreekbs") | ||||||
|  |     @Param(description = "the internal memory free of the VM or zero if it cannot be calculated") | ||||||
|  |     private Long memoryIntFreeKBs; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("memorykbs") | ||||||
|  |     @Param(description = "the memory used by the VM in Kbps") | ||||||
|  |     private Long memoryKBs; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("memorytargetkbs") | ||||||
|  |     @Param(description = "the target memory in VM in Kbps") | ||||||
|  |     private Long memoryTargetKBs; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("networkkbsread") | ||||||
|  |     @Param(description = "the incoming network traffic on the VM") | ||||||
|  |     protected Long networkKbsRead; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("networkkbswrite") | ||||||
|  |     @Param(description = "the outgoing network traffic on the host") | ||||||
|  |     protected Long networkKbsWrite; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("networkread") | ||||||
|  |     @Param(description = "the network read in MiB") | ||||||
|  |     protected String networkRead; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("networkwrite") | ||||||
|  |     @Param(description = "the network write in MiB") | ||||||
|  |     protected String networkWrite; | ||||||
|  | 
 | ||||||
|  |     public void setTimestamp(Date timestamp) { | ||||||
|  |         this.timestamp = timestamp; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setCpuUsed(String cpuUsed) { | ||||||
|  |         this.cpuUsed = cpuUsed; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDiskIORead(Long diskIORead) { | ||||||
|  |         this.diskIORead = diskIORead; | ||||||
|  |         accumulateDiskIopsTotal(diskIORead); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDiskIOWrite(Long diskIOWrite) { | ||||||
|  |         this.diskIOWrite = diskIOWrite; | ||||||
|  |         accumulateDiskIopsTotal(diskIOWrite); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDiskKbsRead(Long diskKbsRead) { | ||||||
|  |         this.diskKbsRead = diskKbsRead; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDiskKbsWrite(Long diskKbsWrite) { | ||||||
|  |         this.diskKbsWrite = diskKbsWrite; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setMemoryIntFreeKBs(Long memoryIntFreeKBs) { | ||||||
|  |         this.memoryIntFreeKBs = memoryIntFreeKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setMemoryKBs(Long memoryKBs) { | ||||||
|  |         this.memoryKBs = memoryKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setMemoryTargetKBs(Long memoryTargetKBs) { | ||||||
|  |         this.memoryTargetKBs = memoryTargetKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setNetworkKbsRead(Long networkKbsRead) { | ||||||
|  |         this.networkKbsRead = networkKbsRead; | ||||||
|  |         if (networkKbsRead != null) { | ||||||
|  |             this.networkRead = String.format("%.2f MB", networkKbsRead / 1024.0); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setNetworkKbsWrite(Long networkKbsWrite) { | ||||||
|  |         this.networkKbsWrite = networkKbsWrite; | ||||||
|  |         if (networkKbsWrite != null) { | ||||||
|  |             this.networkWrite = String.format("%.2f MB", networkKbsWrite / 1024.0); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Accumulates disk IOPS (Input/Output Operations Per Second) | ||||||
|  |      * in {@code diskIopsTotal} attribute. | ||||||
|  |      * @param diskIo the IOPS value to increment in {@code diskIopsTotal}. | ||||||
|  |      */ | ||||||
|  |     protected void accumulateDiskIopsTotal(Long diskIo) { | ||||||
|  |         if (diskIo != null) { | ||||||
|  |             this.diskIopsTotal += diskIo; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,135 @@ | |||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | package org.apache.cloudstack.api.response; | ||||||
|  | 
 | ||||||
|  | import java.text.DecimalFormat; | ||||||
|  | 
 | ||||||
|  | import org.junit.Assert; | ||||||
|  | import org.junit.Test; | ||||||
|  | import org.junit.runner.RunWith; | ||||||
|  | import org.mockito.Mockito; | ||||||
|  | import org.mockito.Spy; | ||||||
|  | import org.mockito.junit.MockitoJUnitRunner; | ||||||
|  | 
 | ||||||
|  | @RunWith(MockitoJUnitRunner.class) | ||||||
|  | public class StatsResponseTest { | ||||||
|  | 
 | ||||||
|  |     @Spy | ||||||
|  |     StatsResponse statsResponseMock; | ||||||
|  | 
 | ||||||
|  |     final char decimalSeparator = ((DecimalFormat) DecimalFormat.getInstance()).getDecimalFormatSymbols().getDecimalSeparator(); | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void setDiskIOReadTestWithAnyInput() { | ||||||
|  |         statsResponseMock.setDiskIORead(1L); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(statsResponseMock).accumulateDiskIopsTotal(Mockito.anyLong()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void setDiskIOWriteTestWithAnyInput() { | ||||||
|  |         statsResponseMock.setDiskIOWrite(1L); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(statsResponseMock).accumulateDiskIopsTotal(Mockito.anyLong()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void accumulateDiskIopsTotalTestWithNullInput() { | ||||||
|  |         Long expected = 0L; | ||||||
|  | 
 | ||||||
|  |         statsResponseMock.accumulateDiskIopsTotal(null); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(expected, statsResponseMock.diskIopsTotal); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void accumulateDiskIopsTotalTestWithZeroAsInput() { | ||||||
|  |         Long expected = 0L; | ||||||
|  | 
 | ||||||
|  |         statsResponseMock.accumulateDiskIopsTotal(0L); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(expected, statsResponseMock.diskIopsTotal); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void accumulateDiskIopsTotalTestWithInputGreatherThanZero() { | ||||||
|  |         Long expected = 1L; | ||||||
|  | 
 | ||||||
|  |         statsResponseMock.accumulateDiskIopsTotal(1L); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(expected, statsResponseMock.diskIopsTotal); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void setDiskIOWriteTestWithInputNotNullAndNullDiskIopsTotal() { | ||||||
|  |         Long expected = 1L; | ||||||
|  | 
 | ||||||
|  |         statsResponseMock.setDiskIOWrite(expected); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(expected, statsResponseMock.diskIOWrite); | ||||||
|  |         Assert.assertEquals(expected, statsResponseMock.diskIopsTotal); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void setDiskIOWriteTestWithInputNotNullAndDiskIopsTotalNotNull() { | ||||||
|  |         statsResponseMock.diskIopsTotal = 1L; | ||||||
|  |         Long expectedDiskIOWrite = 1L, expectedDiskIopsTotal = 2L; | ||||||
|  | 
 | ||||||
|  |         statsResponseMock.setDiskIOWrite(1L); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(expectedDiskIOWrite, statsResponseMock.diskIOWrite); | ||||||
|  |         Assert.assertEquals(expectedDiskIopsTotal, statsResponseMock.diskIopsTotal); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void setNetworkKbsReadTestWithNullInput() { | ||||||
|  |         statsResponseMock.setNetworkKbsRead(null); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(null, statsResponseMock.networkKbsRead); | ||||||
|  |         Assert.assertEquals(null, statsResponseMock.networkRead); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void setNetworkKbsReadTestWithInputNotNull() { | ||||||
|  |         Long expectedNetworkKbsRead = Long.valueOf("100"); | ||||||
|  |         String expectedNetworkRead = String.format("0%s10 MB", decimalSeparator); // the actual result is 0.097 but the value is rounded to 0.10 | ||||||
|  | 
 | ||||||
|  |         statsResponseMock.setNetworkKbsRead(expectedNetworkKbsRead); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(expectedNetworkKbsRead, statsResponseMock.networkKbsRead); | ||||||
|  |         Assert.assertEquals(expectedNetworkRead, statsResponseMock.networkRead); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void setNetworkKbsWriteTestWithNullInput() { | ||||||
|  |         statsResponseMock.setNetworkKbsWrite(null); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(null, statsResponseMock.networkKbsWrite); | ||||||
|  |         Assert.assertEquals(null, statsResponseMock.networkWrite); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void setNetworkKbsWriteTestWithInputNotNull() { | ||||||
|  |         Long expectedNetworkKbsWrite = Long.valueOf("100"); | ||||||
|  |         String expectedNetworkWrite = String.format("0%s10 MB", decimalSeparator); // the actual result is 0.097 but the value is rounded to 0.10 | ||||||
|  | 
 | ||||||
|  |         statsResponseMock.setNetworkKbsWrite(expectedNetworkKbsWrite); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(expectedNetworkKbsWrite, statsResponseMock.networkKbsWrite); | ||||||
|  |         Assert.assertEquals(expectedNetworkWrite, statsResponseMock.networkWrite); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -20,151 +20,36 @@ | |||||||
| package com.cloud.agent.api; | package com.cloud.agent.api; | ||||||
| 
 | 
 | ||||||
| import com.cloud.vm.UserVmVO; | import com.cloud.vm.UserVmVO; | ||||||
| import com.cloud.vm.VmStats; |  | ||||||
| 
 | 
 | ||||||
| public class VmStatsEntry implements VmStats { | public class VmStatsEntry extends VmStatsEntryBase { | ||||||
| 
 | 
 | ||||||
|     private long vmId; |  | ||||||
|     private UserVmVO userVmVO; |     private UserVmVO userVmVO; | ||||||
|     private double cpuUtilization; |  | ||||||
|     private double networkReadKBs; |  | ||||||
|     private double networkWriteKBs; |  | ||||||
|     private double diskReadIOs; |  | ||||||
|     private double diskWriteIOs; |  | ||||||
|     private double diskReadKBs; |  | ||||||
|     private double diskWriteKBs; |  | ||||||
|     private double memoryKBs; |  | ||||||
|     private double intfreememoryKBs; |  | ||||||
|     private double targetmemoryKBs; |  | ||||||
|     private int numCPUs; |  | ||||||
|     private String entityType; |  | ||||||
| 
 | 
 | ||||||
|     public VmStatsEntry() { |     public VmStatsEntry() { | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public VmStatsEntry(double memoryKBs,double intfreememoryKBs,double targetmemoryKBs, double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, String entityType) { |     /** | ||||||
|         this.memoryKBs = memoryKBs; |      * Creates an instance of {@code VmStatsEntry} with all the stats attributes filled in. | ||||||
|         this.intfreememoryKBs = intfreememoryKBs; |      * | ||||||
|         this.targetmemoryKBs = targetmemoryKBs; |      * @param vmId the VM ID. | ||||||
|         this.cpuUtilization = cpuUtilization; |      * @param memoryKBs the memory total (in KBs). | ||||||
|         this.networkReadKBs = networkReadKBs; |      * @param intFreeMemoryKBs the internal free memory (in KBs). | ||||||
|         this.networkWriteKBs = networkWriteKBs; |      * @param targetMemoryKBs the target memory (in KBs). | ||||||
|         this.numCPUs = numCPUs; |      * @param cpuUtilization the CPU utilization. | ||||||
|         this.entityType = entityType; |      * @param networkReadKBs the network read (in KBs). | ||||||
|     } |      * @param networkWriteKBs the network write (in KBs). | ||||||
| 
 |      * @param numCPUs the number of CPUs. | ||||||
|     public long getVmId() { |      * @param diskReadKBs the disk read (in KBs). | ||||||
|         return vmId; |      * @param diskWriteKBs the disk write (in KBs). | ||||||
|     } |      * @param diskReadIOs the disk read I/O. | ||||||
| 
 |      * @param diskWriteIOs the disk write I/O. | ||||||
|     public void setVmId(long vmId) { |      * @param entityType the entity type. | ||||||
|         this.vmId = vmId; |      */ | ||||||
|     } |     public VmStatsEntry(long vmId, double memoryKBs, double intFreeMemoryKBs, double targetMemoryKBs, double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, | ||||||
| 
 |             double diskReadKBs, double diskWriteKBs, double diskReadIOs, double diskWriteIOs, String entityType) { | ||||||
|     @Override |         super(vmId, memoryKBs, intFreeMemoryKBs, targetMemoryKBs, cpuUtilization, networkReadKBs, networkWriteKBs, numCPUs, diskReadKBs, diskWriteKBs, diskReadIOs, diskWriteIOs, | ||||||
|     public double getCPUUtilization() { |                 entityType); | ||||||
|         return cpuUtilization; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setCPUUtilization(double cpuUtilization) { |  | ||||||
|         this.cpuUtilization = cpuUtilization; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getNetworkReadKBs() { |  | ||||||
|         return networkReadKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setNetworkReadKBs(double networkReadKBs) { |  | ||||||
|         this.networkReadKBs = networkReadKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getNetworkWriteKBs() { |  | ||||||
|         return networkWriteKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setNetworkWriteKBs(double networkWriteKBs) { |  | ||||||
|         this.networkWriteKBs = networkWriteKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getDiskReadIOs() { |  | ||||||
|         return diskReadIOs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setDiskReadIOs(double diskReadIOs) { |  | ||||||
|         this.diskReadIOs = diskReadIOs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getDiskWriteIOs() { |  | ||||||
|         return diskWriteIOs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setDiskWriteIOs(double diskWriteIOs) { |  | ||||||
|         this.diskWriteIOs = diskWriteIOs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getDiskReadKBs() { |  | ||||||
|         return diskReadKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setDiskReadKBs(double diskReadKBs) { |  | ||||||
|         this.diskReadKBs = diskReadKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getDiskWriteKBs() { |  | ||||||
|         return diskWriteKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setDiskWriteKBs(double diskWriteKBs) { |  | ||||||
|         this.diskWriteKBs = diskWriteKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getMemoryKBs() { |  | ||||||
|         return memoryKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setMemoryKBs(double memoryKBs) { |  | ||||||
|         this.memoryKBs = memoryKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getIntFreeMemoryKBs() { |  | ||||||
|         return intfreememoryKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setIntFreeMemoryKBs(double intfreememoryKBs) { |  | ||||||
|         this.intfreememoryKBs = intfreememoryKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public double getTargetMemoryKBs() { |  | ||||||
|         return targetmemoryKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setTargetMemoryKBs(double targetmemoryKBs) { |  | ||||||
|         this.targetmemoryKBs = targetmemoryKBs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public int getNumCPUs() { |  | ||||||
|         return numCPUs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setNumCPUs(int numCPUs) { |  | ||||||
|         this.numCPUs = numCPUs; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public String getEntityType() { |  | ||||||
|         return this.entityType; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setEntityType(String entityType) { |  | ||||||
|         this.entityType = entityType; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public UserVmVO getUserVmVO() { |     public UserVmVO getUserVmVO() { | ||||||
|  | |||||||
							
								
								
									
										192
									
								
								core/src/main/java/com/cloud/agent/api/VmStatsEntryBase.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								core/src/main/java/com/cloud/agent/api/VmStatsEntryBase.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,192 @@ | |||||||
|  | // | ||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | // | ||||||
|  | 
 | ||||||
|  | package com.cloud.agent.api; | ||||||
|  | 
 | ||||||
|  | import com.cloud.vm.VmStats; | ||||||
|  | 
 | ||||||
|  | public class VmStatsEntryBase implements VmStats { | ||||||
|  | 
 | ||||||
|  |     private long vmId; | ||||||
|  |     private double cpuUtilization; | ||||||
|  |     private double networkReadKBs; | ||||||
|  |     private double networkWriteKBs; | ||||||
|  |     private double diskReadIOs; | ||||||
|  |     private double diskWriteIOs; | ||||||
|  |     private double diskReadKBs; | ||||||
|  |     private double diskWriteKBs; | ||||||
|  |     private double memoryKBs; | ||||||
|  |     private double intFreeMemoryKBs; | ||||||
|  |     private double targetMemoryKBs; | ||||||
|  |     private int numCPUs; | ||||||
|  |     private String entityType; | ||||||
|  | 
 | ||||||
|  |     public VmStatsEntryBase() { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Creates an instance of {@code VmStatsEntryBase} with all the stats attributes filled in. | ||||||
|  |      * | ||||||
|  |      * @param memoryKBs the memory total (in KBs). | ||||||
|  |      * @param intFreeMemoryKBs the internal free memory (in KBs). | ||||||
|  |      * @param targetMemoryKBs the target memory (in KBs). | ||||||
|  |      * @param cpuUtilization the CPU utilization. | ||||||
|  |      * @param networkReadKBs the network read (in KBs). | ||||||
|  |      * @param networkWriteKBs the network write (in KBs). | ||||||
|  |      * @param numCPUs the number of CPUs. | ||||||
|  |      * @param diskReadKBs the disk read (in KBs). | ||||||
|  |      * @param diskWriteKBs the disk write (in KBs). | ||||||
|  |      * @param diskReadIOs the disk read I/O. | ||||||
|  |      * @param diskWriteIOs the disk write I/O. | ||||||
|  |      * @param entityType the entity type. | ||||||
|  |      */ | ||||||
|  |     public VmStatsEntryBase(long vmId, double memoryKBs, double intFreeMemoryKBs, double targetMemoryKBs, double cpuUtilization, double networkReadKBs, double networkWriteKBs, int numCPUs, | ||||||
|  |             double diskReadKBs, double diskWriteKBs, double diskReadIOs, double diskWriteIOs, String entityType) { | ||||||
|  |         this.vmId = vmId; | ||||||
|  |         this.memoryKBs = memoryKBs; | ||||||
|  |         this.intFreeMemoryKBs = intFreeMemoryKBs; | ||||||
|  |         this.targetMemoryKBs = targetMemoryKBs; | ||||||
|  |         this.cpuUtilization = cpuUtilization; | ||||||
|  |         this.networkReadKBs = networkReadKBs; | ||||||
|  |         this.networkWriteKBs = networkWriteKBs; | ||||||
|  |         this.numCPUs = numCPUs; | ||||||
|  |         this.diskReadKBs = diskReadKBs; | ||||||
|  |         this.diskWriteKBs = diskWriteKBs; | ||||||
|  |         this.diskReadIOs = diskReadIOs; | ||||||
|  |         this.diskWriteIOs = diskWriteIOs; | ||||||
|  |         this.entityType = entityType; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public long getVmId() { | ||||||
|  |         return vmId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setVmId(long vmId) { | ||||||
|  |         this.vmId = vmId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getCPUUtilization() { | ||||||
|  |         return cpuUtilization; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setCPUUtilization(double cpuUtilization) { | ||||||
|  |         this.cpuUtilization = cpuUtilization; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getNetworkReadKBs() { | ||||||
|  |         return networkReadKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setNetworkReadKBs(double networkReadKBs) { | ||||||
|  |         this.networkReadKBs = networkReadKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getNetworkWriteKBs() { | ||||||
|  |         return networkWriteKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setNetworkWriteKBs(double networkWriteKBs) { | ||||||
|  |         this.networkWriteKBs = networkWriteKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getDiskReadIOs() { | ||||||
|  |         return diskReadIOs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDiskReadIOs(double diskReadIOs) { | ||||||
|  |         this.diskReadIOs = diskReadIOs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getDiskWriteIOs() { | ||||||
|  |         return diskWriteIOs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDiskWriteIOs(double diskWriteIOs) { | ||||||
|  |         this.diskWriteIOs = diskWriteIOs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getDiskReadKBs() { | ||||||
|  |         return diskReadKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDiskReadKBs(double diskReadKBs) { | ||||||
|  |         this.diskReadKBs = diskReadKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getDiskWriteKBs() { | ||||||
|  |         return diskWriteKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDiskWriteKBs(double diskWriteKBs) { | ||||||
|  |         this.diskWriteKBs = diskWriteKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getMemoryKBs() { | ||||||
|  |         return memoryKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setMemoryKBs(double memoryKBs) { | ||||||
|  |         this.memoryKBs = memoryKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getIntFreeMemoryKBs() { | ||||||
|  |         return intFreeMemoryKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setIntFreeMemoryKBs(double intFreeMemoryKBs) { | ||||||
|  |         this.intFreeMemoryKBs = intFreeMemoryKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public double getTargetMemoryKBs() { | ||||||
|  |         return targetMemoryKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setTargetMemoryKBs(double targetMemoryKBs) { | ||||||
|  |         this.targetMemoryKBs = targetMemoryKBs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getNumCPUs() { | ||||||
|  |         return numCPUs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setNumCPUs(int numCPUs) { | ||||||
|  |         this.numCPUs = numCPUs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getEntityType() { | ||||||
|  |         return this.entityType; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setEntityType(String entityType) { | ||||||
|  |         this.entityType = entityType; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								engine/schema/src/main/java/com/cloud/vm/VmStatsVO.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								engine/schema/src/main/java/com/cloud/vm/VmStatsVO.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | |||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | package com.cloud.vm; | ||||||
|  | 
 | ||||||
|  | import java.util.Date; | ||||||
|  | 
 | ||||||
|  | import javax.persistence.Column; | ||||||
|  | import javax.persistence.Entity; | ||||||
|  | import javax.persistence.Id; | ||||||
|  | import javax.persistence.Table; | ||||||
|  | import javax.persistence.Temporal; | ||||||
|  | import javax.persistence.TemporalType; | ||||||
|  | 
 | ||||||
|  | import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils; | ||||||
|  | 
 | ||||||
|  | @Entity | ||||||
|  | @Table(name = "vm_stats") | ||||||
|  | public class VmStatsVO { | ||||||
|  | 
 | ||||||
|  |     @Id | ||||||
|  |     @Column(name = "id", updatable = false, nullable = false) | ||||||
|  |     protected long id; | ||||||
|  | 
 | ||||||
|  |     @Column(name = "vm_id", updatable = false, nullable = false) | ||||||
|  |     protected Long vmId; | ||||||
|  | 
 | ||||||
|  |     @Column(name = "mgmt_server_id", updatable = false, nullable = false) | ||||||
|  |     protected Long mgmtServerId; | ||||||
|  | 
 | ||||||
|  |     @Column(name= "timestamp", updatable = false) | ||||||
|  |     @Temporal(value = TemporalType.TIMESTAMP) | ||||||
|  |     protected Date timestamp; | ||||||
|  | 
 | ||||||
|  |     @Column(name = "vm_stats_data", updatable = false, nullable = false, length = 65535) | ||||||
|  |     protected String vmStatsData; | ||||||
|  | 
 | ||||||
|  |     public VmStatsVO(Long vmId, Long mgmtServerId, Date timestamp, String vmStatsData) { | ||||||
|  |         this.vmId = vmId; | ||||||
|  |         this.mgmtServerId = mgmtServerId; | ||||||
|  |         this.timestamp = timestamp; | ||||||
|  |         this.vmStatsData = vmStatsData; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public VmStatsVO() { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public long getId() { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Long getVmId() { | ||||||
|  |         return vmId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Long getMgmtServerId() { | ||||||
|  |         return mgmtServerId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Date getTimestamp() { | ||||||
|  |         return timestamp; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getVmStatsData() { | ||||||
|  |         return vmStatsData; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String toString() { | ||||||
|  |         return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "vmId", "mgmtServerId", "timestamp", "vmStatsData"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										82
									
								
								engine/schema/src/main/java/com/cloud/vm/dao/VmStatsDao.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								engine/schema/src/main/java/com/cloud/vm/dao/VmStatsDao.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,82 @@ | |||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | package com.cloud.vm.dao; | ||||||
|  | 
 | ||||||
|  | import java.util.Date; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import com.cloud.utils.db.GenericDao; | ||||||
|  | import com.cloud.vm.VmStatsVO; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Data Access Object for vm_stats table. | ||||||
|  |  */ | ||||||
|  | public interface VmStatsDao extends GenericDao<VmStatsVO, Long> { | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Finds VM stats by VM ID. | ||||||
|  |      * @param vmId the VM ID. | ||||||
|  |      * @return list of stats for the specified VM. | ||||||
|  |      */ | ||||||
|  |     List<VmStatsVO> findByVmId(long vmId); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Finds VM stats by VM ID. The result is sorted by timestamp in descending order. | ||||||
|  |      * @param vmId the VM ID. | ||||||
|  |      * @return ordered list of stats for the specified VM. | ||||||
|  |      */ | ||||||
|  |     List<VmStatsVO> findByVmIdOrderByTimestampDesc(long vmId); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Finds stats by VM ID and timestamp >= a given time. | ||||||
|  |      * @param vmId the specific VM. | ||||||
|  |      * @param time the specific time. | ||||||
|  |      * @return list of stats for the specified VM, with timestamp >= the specified time. | ||||||
|  |      */ | ||||||
|  |     List<VmStatsVO> findByVmIdAndTimestampGreaterThanEqual(long vmId, Date time); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Finds stats by VM ID and timestamp <= a given time. | ||||||
|  |      * @param vmId the specific VM. | ||||||
|  |      * @param time the specific time. | ||||||
|  |      * @return list of stats for the specified VM, with timestamp <= the specified time. | ||||||
|  |      */ | ||||||
|  |     List<VmStatsVO> findByVmIdAndTimestampLessThanEqual(long vmId, Date time); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Finds stats by VM ID and timestamp between a given time range. | ||||||
|  |      * @param vmId the specific VM. | ||||||
|  |      * @param startTime the start time. | ||||||
|  |      * @param endTime the start time. | ||||||
|  |      * @return list of stats for the specified VM, between the specified start and end times. | ||||||
|  |      */ | ||||||
|  |     List<VmStatsVO> findByVmIdAndTimestampBetween(long vmId, Date startTime, Date endTime); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Removes (expunges) all stats of the specified VM. | ||||||
|  |      * @param vmId the VM ID to remove stats. | ||||||
|  |      */ | ||||||
|  |     void removeAllByVmId(long vmId); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Removes (expunges) all VM stats with {@code timestamp} less than | ||||||
|  |      * a given Date. | ||||||
|  |      * @param limit the maximum date to keep stored. Records that exceed this limit will be removed. | ||||||
|  |      */ | ||||||
|  |     void removeAllByTimestampLessThan(Date limit); | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										122
									
								
								engine/schema/src/main/java/com/cloud/vm/dao/VmStatsDaoImpl.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								engine/schema/src/main/java/com/cloud/vm/dao/VmStatsDaoImpl.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,122 @@ | |||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | package com.cloud.vm.dao; | ||||||
|  | 
 | ||||||
|  | import java.util.Date; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import javax.annotation.PostConstruct; | ||||||
|  | 
 | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | 
 | ||||||
|  | import com.cloud.utils.db.Filter; | ||||||
|  | import com.cloud.utils.db.GenericDaoBase; | ||||||
|  | import com.cloud.utils.db.SearchBuilder; | ||||||
|  | import com.cloud.utils.db.SearchCriteria; | ||||||
|  | import com.cloud.utils.db.SearchCriteria.Op; | ||||||
|  | import com.cloud.vm.VmStatsVO; | ||||||
|  | 
 | ||||||
|  | @Component | ||||||
|  | public class VmStatsDaoImpl extends GenericDaoBase<VmStatsVO, Long> implements VmStatsDao { | ||||||
|  | 
 | ||||||
|  |     protected SearchBuilder<VmStatsVO> vmIdSearch; | ||||||
|  |     protected SearchBuilder<VmStatsVO> vmIdTimestampGreaterThanEqualSearch; | ||||||
|  |     protected SearchBuilder<VmStatsVO> vmIdTimestampLessThanEqualSearch; | ||||||
|  |     protected SearchBuilder<VmStatsVO> vmIdTimestampBetweenSearch; | ||||||
|  |     protected SearchBuilder<VmStatsVO> timestampSearch; | ||||||
|  | 
 | ||||||
|  |     @PostConstruct | ||||||
|  |     protected void init() { | ||||||
|  |         vmIdSearch = createSearchBuilder(); | ||||||
|  |         vmIdSearch.and("vmId", vmIdSearch.entity().getVmId(), Op.EQ); | ||||||
|  |         vmIdSearch.done(); | ||||||
|  | 
 | ||||||
|  |         vmIdTimestampGreaterThanEqualSearch = createSearchBuilder(); | ||||||
|  |         vmIdTimestampGreaterThanEqualSearch.and("vmId", vmIdTimestampGreaterThanEqualSearch.entity().getVmId(), Op.EQ); | ||||||
|  |         vmIdTimestampGreaterThanEqualSearch.and("timestamp", vmIdTimestampGreaterThanEqualSearch.entity().getTimestamp(), Op.GTEQ); | ||||||
|  |         vmIdTimestampGreaterThanEqualSearch.done(); | ||||||
|  | 
 | ||||||
|  |         vmIdTimestampLessThanEqualSearch = createSearchBuilder(); | ||||||
|  |         vmIdTimestampLessThanEqualSearch.and("vmId", vmIdTimestampLessThanEqualSearch.entity().getVmId(), Op.EQ); | ||||||
|  |         vmIdTimestampLessThanEqualSearch.and("timestamp", vmIdTimestampLessThanEqualSearch.entity().getTimestamp(), Op.LTEQ); | ||||||
|  |         vmIdTimestampLessThanEqualSearch.done(); | ||||||
|  | 
 | ||||||
|  |         vmIdTimestampBetweenSearch = createSearchBuilder(); | ||||||
|  |         vmIdTimestampBetweenSearch.and("vmId", vmIdTimestampBetweenSearch.entity().getVmId(), Op.EQ); | ||||||
|  |         vmIdTimestampBetweenSearch.and("timestamp", vmIdTimestampBetweenSearch.entity().getTimestamp(), Op.BETWEEN); | ||||||
|  |         vmIdTimestampBetweenSearch.done(); | ||||||
|  | 
 | ||||||
|  |         timestampSearch = createSearchBuilder(); | ||||||
|  |         timestampSearch.and("timestamp", timestampSearch.entity().getTimestamp(), Op.LT); | ||||||
|  |         timestampSearch.done(); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<VmStatsVO> findByVmId(long vmId) { | ||||||
|  |         SearchCriteria<VmStatsVO> sc = vmIdSearch.create(); | ||||||
|  |         sc.setParameters("vmId", vmId); | ||||||
|  |         return listBy(sc); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<VmStatsVO> findByVmIdOrderByTimestampDesc(long vmId) { | ||||||
|  |         SearchCriteria<VmStatsVO> sc = vmIdSearch.create(); | ||||||
|  |         sc.setParameters("vmId", vmId); | ||||||
|  |         Filter orderByFilter = new Filter(VmStatsVO.class, "timestamp", false, null, null); | ||||||
|  |         return search(sc, orderByFilter, null, false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<VmStatsVO> findByVmIdAndTimestampGreaterThanEqual(long vmId, Date time) { | ||||||
|  |         SearchCriteria<VmStatsVO> sc = vmIdTimestampGreaterThanEqualSearch.create(); | ||||||
|  |         sc.setParameters("vmId", vmId); | ||||||
|  |         sc.setParameters("timestamp", time); | ||||||
|  |         return listBy(sc); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<VmStatsVO> findByVmIdAndTimestampLessThanEqual(long vmId, Date time) { | ||||||
|  |         SearchCriteria<VmStatsVO> sc = vmIdTimestampLessThanEqualSearch.create(); | ||||||
|  |         sc.setParameters("vmId", vmId); | ||||||
|  |         sc.setParameters("timestamp", time); | ||||||
|  |         return listBy(sc); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<VmStatsVO> findByVmIdAndTimestampBetween(long vmId, Date startTime, Date endTime) { | ||||||
|  |         SearchCriteria<VmStatsVO> sc = vmIdTimestampBetweenSearch.create(); | ||||||
|  |         sc.setParameters("vmId", vmId); | ||||||
|  |         sc.setParameters("timestamp", startTime, endTime); | ||||||
|  |         return listBy(sc); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void removeAllByVmId(long vmId) { | ||||||
|  |         SearchCriteria<VmStatsVO> sc = vmIdSearch.create(); | ||||||
|  |         sc.setParameters("vmId", vmId); | ||||||
|  |         expunge(sc); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void removeAllByTimestampLessThan(Date limit) { | ||||||
|  |         SearchCriteria<VmStatsVO> sc = timestampSearch.create(); | ||||||
|  |         sc.setParameters("timestamp", limit); | ||||||
|  |         expunge(sc); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -239,6 +239,7 @@ | |||||||
|   <bean id="vMRootDiskTagDaoImpl" class="org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMRootDiskTagDaoImpl" /> |   <bean id="vMRootDiskTagDaoImpl" class="org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMRootDiskTagDaoImpl" /> | ||||||
|   <bean id="vMSnapshotDaoImpl" class="com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl" /> |   <bean id="vMSnapshotDaoImpl" class="com.cloud.vm.snapshot.dao.VMSnapshotDaoImpl" /> | ||||||
|   <bean id="vMSnapshotDetailsDaoImpl" class="com.cloud.vm.snapshot.dao.VMSnapshotDetailsDaoImpl" /> |   <bean id="vMSnapshotDetailsDaoImpl" class="com.cloud.vm.snapshot.dao.VMSnapshotDetailsDaoImpl" /> | ||||||
|  |   <bean id="vmStatsDaoImpl" class="com.cloud.vm.dao.VmStatsDaoImpl" /> | ||||||
|   <bean id="vMTemplateDetailsDaoImpl" class="com.cloud.storage.dao.VMTemplateDetailsDaoImpl" /> |   <bean id="vMTemplateDetailsDaoImpl" class="com.cloud.storage.dao.VMTemplateDetailsDaoImpl" /> | ||||||
|   <bean id="vMTemplatePoolDaoImpl" class="com.cloud.storage.dao.VMTemplatePoolDaoImpl" /> |   <bean id="vMTemplatePoolDaoImpl" class="com.cloud.storage.dao.VMTemplatePoolDaoImpl" /> | ||||||
|   <bean id="vMTemplateZoneDaoImpl" class="com.cloud.storage.dao.VMTemplateZoneDaoImpl" /> |   <bean id="vMTemplateZoneDaoImpl" class="com.cloud.storage.dao.VMTemplateZoneDaoImpl" /> | ||||||
|  | |||||||
| @ -655,3 +655,16 @@ INSERT INTO `cloud`.`user_vm_details`(`vm_id`, `name`, `value`) | |||||||
| ALTER TABLE `cloud`.`kubernetes_cluster` ADD COLUMN `security_group_id` bigint unsigned DEFAULT NULL, | ALTER TABLE `cloud`.`kubernetes_cluster` ADD COLUMN `security_group_id` bigint unsigned DEFAULT NULL, | ||||||
| ADD CONSTRAINT `fk_kubernetes_cluster__security_group_id` FOREIGN KEY `fk_kubernetes_cluster__security_group_id`(`security_group_id`) REFERENCES `security_group`(`id`) ON DELETE CASCADE; | ADD CONSTRAINT `fk_kubernetes_cluster__security_group_id` FOREIGN KEY `fk_kubernetes_cluster__security_group_id`(`security_group_id`) REFERENCES `security_group`(`id`) ON DELETE CASCADE; | ||||||
| 
 | 
 | ||||||
|  | -- PR#5984 Create table to persist VM stats. | ||||||
|  | DROP TABLE IF EXISTS `cloud`.`vm_stats`; | ||||||
|  | CREATE TABLE `cloud`.`vm_stats` ( | ||||||
|  |   `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', | ||||||
|  |   `vm_id` bigint unsigned NOT NULL, | ||||||
|  |   `mgmt_server_id` bigint unsigned NOT NULL, | ||||||
|  |   `timestamp` datetime NOT NULL, | ||||||
|  |   `vm_stats_data` text NOT NULL, | ||||||
|  |   PRIMARY KEY (`id`) | ||||||
|  |   ) ENGINE=InnoDB DEFAULT CHARSET=utf8; | ||||||
|  | 
 | ||||||
|  | -- PR#5984 Update name for global configuration vm.stats.increment.metrics | ||||||
|  | Update configuration set name='vm.stats.increment.metrics' where name='vm.stats.increment.metrics.in.memory'; | ||||||
|  | |||||||
| @ -319,7 +319,7 @@ public class MockVmManagerImpl extends ManagerBase implements MockVmManager { | |||||||
|         final HashMap<String, VmStatsEntry> vmStatsNameMap = new HashMap<String, VmStatsEntry>(); |         final HashMap<String, VmStatsEntry> vmStatsNameMap = new HashMap<String, VmStatsEntry>(); | ||||||
|         final List<String> vmNames = cmd.getVmNames(); |         final List<String> vmNames = cmd.getVmNames(); | ||||||
|         for (final String vmName : vmNames) { |         for (final String vmName : vmNames) { | ||||||
|             final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, "vm"); |             final VmStatsEntry entry = new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "vm"); | ||||||
|             entry.setNetworkReadKBs(32768); // default values 256 KBps |             entry.setNetworkReadKBs(32768); // default values 256 KBps | ||||||
|             entry.setNetworkWriteKBs(16384); |             entry.setNetworkWriteKBs(16384); | ||||||
|             entry.setCPUUtilization(10); |             entry.setCPUUtilization(10); | ||||||
|  | |||||||
| @ -6424,12 +6424,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa | |||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     final VmStatsEntry vmStats = new VmStatsEntry(NumberUtils.toDouble(memkb) * 1024, NumberUtils.toDouble(guestMemusage) * 1024, NumberUtils.toDouble(memlimit) * 1024, |                     final VmStatsEntry vmStats = new VmStatsEntry(0, NumberUtils.toDouble(memkb) * 1024, NumberUtils.toDouble(guestMemusage) * 1024, NumberUtils.toDouble(memlimit) * 1024, | ||||||
|                             maxCpuUsage, networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), "vm"); |                             maxCpuUsage, networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), diskReadKbs, diskWriteKbs, diskReadIops, diskWriteIops, "vm"); | ||||||
|                     vmStats.setDiskReadIOs(diskReadIops); |  | ||||||
|                     vmStats.setDiskWriteIOs(diskWriteIops); |  | ||||||
|                     vmStats.setDiskReadKBs(diskReadKbs); |  | ||||||
|                     vmStats.setDiskWriteKBs(diskWriteKbs); |  | ||||||
|                     vmResponseMap.put(name, vmStats); |                     vmResponseMap.put(name, vmStats); | ||||||
| 
 | 
 | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -3446,7 +3446,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe | |||||||
|         final HashMap<String, VmStatsEntry> vmResponseMap = new HashMap<String, VmStatsEntry>(); |         final HashMap<String, VmStatsEntry> vmResponseMap = new HashMap<String, VmStatsEntry>(); | ||||||
| 
 | 
 | ||||||
|         for (final String vmUUID : vmUUIDs) { |         for (final String vmUUID : vmUUIDs) { | ||||||
|             vmResponseMap.put(vmUUID, new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, "vm")); |             vmResponseMap.put(vmUUID, new VmStatsEntry(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "vm")); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         final Object[] rrdData = getRRDData(conn, 2); // call rrddata with 2 for |         final Object[] rrdData = getRRDData(conn, 2); // call rrddata with 2 for | ||||||
|  | |||||||
| @ -27,9 +27,23 @@ import org.apache.cloudstack.response.VmMetricsResponse; | |||||||
| import javax.inject.Inject; | import javax.inject.Inject; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * API supported for backward compatibility. Use the {@link ListVMsUsageHistoryCmd} API instead. <br> | ||||||
|  |  * The reasons for this are: <br> | ||||||
|  |  * <ul> | ||||||
|  |  *     <li>While API {@link ListVMsMetricsCmd} allows ACS users to get only the most recent stats data | ||||||
|  |  *     from VMs or their cumulative data, the {@link ListVMsUsageHistoryCmd} API allows getting historical | ||||||
|  |  *     data by filtering by specific VMs and periods.</li> | ||||||
|  |  *     <li>{@link ListVMsMetricsCmd} just extends the {@link ListVMsCmd} API, so it inherits all of | ||||||
|  |  *     its parameters, even if some of them are not suitable/useful for the API purpose.</li> | ||||||
|  |  *     <li>{@link ListVMsMetricsCmd} returns all VM information just like the {@link ListVMsCmd} API, | ||||||
|  |  *     although most of it is not suitable/useful for the API purpose.</li> | ||||||
|  |  * </ul> | ||||||
|  |  */ | ||||||
| @APICommand(name = ListVMsMetricsCmd.APINAME, description = "Lists VM metrics", responseObject = VmMetricsResponse.class, | @APICommand(name = ListVMsMetricsCmd.APINAME, description = "Lists VM metrics", responseObject = VmMetricsResponse.class, | ||||||
|         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full, |         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,  responseView = ResponseObject.ResponseView.Full, | ||||||
|         since = "4.9.3", authorized = {RoleType.Admin,  RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) |         since = "4.9.3", authorized = {RoleType.Admin,  RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) | ||||||
|  | @Deprecated(since = "4.17.0") | ||||||
| public class ListVMsMetricsCmd extends ListVMsCmd { | public class ListVMsMetricsCmd extends ListVMsCmd { | ||||||
|     public static final String APINAME = "listVirtualMachinesMetrics"; |     public static final String APINAME = "listVirtualMachinesMetrics"; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -0,0 +1,100 @@ | |||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | 
 | ||||||
|  | package org.apache.cloudstack.api; | ||||||
|  | 
 | ||||||
|  | import java.util.Date; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import javax.inject.Inject; | ||||||
|  | 
 | ||||||
|  | import org.apache.cloudstack.acl.RoleType; | ||||||
|  | import org.apache.cloudstack.api.response.ListResponse; | ||||||
|  | import org.apache.cloudstack.api.response.UserVmResponse; | ||||||
|  | import org.apache.cloudstack.metrics.MetricsService; | ||||||
|  | import org.apache.cloudstack.response.VmMetricsStatsResponse; | ||||||
|  | 
 | ||||||
|  | @APICommand(name = ListVMsUsageHistoryCmd.APINAME, description = "Lists VM stats", responseObject = VmMetricsStatsResponse.class, | ||||||
|  |         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.17", | ||||||
|  |         authorized = {RoleType.Admin,  RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) | ||||||
|  | public class ListVMsUsageHistoryCmd extends BaseListCmd { | ||||||
|  |     public static final String APINAME = "listVirtualMachinesUsageHistory"; | ||||||
|  | 
 | ||||||
|  |     @Inject | ||||||
|  |     private MetricsService metricsService; | ||||||
|  | 
 | ||||||
|  |     ///////////////////////////////////////////////////// | ||||||
|  |     //////////////// API parameters ///////////////////// | ||||||
|  |     ///////////////////////////////////////////////////// | ||||||
|  | 
 | ||||||
|  |     @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = UserVmResponse.class, description = "the ID of the virtual machine.") | ||||||
|  |     private Long id; | ||||||
|  | 
 | ||||||
|  |     @Parameter(name=ApiConstants.IDS, type=CommandType.LIST, collectionType=CommandType.UUID, entityType=UserVmResponse.class, description="the IDs of the virtual machines, mutually exclusive with id.") | ||||||
|  |     private List<Long> ids; | ||||||
|  | 
 | ||||||
|  |     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the virtual machine (a substring match is made against the parameter value returning the data for all matching VMs).") | ||||||
|  |     private String name; | ||||||
|  | 
 | ||||||
|  |     @Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, description = "start date to filter VM stats." | ||||||
|  |             + "Use format \"yyyy-MM-dd hh:mm:ss\")") | ||||||
|  |     private Date startDate; | ||||||
|  | 
 | ||||||
|  |     @Parameter(name = ApiConstants.END_DATE, type = CommandType.DATE, description = "end date to filter VM stats." | ||||||
|  |             + "Use format \"yyyy-MM-dd hh:mm:ss\")") | ||||||
|  |     private Date endDate; | ||||||
|  | 
 | ||||||
|  |     ///////////////////////////////////////////////////// | ||||||
|  |     /////////////////// Accessors /////////////////////// | ||||||
|  |     ///////////////////////////////////////////////////// | ||||||
|  | 
 | ||||||
|  |     public Long getId() { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Long> getIds() { | ||||||
|  |         return ids; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getName() { | ||||||
|  |         return name; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Date getStartDate() { | ||||||
|  |         return startDate; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Date getEndDate() { | ||||||
|  |         return endDate; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ///////////////////////////////////////////////////// | ||||||
|  |     /////////////// API Implementation/////////////////// | ||||||
|  |     ///////////////////////////////////////////////////// | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getCommandName() { | ||||||
|  |         return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void execute() { | ||||||
|  |         ListResponse<VmMetricsStatsResponse> response = metricsService.searchForVmMetricsStats(this); | ||||||
|  |         response.setResponseName(getCommandName()); | ||||||
|  |         setResponseObject(response); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -19,8 +19,11 @@ package org.apache.cloudstack.metrics; | |||||||
| 
 | 
 | ||||||
| import com.cloud.utils.Pair; | import com.cloud.utils.Pair; | ||||||
| import com.cloud.utils.component.PluggableService; | import com.cloud.utils.component.PluggableService; | ||||||
|  | 
 | ||||||
|  | import org.apache.cloudstack.api.ListVMsUsageHistoryCmd; | ||||||
| import org.apache.cloudstack.api.response.ClusterResponse; | import org.apache.cloudstack.api.response.ClusterResponse; | ||||||
| import org.apache.cloudstack.api.response.HostResponse; | import org.apache.cloudstack.api.response.HostResponse; | ||||||
|  | import org.apache.cloudstack.api.response.ListResponse; | ||||||
| import org.apache.cloudstack.api.response.StoragePoolResponse; | import org.apache.cloudstack.api.response.StoragePoolResponse; | ||||||
| import org.apache.cloudstack.api.response.UserVmResponse; | import org.apache.cloudstack.api.response.UserVmResponse; | ||||||
| import org.apache.cloudstack.api.response.VolumeResponse; | import org.apache.cloudstack.api.response.VolumeResponse; | ||||||
| @ -30,6 +33,7 @@ import org.apache.cloudstack.response.HostMetricsResponse; | |||||||
| import org.apache.cloudstack.response.InfrastructureResponse; | import org.apache.cloudstack.response.InfrastructureResponse; | ||||||
| import org.apache.cloudstack.response.StoragePoolMetricsResponse; | import org.apache.cloudstack.response.StoragePoolMetricsResponse; | ||||||
| import org.apache.cloudstack.response.VmMetricsResponse; | import org.apache.cloudstack.response.VmMetricsResponse; | ||||||
|  | import org.apache.cloudstack.response.VmMetricsStatsResponse; | ||||||
| import org.apache.cloudstack.response.VolumeMetricsResponse; | import org.apache.cloudstack.response.VolumeMetricsResponse; | ||||||
| import org.apache.cloudstack.response.ZoneMetricsResponse; | import org.apache.cloudstack.response.ZoneMetricsResponse; | ||||||
| 
 | 
 | ||||||
| @ -38,6 +42,7 @@ import java.util.List; | |||||||
| public interface MetricsService extends PluggableService { | public interface MetricsService extends PluggableService { | ||||||
|     InfrastructureResponse listInfrastructure(); |     InfrastructureResponse listInfrastructure(); | ||||||
| 
 | 
 | ||||||
|  |     ListResponse<VmMetricsStatsResponse> searchForVmMetricsStats(ListVMsUsageHistoryCmd cmd); | ||||||
|     List<VolumeMetricsResponse> listVolumeMetrics(List<VolumeResponse> volumeResponses); |     List<VolumeMetricsResponse> listVolumeMetrics(List<VolumeResponse> volumeResponses); | ||||||
|     List<VmMetricsResponse> listVmMetrics(List<UserVmResponse> vmResponses); |     List<VmMetricsResponse> listVmMetrics(List<UserVmResponse> vmResponses); | ||||||
|     List<StoragePoolMetricsResponse> listStoragePoolMetrics(List<StoragePoolResponse> poolResponses); |     List<StoragePoolMetricsResponse> listStoragePoolMetrics(List<StoragePoolResponse> poolResponses); | ||||||
|  | |||||||
| @ -18,8 +18,12 @@ | |||||||
| package org.apache.cloudstack.metrics; | package org.apache.cloudstack.metrics; | ||||||
| 
 | 
 | ||||||
| import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||||
|  | import java.text.DecimalFormat; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
|  | import java.util.Date; | ||||||
|  | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| 
 | 
 | ||||||
| import javax.inject.Inject; | import javax.inject.Inject; | ||||||
| 
 | 
 | ||||||
| @ -29,11 +33,14 @@ import org.apache.cloudstack.api.ListHostsMetricsCmd; | |||||||
| import org.apache.cloudstack.api.ListInfrastructureCmd; | import org.apache.cloudstack.api.ListInfrastructureCmd; | ||||||
| import org.apache.cloudstack.api.ListStoragePoolsMetricsCmd; | import org.apache.cloudstack.api.ListStoragePoolsMetricsCmd; | ||||||
| import org.apache.cloudstack.api.ListVMsMetricsCmd; | import org.apache.cloudstack.api.ListVMsMetricsCmd; | ||||||
|  | import org.apache.cloudstack.api.ListVMsUsageHistoryCmd; | ||||||
| import org.apache.cloudstack.api.ListVolumesMetricsCmd; | import org.apache.cloudstack.api.ListVolumesMetricsCmd; | ||||||
| import org.apache.cloudstack.api.ListZonesMetricsCmd; | import org.apache.cloudstack.api.ListZonesMetricsCmd; | ||||||
| import org.apache.cloudstack.api.ServerApiException; | import org.apache.cloudstack.api.ServerApiException; | ||||||
| import org.apache.cloudstack.api.response.ClusterResponse; | import org.apache.cloudstack.api.response.ClusterResponse; | ||||||
| import org.apache.cloudstack.api.response.HostResponse; | import org.apache.cloudstack.api.response.HostResponse; | ||||||
|  | import org.apache.cloudstack.api.response.ListResponse; | ||||||
|  | import org.apache.cloudstack.api.response.StatsResponse; | ||||||
| import org.apache.cloudstack.api.response.StoragePoolResponse; | import org.apache.cloudstack.api.response.StoragePoolResponse; | ||||||
| import org.apache.cloudstack.api.response.UserVmResponse; | import org.apache.cloudstack.api.response.UserVmResponse; | ||||||
| import org.apache.cloudstack.api.response.VolumeResponse; | import org.apache.cloudstack.api.response.VolumeResponse; | ||||||
| @ -44,15 +51,20 @@ import org.apache.cloudstack.response.HostMetricsResponse; | |||||||
| import org.apache.cloudstack.response.InfrastructureResponse; | import org.apache.cloudstack.response.InfrastructureResponse; | ||||||
| import org.apache.cloudstack.response.StoragePoolMetricsResponse; | import org.apache.cloudstack.response.StoragePoolMetricsResponse; | ||||||
| import org.apache.cloudstack.response.VmMetricsResponse; | import org.apache.cloudstack.response.VmMetricsResponse; | ||||||
|  | import org.apache.cloudstack.response.VmMetricsStatsResponse; | ||||||
| import org.apache.cloudstack.response.VolumeMetricsResponse; | import org.apache.cloudstack.response.VolumeMetricsResponse; | ||||||
| import org.apache.cloudstack.response.ZoneMetricsResponse; | import org.apache.cloudstack.response.ZoneMetricsResponse; | ||||||
| import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; | import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; | ||||||
| import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; | import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; | ||||||
| import org.apache.commons.beanutils.BeanUtils; | import org.apache.commons.beanutils.BeanUtils; | ||||||
|  | import org.apache.commons.collections.CollectionUtils; | ||||||
|  | import org.apache.commons.lang3.StringUtils; | ||||||
| 
 | 
 | ||||||
|  | import com.cloud.agent.api.VmStatsEntryBase; | ||||||
| import com.cloud.alert.AlertManager; | import com.cloud.alert.AlertManager; | ||||||
| import com.cloud.alert.dao.AlertDao; | import com.cloud.alert.dao.AlertDao; | ||||||
| import com.cloud.api.ApiDBUtils; | import com.cloud.api.ApiDBUtils; | ||||||
|  | import com.cloud.api.query.MutualExclusiveIdsManagerBase; | ||||||
| import com.cloud.api.query.dao.HostJoinDao; | import com.cloud.api.query.dao.HostJoinDao; | ||||||
| import com.cloud.api.query.vo.HostJoinVO; | import com.cloud.api.query.vo.HostJoinVO; | ||||||
| import com.cloud.capacity.Capacity; | import com.cloud.capacity.Capacity; | ||||||
| @ -65,6 +77,7 @@ import com.cloud.dc.dao.ClusterDao; | |||||||
| import com.cloud.dc.dao.DataCenterDao; | import com.cloud.dc.dao.DataCenterDao; | ||||||
| import com.cloud.dc.dao.HostPodDao; | import com.cloud.dc.dao.HostPodDao; | ||||||
| import com.cloud.deploy.DeploymentClusterPlanner; | import com.cloud.deploy.DeploymentClusterPlanner; | ||||||
|  | import com.cloud.exception.InvalidParameterValueException; | ||||||
| import com.cloud.host.Host; | import com.cloud.host.Host; | ||||||
| import com.cloud.host.HostStats; | import com.cloud.host.HostStats; | ||||||
| import com.cloud.host.Status; | import com.cloud.host.Status; | ||||||
| @ -76,13 +89,20 @@ import com.cloud.org.Managed; | |||||||
| import com.cloud.user.Account; | import com.cloud.user.Account; | ||||||
| import com.cloud.user.AccountManager; | import com.cloud.user.AccountManager; | ||||||
| import com.cloud.utils.Pair; | import com.cloud.utils.Pair; | ||||||
| import com.cloud.utils.component.ComponentLifecycleBase; | import com.cloud.utils.db.Filter; | ||||||
|  | import com.cloud.utils.db.SearchBuilder; | ||||||
|  | import com.cloud.utils.db.SearchCriteria; | ||||||
|  | import com.cloud.vm.UserVmVO; | ||||||
| import com.cloud.vm.VMInstanceVO; | import com.cloud.vm.VMInstanceVO; | ||||||
| import com.cloud.vm.VirtualMachine; | import com.cloud.vm.VirtualMachine; | ||||||
|  | import com.cloud.vm.VmStatsVO; | ||||||
| import com.cloud.vm.dao.DomainRouterDao; | import com.cloud.vm.dao.DomainRouterDao; | ||||||
|  | import com.cloud.vm.dao.UserVmDao; | ||||||
| import com.cloud.vm.dao.VMInstanceDao; | import com.cloud.vm.dao.VMInstanceDao; | ||||||
|  | import com.cloud.vm.dao.VmStatsDao; | ||||||
|  | import com.google.gson.Gson; | ||||||
| 
 | 
 | ||||||
| public class MetricsServiceImpl extends ComponentLifecycleBase implements MetricsService { | public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements MetricsService { | ||||||
| 
 | 
 | ||||||
|     @Inject |     @Inject | ||||||
|     private DataCenterDao dataCenterDao; |     private DataCenterDao dataCenterDao; | ||||||
| @ -110,18 +130,17 @@ public class MetricsServiceImpl extends ComponentLifecycleBase implements Metric | |||||||
|     private ManagementServerHostDao managementServerHostDao; |     private ManagementServerHostDao managementServerHostDao; | ||||||
|     @Inject |     @Inject | ||||||
|     private AlertDao alertDao; |     private AlertDao alertDao; | ||||||
|  |     @Inject | ||||||
|  |     protected UserVmDao userVmDao; | ||||||
|  |     @Inject | ||||||
|  |     protected VmStatsDao vmStatsDao; | ||||||
|  | 
 | ||||||
|  |     private static Gson gson = new Gson(); | ||||||
| 
 | 
 | ||||||
|     protected MetricsServiceImpl() { |     protected MetricsServiceImpl() { | ||||||
|         super(); |         super(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private Double findRatioValue(final String value) { |  | ||||||
|         if (value != null) { |  | ||||||
|             return Double.valueOf(value); |  | ||||||
|         } |  | ||||||
|         return 1.0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private void updateHostMetrics(final Metrics metrics, final HostJoinVO host) { |     private void updateHostMetrics(final Metrics metrics, final HostJoinVO host) { | ||||||
|         metrics.incrTotalHosts(); |         metrics.incrTotalHosts(); | ||||||
|         metrics.addCpuAllocated(host.getCpuReservedCapacity() + host.getCpuUsedCapacity()); |         metrics.addCpuAllocated(host.getCpuReservedCapacity() + host.getCpuUsedCapacity()); | ||||||
| @ -134,6 +153,169 @@ public class MetricsServiceImpl extends ComponentLifecycleBase implements Metric | |||||||
|             metrics.setMaximumMemoryUsage((long) hostStats.getUsedMemory()); |             metrics.setMaximumMemoryUsage((long) hostStats.getUsedMemory()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     /** | ||||||
|  |      * Searches for VM stats based on the {@code ListVMsUsageHistoryCmd} parameters. | ||||||
|  |      * | ||||||
|  |      * @param cmd the {@link ListVMsUsageHistoryCmd} specifying what should be searched. | ||||||
|  |      * @return the list of VM metrics stats found. | ||||||
|  |      */ | ||||||
|  |     @Override | ||||||
|  |     public ListResponse<VmMetricsStatsResponse> searchForVmMetricsStats(ListVMsUsageHistoryCmd cmd) { | ||||||
|  |         Pair<List<UserVmVO>, Integer> userVmList = searchForUserVmsInternal(cmd); | ||||||
|  |         Map<Long,List<VmStatsVO>> vmStatsList = searchForVmMetricsStatsInternal(cmd, userVmList.first()); | ||||||
|  |         return createVmMetricsStatsResponse(userVmList, vmStatsList); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Searches VMs based on {@code ListVMsUsageHistoryCmd} parameters. | ||||||
|  |      * | ||||||
|  |      * @param cmd the {@link ListVMsUsageHistoryCmd} specifying the parameters. | ||||||
|  |      * @return the list of VMs. | ||||||
|  |      */ | ||||||
|  |     protected Pair<List<UserVmVO>, Integer> searchForUserVmsInternal(ListVMsUsageHistoryCmd cmd) { | ||||||
|  |         Filter searchFilter = new Filter(UserVmVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); | ||||||
|  |         List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); | ||||||
|  |         String name = cmd.getName(); | ||||||
|  |         String keyword = cmd.getKeyword(); | ||||||
|  | 
 | ||||||
|  |         SearchBuilder<UserVmVO> sb =  userVmDao.createSearchBuilder(); | ||||||
|  |         sb.and("idIN", sb.entity().getId(), SearchCriteria.Op.IN); | ||||||
|  |         sb.and("displayName", sb.entity().getDisplayName(), SearchCriteria.Op.LIKE); | ||||||
|  |         sb.and("state", sb.entity().getState(), SearchCriteria.Op.EQ); | ||||||
|  | 
 | ||||||
|  |         SearchCriteria<UserVmVO> sc = sb.create(); | ||||||
|  |         if (CollectionUtils.isNotEmpty(ids)) { | ||||||
|  |             sc.setParameters("idIN", ids.toArray()); | ||||||
|  |         } | ||||||
|  |         if (StringUtils.isNotBlank(name)) { | ||||||
|  |             sc.setParameters("displayName", "%" + name + "%"); | ||||||
|  |         } | ||||||
|  |         if (StringUtils.isNotBlank(keyword)) { | ||||||
|  |             SearchCriteria<UserVmVO> ssc = userVmDao.createSearchCriteria(); | ||||||
|  |             ssc.addOr("displayName", SearchCriteria.Op.LIKE, "%" + keyword + "%"); | ||||||
|  |             ssc.addOr("state", SearchCriteria.Op.EQ, keyword); | ||||||
|  |             sc.addAnd("displayName", SearchCriteria.Op.SC, ssc); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return userVmDao.searchAndCount(sc, searchFilter); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Searches stats for a list of VMs, based on date filtering parameters. | ||||||
|  |      * | ||||||
|  |      * @param cmd the {@link ListVMsUsageHistoryCmd} specifying the filtering parameters. | ||||||
|  |      * @param userVmList the list of VMs for which stats should be searched. | ||||||
|  |      * @return the key-value map in which keys are VM IDs and values are lists of VM stats. | ||||||
|  |      */ | ||||||
|  |     protected Map<Long,List<VmStatsVO>> searchForVmMetricsStatsInternal(ListVMsUsageHistoryCmd cmd, List<UserVmVO> userVmList) { | ||||||
|  |         Map<Long,List<VmStatsVO>> vmStatsVOList = new HashMap<Long,List<VmStatsVO>>(); | ||||||
|  |         Date startDate = cmd.getStartDate(); | ||||||
|  |         Date endDate = cmd.getEndDate(); | ||||||
|  | 
 | ||||||
|  |         validateDateParams(startDate, endDate); | ||||||
|  | 
 | ||||||
|  |         for (UserVmVO userVmVO : userVmList) { | ||||||
|  |             Long vmId = userVmVO.getId(); | ||||||
|  |             vmStatsVOList.put(vmId, findVmStatsAccordingToDateParams(vmId, startDate, endDate)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return vmStatsVOList; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Checks if {@code startDate} is after {@code endDate} (when both are not null) | ||||||
|  |      * and throws an {@link InvalidParameterValueException} if so. | ||||||
|  |      * | ||||||
|  |      * @param startDate the start date to be validated. | ||||||
|  |      * @param endDate the end date to be validated. | ||||||
|  |      */ | ||||||
|  |     protected void validateDateParams(Date startDate, Date endDate) { | ||||||
|  |         if ((startDate != null && endDate != null) && (startDate.after(endDate))){ | ||||||
|  |             throw new InvalidParameterValueException("startDate cannot be after endDate."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Finds stats for a specific VM based on date parameters. | ||||||
|  |      * | ||||||
|  |      * @param vmId the specific VM. | ||||||
|  |      * @param startDate the start date to filtering. | ||||||
|  |      * @param endDate the end date to filtering. | ||||||
|  |      * @return the list of stats for the specified VM. | ||||||
|  |      */ | ||||||
|  |     protected List<VmStatsVO> findVmStatsAccordingToDateParams(Long vmId, Date startDate, Date endDate){ | ||||||
|  |         if (startDate != null && endDate != null) { | ||||||
|  |             return vmStatsDao.findByVmIdAndTimestampBetween(vmId, startDate, endDate); | ||||||
|  |         } | ||||||
|  |         if (startDate != null) { | ||||||
|  |             return vmStatsDao.findByVmIdAndTimestampGreaterThanEqual(vmId, startDate); | ||||||
|  |         } | ||||||
|  |         if (endDate != null) { | ||||||
|  |             return vmStatsDao.findByVmIdAndTimestampLessThanEqual(vmId, endDate); | ||||||
|  |         } | ||||||
|  |         return vmStatsDao.findByVmId(vmId); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Creates a {@code ListResponse<VmMetricsStatsResponse>}. For each VM, this joins essential VM info | ||||||
|  |      * with its respective list of stats. | ||||||
|  |      * | ||||||
|  |      * @param userVmList the list of VMs. | ||||||
|  |      * @param vmStatsList the respective list of stats. | ||||||
|  |      * @return the list of responses that was created. | ||||||
|  |      */ | ||||||
|  |     protected ListResponse<VmMetricsStatsResponse> createVmMetricsStatsResponse(Pair<List<UserVmVO>, Integer> userVmList, | ||||||
|  |             Map<Long,List<VmStatsVO>> vmStatsList) { | ||||||
|  |         List<VmMetricsStatsResponse> responses = new ArrayList<VmMetricsStatsResponse>(); | ||||||
|  |         for (UserVmVO userVmVO : userVmList.first()) { | ||||||
|  |             VmMetricsStatsResponse vmMetricsStatsResponse = new VmMetricsStatsResponse(); | ||||||
|  |             vmMetricsStatsResponse.setObjectName("virtualmachine"); | ||||||
|  |             vmMetricsStatsResponse.setId(userVmVO.getUuid()); | ||||||
|  |             vmMetricsStatsResponse.setName(userVmVO.getName()); | ||||||
|  |             vmMetricsStatsResponse.setDisplayName(userVmVO.getDisplayName()); | ||||||
|  | 
 | ||||||
|  |             vmMetricsStatsResponse.setStats(createStatsResponse(vmStatsList.get(userVmVO.getId()))); | ||||||
|  |             responses.add(vmMetricsStatsResponse); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ListResponse<VmMetricsStatsResponse> response = new ListResponse<VmMetricsStatsResponse>(); | ||||||
|  |         response.setResponses(responses); | ||||||
|  |         return response; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Creates a {@code Set<StatsResponse>} from a given {@code List<VmStatsVO>}. | ||||||
|  |      * | ||||||
|  |      * @param vmStatsList the list of VM stats. | ||||||
|  |      * @return the set of responses that was created. | ||||||
|  |      */ | ||||||
|  |     protected List<StatsResponse> createStatsResponse(List<VmStatsVO> vmStatsList) { | ||||||
|  |         List<StatsResponse> statsResponseList = new ArrayList<StatsResponse>(); | ||||||
|  |         DecimalFormat decimalFormat = new DecimalFormat("#.##"); | ||||||
|  |         for (VmStatsVO vmStats : vmStatsList) { | ||||||
|  |             StatsResponse response = new StatsResponse(); | ||||||
|  |             response.setTimestamp(vmStats.getTimestamp()); | ||||||
|  | 
 | ||||||
|  |             VmStatsEntryBase statsEntry = gson.fromJson(vmStats.getVmStatsData(), VmStatsEntryBase.class); | ||||||
|  |             response.setCpuUsed(decimalFormat.format(statsEntry.getCPUUtilization()) + "%"); | ||||||
|  |             response.setNetworkKbsRead((long)statsEntry.getNetworkReadKBs()); | ||||||
|  |             response.setNetworkKbsWrite((long)statsEntry.getNetworkWriteKBs()); | ||||||
|  |             response.setDiskKbsRead((long)statsEntry.getDiskReadKBs()); | ||||||
|  |             response.setDiskKbsWrite((long)statsEntry.getDiskWriteKBs()); | ||||||
|  |             response.setDiskIORead((long)statsEntry.getDiskReadIOs()); | ||||||
|  |             response.setDiskIOWrite((long)statsEntry.getDiskWriteIOs()); | ||||||
|  |             long totalMemory = (long)statsEntry.getMemoryKBs(); | ||||||
|  |             long freeMemory = (long)statsEntry.getIntFreeMemoryKBs(); | ||||||
|  |             long correctedFreeMemory = freeMemory >= totalMemory ? 0 : freeMemory; | ||||||
|  |             response.setMemoryKBs(totalMemory); | ||||||
|  |             response.setMemoryIntFreeKBs(correctedFreeMemory); | ||||||
|  |             response.setMemoryTargetKBs((long)statsEntry.getTargetMemoryKBs()); | ||||||
|  | 
 | ||||||
|  |             statsResponseList.add(response); | ||||||
|  |         } | ||||||
|  |         return statsResponseList; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public InfrastructureResponse listInfrastructure() { |     public InfrastructureResponse listInfrastructure() { | ||||||
| @ -480,6 +662,7 @@ public class MetricsServiceImpl extends ComponentLifecycleBase implements Metric | |||||||
|         cmdList.add(ListHostsMetricsCmd.class); |         cmdList.add(ListHostsMetricsCmd.class); | ||||||
|         cmdList.add(ListClustersMetricsCmd.class); |         cmdList.add(ListClustersMetricsCmd.class); | ||||||
|         cmdList.add(ListZonesMetricsCmd.class); |         cmdList.add(ListZonesMetricsCmd.class); | ||||||
|  |         cmdList.add(ListVMsUsageHistoryCmd.class); | ||||||
|         return cmdList; |         return cmdList; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -0,0 +1,62 @@ | |||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | 
 | ||||||
|  | package org.apache.cloudstack.response; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.apache.cloudstack.api.ApiConstants; | ||||||
|  | import org.apache.cloudstack.api.BaseResponse; | ||||||
|  | import org.apache.cloudstack.api.response.StatsResponse; | ||||||
|  | 
 | ||||||
|  | import com.cloud.serializer.Param; | ||||||
|  | import com.google.gson.annotations.SerializedName; | ||||||
|  | 
 | ||||||
|  | public class VmMetricsStatsResponse extends BaseResponse { | ||||||
|  |     @SerializedName(ApiConstants.ID) | ||||||
|  |     @Param(description = "the ID of the virtual machine") | ||||||
|  |     private String id; | ||||||
|  | 
 | ||||||
|  |     @SerializedName(ApiConstants.NAME) | ||||||
|  |     @Param(description = "the name of the virtual machine") | ||||||
|  |     private String name; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("displayname") | ||||||
|  |     @Param(description = "user generated name. The name of the virtual machine is returned if no displayname exists.") | ||||||
|  |     private String displayName; | ||||||
|  | 
 | ||||||
|  |     @SerializedName("stats") | ||||||
|  |     @Param(description = "the list of VM stats") | ||||||
|  |     private List<StatsResponse> stats; | ||||||
|  | 
 | ||||||
|  |     public void setId(String id) { | ||||||
|  |         this.id = id; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setName(String name) { | ||||||
|  |         this.name = name; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setDisplayName(String displayName) { | ||||||
|  |         this.displayName = displayName; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setStats(List<StatsResponse> stats) { | ||||||
|  |         this.stats = stats; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,314 @@ | |||||||
|  | // Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | // or more contributor license agreements.  See the NOTICE file | ||||||
|  | // distributed with this work for additional information | ||||||
|  | // regarding copyright ownership.  The ASF licenses this file | ||||||
|  | // to you under the Apache License, Version 2.0 (the | ||||||
|  | // "License"); you may not use this file except in compliance | ||||||
|  | // with the License.  You may obtain a copy of the License at | ||||||
|  | // | ||||||
|  | //   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  | // | ||||||
|  | // Unless required by applicable law or agreed to in writing, | ||||||
|  | // software distributed under the License is distributed on an | ||||||
|  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  | // KIND, either express or implied.  See the License for the | ||||||
|  | // specific language governing permissions and limitations | ||||||
|  | // under the License. | ||||||
|  | package org.apache.cloudstack.metrics; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Date; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | import org.apache.cloudstack.api.ListVMsUsageHistoryCmd; | ||||||
|  | import org.apache.cloudstack.api.response.ListResponse; | ||||||
|  | import org.apache.cloudstack.response.VmMetricsStatsResponse; | ||||||
|  | import org.apache.commons.lang3.time.DateUtils; | ||||||
|  | import org.junit.Assert; | ||||||
|  | import org.junit.Test; | ||||||
|  | import org.junit.runner.RunWith; | ||||||
|  | import org.mockito.ArgumentCaptor; | ||||||
|  | import org.mockito.Captor; | ||||||
|  | import org.mockito.InjectMocks; | ||||||
|  | import org.mockito.Mock; | ||||||
|  | import org.mockito.Mockito; | ||||||
|  | import org.mockito.Spy; | ||||||
|  | import org.mockito.junit.MockitoJUnitRunner; | ||||||
|  | 
 | ||||||
|  | import com.cloud.exception.InvalidParameterValueException; | ||||||
|  | import com.cloud.utils.Pair; | ||||||
|  | import com.cloud.utils.db.SearchBuilder; | ||||||
|  | import com.cloud.utils.db.SearchCriteria; | ||||||
|  | import com.cloud.vm.UserVmVO; | ||||||
|  | import com.cloud.vm.VmStatsVO; | ||||||
|  | import com.cloud.vm.dao.UserVmDao; | ||||||
|  | import com.cloud.vm.dao.VmStatsDao; | ||||||
|  | 
 | ||||||
|  | @RunWith(MockitoJUnitRunner.class) | ||||||
|  | public class MetricsServiceImplTest { | ||||||
|  | 
 | ||||||
|  |     @Spy | ||||||
|  |     @InjectMocks | ||||||
|  |     MetricsServiceImpl spy; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     ListVMsUsageHistoryCmd listVMsUsageHistoryCmdMock; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     UserVmVO userVmVOMock; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     SearchBuilder<UserVmVO> sbMock; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     SearchCriteria<UserVmVO> scMock; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     UserVmDao userVmDaoMock; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     VmStatsDao vmStatsDaoMock; | ||||||
|  | 
 | ||||||
|  |     @Captor | ||||||
|  |     ArgumentCaptor<String> stringCaptor1, stringCaptor2; | ||||||
|  | 
 | ||||||
|  |     @Captor | ||||||
|  |     ArgumentCaptor<Object[]> objectArrayCaptor; | ||||||
|  | 
 | ||||||
|  |     @Captor | ||||||
|  |     ArgumentCaptor<SearchCriteria.Op> opCaptor; | ||||||
|  |     long fakeVmId1 = 1L, fakeVmId2 = 2L; | ||||||
|  | 
 | ||||||
|  |     Pair<List<UserVmVO>, Integer> expectedVmListAndCounter; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     Pair<List<UserVmVO>, Integer> expectedVmListAndCounterMock; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     Map<Long,List<VmStatsVO>> vmStatsMapMock; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     VmStatsVO vmStatsVOMock; | ||||||
|  | 
 | ||||||
|  |     private void prepareSearchCriteriaWhenUseSetParameters() { | ||||||
|  |         Mockito.doNothing().when(scMock).setParameters(Mockito.anyString(), Mockito.any()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void preparesearchForUserVmsInternalTest() { | ||||||
|  |         expectedVmListAndCounter = new Pair<List<UserVmVO>, Integer>(Arrays.asList(userVmVOMock), 1); | ||||||
|  | 
 | ||||||
|  |         Mockito.doReturn(1L).when(listVMsUsageHistoryCmdMock).getStartIndex(); | ||||||
|  |         Mockito.doReturn(2L).when(listVMsUsageHistoryCmdMock).getPageSizeVal(); | ||||||
|  | 
 | ||||||
|  |         Mockito.doReturn(sbMock).when(userVmDaoMock).createSearchBuilder(); | ||||||
|  |         Mockito.doReturn(fakeVmId1).when(userVmVOMock).getId(); | ||||||
|  |         Mockito.doReturn(userVmVOMock).when(sbMock).entity(); | ||||||
|  |         Mockito.doReturn(scMock).when(sbMock).create(); | ||||||
|  | 
 | ||||||
|  |         Mockito.doReturn(new Pair<List<UserVmVO>, Integer>(Arrays.asList(userVmVOMock), 1)) | ||||||
|  |         .when(userVmDaoMock).searchAndCount(Mockito.any(), Mockito.any()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void searchForUserVmsInternalTestWithOnlyOneId() { | ||||||
|  |         preparesearchForUserVmsInternalTest(); | ||||||
|  |         prepareSearchCriteriaWhenUseSetParameters(); | ||||||
|  |         Mockito.doReturn(fakeVmId1).when(listVMsUsageHistoryCmdMock).getId(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getIds(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword(); | ||||||
|  | 
 | ||||||
|  |         Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture()); | ||||||
|  |         Assert.assertEquals("idIN", stringCaptor1.getValue()); | ||||||
|  |         Assert.assertEquals(Arrays.asList(fakeVmId1), objectArrayCaptor.getAllValues()); | ||||||
|  |         Assert.assertEquals(expectedVmListAndCounter, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void searchForUserVmsInternalTestWithAListOfIds() { | ||||||
|  |         List<Long> expected =  Arrays.asList(fakeVmId1, fakeVmId2); | ||||||
|  |         preparesearchForUserVmsInternalTest(); | ||||||
|  |         prepareSearchCriteriaWhenUseSetParameters(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getId(); | ||||||
|  |         Mockito.doReturn(expected).when(listVMsUsageHistoryCmdMock).getIds(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword(); | ||||||
|  | 
 | ||||||
|  |         Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture()); | ||||||
|  |         Assert.assertEquals("idIN", stringCaptor1.getValue()); | ||||||
|  |         Assert.assertEquals(expected, objectArrayCaptor.getAllValues()); | ||||||
|  |         Assert.assertEquals(expectedVmListAndCounter, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void searchForUserVmsInternalTestWithName() { | ||||||
|  |         preparesearchForUserVmsInternalTest(); | ||||||
|  |         prepareSearchCriteriaWhenUseSetParameters(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getId(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getIds(); | ||||||
|  |         Mockito.doReturn("fakeName").when(listVMsUsageHistoryCmdMock).getName(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getKeyword(); | ||||||
|  | 
 | ||||||
|  |         Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(scMock).setParameters(stringCaptor1.capture(), objectArrayCaptor.capture()); | ||||||
|  |         Assert.assertEquals("displayName", stringCaptor1.getValue()); | ||||||
|  |         Assert.assertEquals("%fakeName%", objectArrayCaptor.getValue()); | ||||||
|  |         Assert.assertEquals(expectedVmListAndCounter, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void searchForUserVmsInternalTestWithKeyword() { | ||||||
|  |         preparesearchForUserVmsInternalTest(); | ||||||
|  |         prepareSearchCriteriaWhenUseSetParameters(); | ||||||
|  |         Mockito.doReturn(scMock).when(userVmDaoMock).createSearchCriteria(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getId(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getIds(); | ||||||
|  |         Mockito.doReturn(null).when(listVMsUsageHistoryCmdMock).getName(); | ||||||
|  |         Mockito.doReturn("fakeKeyword").when(listVMsUsageHistoryCmdMock).getKeyword(); | ||||||
|  | 
 | ||||||
|  |         Pair<List<UserVmVO>, Integer> result = spy.searchForUserVmsInternal(listVMsUsageHistoryCmdMock); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(scMock, Mockito.times(2)).addOr(stringCaptor1.capture(), opCaptor.capture(), objectArrayCaptor.capture()); | ||||||
|  |         List<String> conditions = stringCaptor1.getAllValues(); | ||||||
|  |         List<Object[]> params = objectArrayCaptor.getAllValues(); | ||||||
|  |         Assert.assertEquals("displayName", conditions.get(0)); | ||||||
|  |         Assert.assertEquals("state", conditions.get(1)); | ||||||
|  |         Assert.assertEquals("%fakeKeyword%", params.get(0)); | ||||||
|  |         Assert.assertEquals("fakeKeyword", params.get(1)); | ||||||
|  |         Assert.assertEquals(expectedVmListAndCounter, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void searchForVmMetricsStatsInternalTestWithAPopulatedListOfVms() { | ||||||
|  |         Mockito.doNothing().when(spy).validateDateParams(Mockito.any(), Mockito.any()); | ||||||
|  |         Mockito.doReturn(new ArrayList<VmStatsVO>()).when(spy).findVmStatsAccordingToDateParams( | ||||||
|  |                 Mockito.anyLong(), Mockito.any(), Mockito.any()); | ||||||
|  |         Mockito.doReturn(fakeVmId1).when(userVmVOMock).getId(); | ||||||
|  |         Map<Long,List<VmStatsVO>> expected = new HashMap<Long,List<VmStatsVO>>(); | ||||||
|  |         expected.put(fakeVmId1, new ArrayList<VmStatsVO>()); | ||||||
|  | 
 | ||||||
|  |         Map<Long,List<VmStatsVO>> result = spy.searchForVmMetricsStatsInternal( | ||||||
|  |                 listVMsUsageHistoryCmdMock, Arrays.asList(userVmVOMock)); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(userVmVOMock).getId(); | ||||||
|  |         Mockito.verify(spy).findVmStatsAccordingToDateParams( | ||||||
|  |                 Mockito.anyLong(), Mockito.any(), Mockito.any()); | ||||||
|  |         Assert.assertEquals(expected, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void searchForVmMetricsStatsInternalTestWithAnEmptyListOfVms() { | ||||||
|  |         Mockito.doNothing().when(spy).validateDateParams(Mockito.any(), Mockito.any()); | ||||||
|  |         Map<Long,List<VmStatsVO>> expected = new HashMap<Long,List<VmStatsVO>>(); | ||||||
|  | 
 | ||||||
|  |         Map<Long,List<VmStatsVO>> result = spy.searchForVmMetricsStatsInternal( | ||||||
|  |                 listVMsUsageHistoryCmdMock, new ArrayList<UserVmVO>()); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(userVmVOMock, Mockito.never()).getId(); | ||||||
|  |         Mockito.verify(spy, Mockito.never()).findVmStatsAccordingToDateParams( | ||||||
|  |                 Mockito.anyLong(), Mockito.any(), Mockito.any()); | ||||||
|  |         Assert.assertEquals(expected, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = InvalidParameterValueException.class) | ||||||
|  |     public void validateDateParamsTestWithEndDateBeforeStartDate() { | ||||||
|  |         Date startDate = new Date(); | ||||||
|  |         Date endDate = DateUtils.addSeconds(startDate, -1); | ||||||
|  | 
 | ||||||
|  |         spy.validateDateParams(startDate, endDate); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void findVmStatsAccordingToDateParamsTestWithStartDateAndEndDate() { | ||||||
|  |         Date startDate = new Date(); | ||||||
|  |         Date endDate = DateUtils.addSeconds(startDate, 1); | ||||||
|  |         Mockito.doReturn(new ArrayList<VmStatsVO>()).when(vmStatsDaoMock).findByVmIdAndTimestampBetween( | ||||||
|  |                 Mockito.anyLong(), Mockito.any(), Mockito.any()); | ||||||
|  | 
 | ||||||
|  |         spy.findVmStatsAccordingToDateParams(fakeVmId1, startDate, endDate); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(vmStatsDaoMock).findByVmIdAndTimestampBetween( | ||||||
|  |               Mockito.anyLong(), Mockito.any(), Mockito.any()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void findVmStatsAccordingToDateParamsTestWithOnlyStartDate() { | ||||||
|  |         Date startDate = new Date(); | ||||||
|  |         Date endDate = null; | ||||||
|  |         Mockito.doReturn(new ArrayList<VmStatsVO>()).when(vmStatsDaoMock).findByVmIdAndTimestampGreaterThanEqual( | ||||||
|  |                 Mockito.anyLong(), Mockito.any()); | ||||||
|  | 
 | ||||||
|  |         spy.findVmStatsAccordingToDateParams(fakeVmId1, startDate, endDate); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(vmStatsDaoMock).findByVmIdAndTimestampGreaterThanEqual( | ||||||
|  |               Mockito.anyLong(), Mockito.any()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void findVmStatsAccordingToDateParamsTestWithOnlyEndDate() { | ||||||
|  |         Date startDate = null; | ||||||
|  |         Date endDate = new Date(); | ||||||
|  |         Mockito.doReturn(new ArrayList<VmStatsVO>()).when(vmStatsDaoMock).findByVmIdAndTimestampLessThanEqual( | ||||||
|  |                 Mockito.anyLong(), Mockito.any()); | ||||||
|  | 
 | ||||||
|  |         spy.findVmStatsAccordingToDateParams(fakeVmId1, startDate, endDate); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(vmStatsDaoMock).findByVmIdAndTimestampLessThanEqual( | ||||||
|  |               Mockito.anyLong(), Mockito.any()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void findVmStatsAccordingToDateParamsTestWithNoDate() { | ||||||
|  |         Mockito.doReturn(new ArrayList<VmStatsVO>()).when(vmStatsDaoMock).findByVmId(Mockito.anyLong()); | ||||||
|  | 
 | ||||||
|  |         spy.findVmStatsAccordingToDateParams(fakeVmId1, null, null); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(vmStatsDaoMock).findByVmId(Mockito.anyLong()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void createVmMetricsStatsResponseTestWithValidInput() { | ||||||
|  |         Mockito.doReturn("").when(userVmVOMock).getUuid(); | ||||||
|  |         Mockito.doReturn("").when(userVmVOMock).getName(); | ||||||
|  |         Mockito.doReturn("").when(userVmVOMock).getDisplayName(); | ||||||
|  |         Mockito.doReturn(fakeVmId1).when(userVmVOMock).getId(); | ||||||
|  |         Mockito.doReturn(Arrays.asList(userVmVOMock)).when(expectedVmListAndCounterMock).first(); | ||||||
|  |         Mockito.doReturn(null).when(vmStatsMapMock).get(Mockito.any()); | ||||||
|  |         Mockito.doReturn(null).when(spy).createStatsResponse(Mockito.any()); | ||||||
|  | 
 | ||||||
|  |         ListResponse<VmMetricsStatsResponse> result = spy.createVmMetricsStatsResponse( | ||||||
|  |                 expectedVmListAndCounterMock, vmStatsMapMock); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals(Integer.valueOf(1), result.getCount()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = NullPointerException.class) | ||||||
|  |     public void createVmMetricsStatsResponseTestWithNoUserVmList() { | ||||||
|  |         spy.createVmMetricsStatsResponse(null, vmStatsMapMock); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = NullPointerException.class) | ||||||
|  |     public void createVmMetricsStatsResponseTestWithNoVmStatsList() { | ||||||
|  |         spy.createVmMetricsStatsResponse(expectedVmListAndCounterMock, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void createStatsResponseTestWithValidStatsData() { | ||||||
|  |         final String fakeVmStatsData = "{\"vmId\":1,\"cpuUtilization\":15.615905273486222,\"networkReadKBs\":0.1," | ||||||
|  |                 + "\"networkWriteKBs\":0.2,\"diskReadIOs\":0.1,\"diskWriteIOs\":0.2,\"diskReadKBs\":1.1," | ||||||
|  |                 + "\"diskWriteKBs\":2.1,\"memoryKBs\":262144.0,\"intfreememoryKBs\":262144.0,\"targetmemoryKBs\":262144.0," | ||||||
|  |                 + "\"numCPUs\":1,\"entityType\":\"vm\"}"; | ||||||
|  |         Mockito.doReturn(new Date()).when(vmStatsVOMock).getTimestamp(); | ||||||
|  |         Mockito.doReturn(fakeVmStatsData).when(vmStatsVOMock).getVmStatsData(); | ||||||
|  | 
 | ||||||
|  |         spy.createStatsResponse(Arrays.asList(vmStatsVOMock)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -994,8 +994,8 @@ public class ApiDBUtils { | |||||||
|         return s_statsCollector.getStoragePoolStats(id); |         return s_statsCollector.getStoragePoolStats(id); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static VmStats getVmStatistics(long hostId) { |     public static VmStats getVmStatistics(long vmId, Boolean accumulate) { | ||||||
|         return s_statsCollector.getVmStats(hostId); |         return s_statsCollector.getVmStats(vmId, accumulate); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static VolumeStats getVolumeStatistics(String volumeUuid) { |     public static VolumeStats getVolumeStatistics(String volumeUuid) { | ||||||
| @ -1805,7 +1805,11 @@ public class ApiDBUtils { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Account caller) { |     public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Account caller) { | ||||||
|         return s_userVmJoinDao.newUserVmResponse(view, objectName, userVm, details, caller); |         return s_userVmJoinDao.newUserVmResponse(view, objectName, userVm, details, null, caller); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Boolean accumulateStats, Account caller) { | ||||||
|  |         return s_userVmJoinDao.newUserVmResponse(view, objectName, userVm, details, accumulateStats, caller); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static UserVmResponse fillVmDetails(ResponseView view, UserVmResponse vmData, UserVmJoinVO vm) { |     public static UserVmResponse fillVmDetails(ResponseView view, UserVmResponse vmData, UserVmJoinVO vm) { | ||||||
|  | |||||||
| @ -46,12 +46,6 @@ import org.apache.cloudstack.api.EntityReference; | |||||||
| import org.apache.cloudstack.api.InternalIdentity; | import org.apache.cloudstack.api.InternalIdentity; | ||||||
| import org.apache.cloudstack.api.Parameter; | import org.apache.cloudstack.api.Parameter; | ||||||
| import org.apache.cloudstack.api.ServerApiException; | import org.apache.cloudstack.api.ServerApiException; | ||||||
| import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd; |  | ||||||
| import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; |  | ||||||
| import org.apache.cloudstack.api.command.admin.usage.ListUsageRecordsCmd; |  | ||||||
| import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd; |  | ||||||
| import org.apache.cloudstack.api.command.user.event.DeleteEventsCmd; |  | ||||||
| import org.apache.cloudstack.api.command.user.event.ListEventsCmd; |  | ||||||
| import org.apache.cloudstack.context.CallContext; | import org.apache.cloudstack.context.CallContext; | ||||||
| import org.apache.log4j.Logger; | import org.apache.log4j.Logger; | ||||||
| 
 | 
 | ||||||
| @ -59,6 +53,7 @@ import com.cloud.exception.InvalidParameterValueException; | |||||||
| import com.cloud.user.Account; | import com.cloud.user.Account; | ||||||
| import com.cloud.user.AccountManager; | import com.cloud.user.AccountManager; | ||||||
| import com.cloud.utils.DateUtil; | import com.cloud.utils.DateUtil; | ||||||
|  | import com.cloud.utils.UuidUtils; | ||||||
| import com.cloud.utils.db.EntityManager; | import com.cloud.utils.db.EntityManager; | ||||||
| import com.cloud.utils.exception.CloudRuntimeException; | import com.cloud.utils.exception.CloudRuntimeException; | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
| @ -93,7 +88,7 @@ public class ParamProcessWorker implements DispatchWorker { | |||||||
| 
 | 
 | ||||||
|     private void validateNonEmptyString(final Object param, final String argName) { |     private void validateNonEmptyString(final Object param, final String argName) { | ||||||
|         if (param == null || StringUtils.isEmpty(param.toString())) { |         if (param == null || StringUtils.isEmpty(param.toString())) { | ||||||
|             throw new InvalidParameterValueException(String.format("Empty or null value provided for API arg: %s", argName)); |             throwInvalidParameterValueException(argName); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -105,10 +100,22 @@ public class ParamProcessWorker implements DispatchWorker { | |||||||
|             value = Long.valueOf(param.toString()); |             value = Long.valueOf(param.toString()); | ||||||
|         } |         } | ||||||
|         if (value == null || value < 1L) { |         if (value == null || value < 1L) { | ||||||
|             throw new InvalidParameterValueException(String.format("Invalid value provided for API arg: %s", argName)); |             throwInvalidParameterValueException(argName); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private void validateUuidString(final Object param, final String argName) { | ||||||
|  |         String value = String.valueOf(param); | ||||||
|  | 
 | ||||||
|  |         if (!UuidUtils.validateUUID(value)) { | ||||||
|  |             throwInvalidParameterValueException(argName); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected void throwInvalidParameterValueException(String argName) { | ||||||
|  |         throw new InvalidParameterValueException(String.format("Invalid value provided for API arg: %s", argName)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private void validateField(final Object paramObj, final Parameter annotation) throws ServerApiException { |     private void validateField(final Object paramObj, final Parameter annotation) throws ServerApiException { | ||||||
|         if (annotation == null) { |         if (annotation == null) { | ||||||
|             return; |             return; | ||||||
| @ -136,6 +143,13 @@ public class ParamProcessWorker implements DispatchWorker { | |||||||
|                             break; |                             break; | ||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
|  |                 case UuidString: | ||||||
|  |                     switch (annotation.type()) { | ||||||
|  |                         case STRING: | ||||||
|  |                             validateUuidString(paramObj, argName); | ||||||
|  |                             break; | ||||||
|  |                     } | ||||||
|  |                     break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -312,31 +326,22 @@ public class ParamProcessWorker implements DispatchWorker { | |||||||
|             case DATE: |             case DATE: | ||||||
|                 // This piece of code is for maintaining backward compatibility |                 // This piece of code is for maintaining backward compatibility | ||||||
|                 // and support both the date formats(Bug 9724) |                 // and support both the date formats(Bug 9724) | ||||||
|                 if (cmdObj instanceof ListEventsCmd || cmdObj instanceof DeleteEventsCmd || cmdObj instanceof ArchiveEventsCmd || |                 final boolean isObjInNewDateFormat = isObjInNewDateFormat(paramObj.toString()); | ||||||
|                         cmdObj instanceof ArchiveAlertsCmd || cmdObj instanceof DeleteAlertsCmd || cmdObj instanceof ListUsageRecordsCmd) { |                 if (isObjInNewDateFormat) { | ||||||
|                     final boolean isObjInNewDateFormat = isObjInNewDateFormat(paramObj.toString()); |                     final DateFormat newFormat = newInputFormat; | ||||||
|                     if (isObjInNewDateFormat) { |                     synchronized (newFormat) { | ||||||
|                         final DateFormat newFormat = newInputFormat; |                         field.set(cmdObj, newFormat.parse(paramObj.toString())); | ||||||
|                         synchronized (newFormat) { |  | ||||||
|                             field.set(cmdObj, newFormat.parse(paramObj.toString())); |  | ||||||
|                         } |  | ||||||
|                     } else { |  | ||||||
|                         final DateFormat format = inputFormat; |  | ||||||
|                         synchronized (format) { |  | ||||||
|                             Date date = format.parse(paramObj.toString()); |  | ||||||
|                             if (field.getName().equals("startDate")) { |  | ||||||
|                                 date = messageDate(date, 0, 0, 0); |  | ||||||
|                             } else if (field.getName().equals("endDate")) { |  | ||||||
|                                 date = messageDate(date, 23, 59, 59); |  | ||||||
|                             } |  | ||||||
|                             field.set(cmdObj, date); |  | ||||||
|                         } |  | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     final DateFormat format = inputFormat; |                     final DateFormat format = inputFormat; | ||||||
|                     synchronized (format) { |                     synchronized (format) { | ||||||
|                         format.setLenient(false); |                         Date date = format.parse(paramObj.toString()); | ||||||
|                         field.set(cmdObj, format.parse(paramObj.toString())); |                         if (field.getName().equals("startDate")) { | ||||||
|  |                             date = messageDate(date, 0, 0, 0); | ||||||
|  |                         } else if (field.getName().equals("endDate")) { | ||||||
|  |                             date = messageDate(date, 23, 59, 59); | ||||||
|  |                         } | ||||||
|  |                         field.set(cmdObj, date); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
| @ -453,7 +458,7 @@ public class ParamProcessWorker implements DispatchWorker { | |||||||
|         // If annotation's empty, the cmd existed before 3.x try conversion to long |         // If annotation's empty, the cmd existed before 3.x try conversion to long | ||||||
|         final boolean isPre3x = annotation.since().isEmpty(); |         final boolean isPre3x = annotation.since().isEmpty(); | ||||||
|         // Match against Java's UUID regex to check if input is uuid string |         // Match against Java's UUID regex to check if input is uuid string | ||||||
|         final boolean isUuid = uuid.matches("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"); |         final boolean isUuid = UuidUtils.validateUUID(uuid); | ||||||
|         // Enforce that it's uuid for newly added apis from version 3.x |         // Enforce that it's uuid for newly added apis from version 3.x | ||||||
|         if (!isPre3x && !isUuid) |         if (!isPre3x && !isUuid) | ||||||
|             return null; |             return null; | ||||||
|  | |||||||
| @ -928,7 +928,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q | |||||||
|         if (_accountMgr.isRootAdmin(caller.getId())) { |         if (_accountMgr.isRootAdmin(caller.getId())) { | ||||||
|             respView = ResponseView.Full; |             respView = ResponseView.Full; | ||||||
|         } |         } | ||||||
|         List<UserVmResponse> vmResponses = ViewResponseHelper.createUserVmResponse(respView, "virtualmachine", cmd.getDetails(), result.first().toArray(new UserVmJoinVO[result.first().size()])); |         List<UserVmResponse> vmResponses = ViewResponseHelper.createUserVmResponse(respView, "virtualmachine", cmd.getDetails(), cmd.getAccumulate(), result.first().toArray(new UserVmJoinVO[result.first().size()])); | ||||||
| 
 | 
 | ||||||
|         response.setResponses(vmResponses, result.second()); |         response.setResponses(vmResponses, result.second()); | ||||||
|         return response; |         return response; | ||||||
|  | |||||||
| @ -134,14 +134,16 @@ public class ViewResponseHelper { | |||||||
|         return respList; |         return respList; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, UserVmJoinVO... userVms) { |     public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, UserVmJoinVO... userVms) { | ||||||
|         return createUserVmResponse(view, objectName, EnumSet.of(VMDetails.all), userVms); |         return createUserVmResponse(view, objectName, EnumSet.of(VMDetails.all), null, userVms); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, EnumSet<VMDetails> details, UserVmJoinVO... userVms) { |     public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, EnumSet<VMDetails> details, UserVmJoinVO... userVms) { | ||||||
|         Account caller = CallContext.current().getCallingAccount(); |         return createUserVmResponse(view, objectName, details, null, userVms); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     public static List<UserVmResponse> createUserVmResponse(ResponseView view, String objectName, EnumSet<VMDetails> details, Boolean accumulateStats, UserVmJoinVO... userVms) { | ||||||
|  |         Account caller = CallContext.current().getCallingAccount(); | ||||||
|         Hashtable<Long, UserVmResponse> vmDataList = new Hashtable<Long, UserVmResponse>(); |         Hashtable<Long, UserVmResponse> vmDataList = new Hashtable<Long, UserVmResponse>(); | ||||||
|         // Initialise the vmdatalist with the input data |         // Initialise the vmdatalist with the input data | ||||||
| 
 | 
 | ||||||
| @ -149,7 +151,7 @@ public class ViewResponseHelper { | |||||||
|             UserVmResponse userVmData = vmDataList.get(userVm.getId()); |             UserVmResponse userVmData = vmDataList.get(userVm.getId()); | ||||||
|             if (userVmData == null) { |             if (userVmData == null) { | ||||||
|                 // first time encountering this vm |                 // first time encountering this vm | ||||||
|                 userVmData = ApiDBUtils.newUserVmResponse(view, objectName, userVm, details, caller); |                 userVmData = ApiDBUtils.newUserVmResponse(view, objectName, userVm, details, accumulateStats, caller); | ||||||
|             } else{ |             } else{ | ||||||
|                 // update nics, securitygroups, tags, affinitygroups for 1 to many mapping fields |                 // update nics, securitygroups, tags, affinitygroups for 1 to many mapping fields | ||||||
|                 userVmData = ApiDBUtils.fillVmDetails(view, userVmData, userVm); |                 userVmData = ApiDBUtils.fillVmDetails(view, userVmData, userVm); | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ import com.cloud.utils.db.GenericDao; | |||||||
| 
 | 
 | ||||||
| public interface UserVmJoinDao extends GenericDao<UserVmJoinVO, Long> { | public interface UserVmJoinDao extends GenericDao<UserVmJoinVO, Long> { | ||||||
| 
 | 
 | ||||||
|     UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Account caller); |     UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Boolean accumulateStats, Account caller); | ||||||
| 
 | 
 | ||||||
|     UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVmData, UserVmJoinVO uvo); |     UserVmResponse setUserVmResponse(ResponseView view, UserVmResponse userVmData, UserVmJoinVO uvo); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -118,7 +118,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Account caller) { |     public UserVmResponse newUserVmResponse(ResponseView view, String objectName, UserVmJoinVO userVm, EnumSet<VMDetails> details, Boolean accumulateStats, Account caller) { | ||||||
|         UserVmResponse userVmResponse = new UserVmResponse(); |         UserVmResponse userVmResponse = new UserVmResponse(); | ||||||
| 
 | 
 | ||||||
|         if (userVm.getHypervisorType() != null) { |         if (userVm.getHypervisorType() != null) { | ||||||
| @ -228,7 +228,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo | |||||||
| 
 | 
 | ||||||
|         if (details.contains(VMDetails.all) || details.contains(VMDetails.stats)) { |         if (details.contains(VMDetails.all) || details.contains(VMDetails.stats)) { | ||||||
|             // stats calculation |             // stats calculation | ||||||
|             VmStats vmStats = ApiDBUtils.getVmStatistics(userVm.getId()); |             VmStats vmStats = ApiDBUtils.getVmStatistics(userVm.getId(), accumulateStats); | ||||||
|             if (vmStats != null) { |             if (vmStats != null) { | ||||||
|                 userVmResponse.setCpuUsed(new DecimalFormat("#.##").format(vmStats.getCPUUtilization()) + "%"); |                 userVmResponse.setCpuUsed(new DecimalFormat("#.##").format(vmStats.getCPUUtilization()) + "%"); | ||||||
|                 userVmResponse.setNetworkKbsRead((long)vmStats.getNetworkReadKBs()); |                 userVmResponse.setNetworkKbsRead((long)vmStats.getNetworkReadKBs()); | ||||||
|  | |||||||
| @ -47,10 +47,12 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; | |||||||
| import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; | import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; | ||||||
| import org.apache.cloudstack.utils.graphite.GraphiteClient; | import org.apache.cloudstack.utils.graphite.GraphiteClient; | ||||||
| import org.apache.cloudstack.utils.graphite.GraphiteException; | import org.apache.cloudstack.utils.graphite.GraphiteException; | ||||||
|  | import org.apache.cloudstack.utils.identity.ManagementServerNode; | ||||||
| import org.apache.cloudstack.utils.usage.UsageUtils; | import org.apache.cloudstack.utils.usage.UsageUtils; | ||||||
| import org.apache.commons.collections.CollectionUtils; | import org.apache.commons.collections.CollectionUtils; | ||||||
| import org.apache.commons.collections.MapUtils; | import org.apache.commons.collections.MapUtils; | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
|  | import org.apache.commons.lang3.time.DateUtils; | ||||||
| import org.apache.commons.lang3.BooleanUtils; | import org.apache.commons.lang3.BooleanUtils; | ||||||
| import org.apache.log4j.Logger; | import org.apache.log4j.Logger; | ||||||
| import org.influxdb.BatchOptions; | import org.influxdb.BatchOptions; | ||||||
| @ -70,6 +72,7 @@ import com.cloud.agent.api.VgpuTypesInfo; | |||||||
| import com.cloud.agent.api.VmDiskStatsEntry; | import com.cloud.agent.api.VmDiskStatsEntry; | ||||||
| import com.cloud.agent.api.VmNetworkStatsEntry; | import com.cloud.agent.api.VmNetworkStatsEntry; | ||||||
| import com.cloud.agent.api.VmStatsEntry; | import com.cloud.agent.api.VmStatsEntry; | ||||||
|  | import com.cloud.agent.api.VmStatsEntryBase; | ||||||
| import com.cloud.agent.api.VolumeStatsEntry; | import com.cloud.agent.api.VolumeStatsEntry; | ||||||
| import com.cloud.capacity.CapacityManager; | import com.cloud.capacity.CapacityManager; | ||||||
| import com.cloud.cluster.ManagementServerHostVO; | import com.cloud.cluster.ManagementServerHostVO; | ||||||
| @ -142,9 +145,12 @@ import com.cloud.vm.UserVmVO; | |||||||
| import com.cloud.vm.VMInstanceVO; | import com.cloud.vm.VMInstanceVO; | ||||||
| import com.cloud.vm.VirtualMachine; | import com.cloud.vm.VirtualMachine; | ||||||
| import com.cloud.vm.VmStats; | import com.cloud.vm.VmStats; | ||||||
|  | import com.cloud.vm.VmStatsVO; | ||||||
| import com.cloud.vm.dao.NicDao; | import com.cloud.vm.dao.NicDao; | ||||||
| import com.cloud.vm.dao.UserVmDao; | import com.cloud.vm.dao.UserVmDao; | ||||||
| import com.cloud.vm.dao.VMInstanceDao; | import com.cloud.vm.dao.VMInstanceDao; | ||||||
|  | import com.cloud.vm.dao.VmStatsDao; | ||||||
|  | import com.google.gson.Gson; | ||||||
| 
 | 
 | ||||||
| import static com.cloud.utils.NumbersUtil.toHumanReadableSize; | import static com.cloud.utils.NumbersUtil.toHumanReadableSize; | ||||||
| import org.apache.commons.io.FileUtils; | import org.apache.commons.io.FileUtils; | ||||||
| @ -222,12 +228,16 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|     private static final ConfigKey<String> statsOutputUri = new ConfigKey<String>("Advanced", String.class, "stats.output.uri", "", |     private static final ConfigKey<String> statsOutputUri = new ConfigKey<String>("Advanced", String.class, "stats.output.uri", "", | ||||||
|             "URI to send StatsCollector statistics to. The collector is defined on the URI scheme. Example: graphite://graphite-hostaddress:port or influxdb://influxdb-hostaddress/dbname. Note that the port is optional, if not added the default port for the respective collector (graphite or influxdb) will be used. Additionally, the database name '/dbname' is  also optional; default db name is 'cloudstack'. You must create and configure the database if using influxdb.", |             "URI to send StatsCollector statistics to. The collector is defined on the URI scheme. Example: graphite://graphite-hostaddress:port or influxdb://influxdb-hostaddress/dbname. Note that the port is optional, if not added the default port for the respective collector (graphite or influxdb) will be used. Additionally, the database name '/dbname' is  also optional; default db name is 'cloudstack'. You must create and configure the database if using influxdb.", | ||||||
|             true); |             true); | ||||||
|     private static final ConfigKey<Boolean> VM_STATS_INCREMENT_METRICS_IN_MEMORY = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.stats.increment.metrics.in.memory", "true", |     protected static ConfigKey<Boolean> vmStatsIncrementMetrics = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.stats.increment.metrics", "true", | ||||||
|             "When set to 'true', VM metrics(NetworkReadKBs, NetworkWriteKBs, DiskWriteKBs, DiskReadKBs, DiskReadIOs and DiskWriteIOs) that are collected from the hypervisor are summed and stored in memory. " |             "When set to 'true', VM metrics(NetworkReadKBs, NetworkWriteKBs, DiskWriteKBs, DiskReadKBs, DiskReadIOs and DiskWriteIOs) that are collected from the hypervisor are summed before being returned." | ||||||
|             + "On the other hand, when set to 'false', the VM metrics API will just display the latest metrics collected.", true); |             + "On the other hand, when set to 'false', the VM metrics API will just display the latest metrics collected.", true); | ||||||
|  |     protected static ConfigKey<Integer> vmStatsMaxRetentionTime = new ConfigKey<Integer>("Advanced", Integer.class, "vm.stats.max.retention.time", "1", | ||||||
|  |             "The maximum time (in minutes) for keeping VM stats records in the database. The VM stats cleanup process will be disabled if this is set to 0 or less than 0.", true); | ||||||
| 
 | 
 | ||||||
|     private static StatsCollector s_instance = null; |     private static StatsCollector s_instance = null; | ||||||
| 
 | 
 | ||||||
|  |     private static Gson gson = new Gson(); | ||||||
|  | 
 | ||||||
|     private ScheduledExecutorService _executor = null; |     private ScheduledExecutorService _executor = null; | ||||||
|     @Inject |     @Inject | ||||||
|     private AgentManager _agentMgr; |     private AgentManager _agentMgr; | ||||||
| @ -240,6 +250,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|     @Inject |     @Inject | ||||||
|     protected UserVmDao _userVmDao; |     protected UserVmDao _userVmDao; | ||||||
|     @Inject |     @Inject | ||||||
|  |     protected VmStatsDao vmStatsDao; | ||||||
|  |     @Inject | ||||||
|     private VolumeDao _volsDao; |     private VolumeDao _volsDao; | ||||||
|     @Inject |     @Inject | ||||||
|     private PrimaryDataStoreDao _storagePoolDao; |     private PrimaryDataStoreDao _storagePoolDao; | ||||||
| @ -289,6 +301,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|     private HostGpuGroupsDao _hostGpuGroupsDao; |     private HostGpuGroupsDao _hostGpuGroupsDao; | ||||||
|     @Inject |     @Inject | ||||||
|     private ImageStoreDetailsUtil imageStoreDetailsUtil; |     private ImageStoreDetailsUtil imageStoreDetailsUtil; | ||||||
|  |     @Inject | ||||||
|  |     private ManagementServerHostDao managementServerHostDao; | ||||||
| 
 | 
 | ||||||
|     private ConcurrentHashMap<Long, HostStats> _hostStats = new ConcurrentHashMap<Long, HostStats>(); |     private ConcurrentHashMap<Long, HostStats> _hostStats = new ConcurrentHashMap<Long, HostStats>(); | ||||||
|     protected ConcurrentHashMap<Long, VmStats> _VmStats = new ConcurrentHashMap<Long, VmStats>(); |     protected ConcurrentHashMap<Long, VmStats> _VmStats = new ConcurrentHashMap<Long, VmStats>(); | ||||||
| @ -296,8 +310,10 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|     private ConcurrentHashMap<Long, StorageStats> _storageStats = new ConcurrentHashMap<Long, StorageStats>(); |     private ConcurrentHashMap<Long, StorageStats> _storageStats = new ConcurrentHashMap<Long, StorageStats>(); | ||||||
|     private ConcurrentHashMap<Long, StorageStats> _storagePoolStats = new ConcurrentHashMap<Long, StorageStats>(); |     private ConcurrentHashMap<Long, StorageStats> _storagePoolStats = new ConcurrentHashMap<Long, StorageStats>(); | ||||||
| 
 | 
 | ||||||
|  |     private static final long DEFAULT_INITIAL_DELAY = 15000L; | ||||||
|  | 
 | ||||||
|     private long hostStatsInterval = -1L; |     private long hostStatsInterval = -1L; | ||||||
|     private long hostAndVmStatsInterval = -1L; |     private long vmStatsInterval = -1L; | ||||||
|     private long storageStatsInterval = -1L; |     private long storageStatsInterval = -1L; | ||||||
|     private long volumeStatsInterval = -1L; |     private long volumeStatsInterval = -1L; | ||||||
|     private long autoScaleStatsInterval = -1L; |     private long autoScaleStatsInterval = -1L; | ||||||
| @ -315,8 +331,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|     private final long mgmtSrvrId = MacAddress.getMacAddress().toLong(); |     private final long mgmtSrvrId = MacAddress.getMacAddress().toLong(); | ||||||
|     private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 5;    // 5 seconds |     private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 5;    // 5 seconds | ||||||
|     private boolean _dailyOrHourly = false; |     private boolean _dailyOrHourly = false; | ||||||
| 
 |     protected long managementServerNodeId = ManagementServerNode.getManagementServerId(); | ||||||
|     //private final GlobalLock m_capacityCheckLock = GlobalLock.getInternLock("capacity.check"); |     protected long msId = managementServerNodeId; | ||||||
| 
 | 
 | ||||||
|     public static StatsCollector getInstance() { |     public static StatsCollector getInstance() { | ||||||
|         return s_instance; |         return s_instance; | ||||||
| @ -341,7 +357,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|         _executor = Executors.newScheduledThreadPool(6, new NamedThreadFactory("StatsCollector")); |         _executor = Executors.newScheduledThreadPool(6, new NamedThreadFactory("StatsCollector")); | ||||||
| 
 | 
 | ||||||
|         hostStatsInterval = NumbersUtil.parseLong(configs.get("host.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); |         hostStatsInterval = NumbersUtil.parseLong(configs.get("host.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); | ||||||
|         hostAndVmStatsInterval = NumbersUtil.parseLong(configs.get("vm.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); |         vmStatsInterval = NumbersUtil.parseLong(configs.get("vm.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); | ||||||
|         storageStatsInterval = NumbersUtil.parseLong(configs.get("storage.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); |         storageStatsInterval = NumbersUtil.parseLong(configs.get("storage.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); | ||||||
|         volumeStatsInterval = NumbersUtil.parseLong(configs.get("volume.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); |         volumeStatsInterval = NumbersUtil.parseLong(configs.get("volume.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); | ||||||
|         autoScaleStatsInterval = NumbersUtil.parseLong(configs.get("autoscale.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); |         autoScaleStatsInterval = NumbersUtil.parseLong(configs.get("autoscale.stats.interval"), ONE_MINUTE_IN_MILLISCONDS); | ||||||
| @ -383,19 +399,23 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (hostStatsInterval > 0) { |         if (hostStatsInterval > 0) { | ||||||
|             _executor.scheduleWithFixedDelay(new HostCollector(), 15000L, hostStatsInterval, TimeUnit.MILLISECONDS); |             _executor.scheduleWithFixedDelay(new HostCollector(), DEFAULT_INITIAL_DELAY, hostStatsInterval, TimeUnit.MILLISECONDS); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (hostAndVmStatsInterval > 0) { |         if (vmStatsInterval > 0) { | ||||||
|             _executor.scheduleWithFixedDelay(new VmStatsCollector(), 15000L, hostAndVmStatsInterval, TimeUnit.MILLISECONDS); |             _executor.scheduleWithFixedDelay(new VmStatsCollector(), DEFAULT_INITIAL_DELAY, vmStatsInterval, TimeUnit.MILLISECONDS); | ||||||
|  |         } else { | ||||||
|  |             s_logger.info("Skipping collect VM stats. The global parameter vm.stats.interval is set to 0 or less than 0."); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         _executor.scheduleWithFixedDelay(new VmStatsCleaner(), DEFAULT_INITIAL_DELAY, 60000L, TimeUnit.MILLISECONDS); | ||||||
|  | 
 | ||||||
|         if (storageStatsInterval > 0) { |         if (storageStatsInterval > 0) { | ||||||
|             _executor.scheduleWithFixedDelay(new StorageCollector(), 15000L, storageStatsInterval, TimeUnit.MILLISECONDS); |             _executor.scheduleWithFixedDelay(new StorageCollector(), DEFAULT_INITIAL_DELAY, storageStatsInterval, TimeUnit.MILLISECONDS); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (autoScaleStatsInterval > 0) { |         if (autoScaleStatsInterval > 0) { | ||||||
|             _executor.scheduleWithFixedDelay(new AutoScaleMonitor(), 15000L, autoScaleStatsInterval, TimeUnit.MILLISECONDS); |             _executor.scheduleWithFixedDelay(new AutoScaleMonitor(), DEFAULT_INITIAL_DELAY, autoScaleStatsInterval, TimeUnit.MILLISECONDS); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (vmDiskStatsInterval.value() > 0) { |         if (vmDiskStatsInterval.value() > 0) { | ||||||
| @ -423,7 +443,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (volumeStatsInterval > 0) { |         if (volumeStatsInterval > 0) { | ||||||
|             _executor.scheduleAtFixedRate(new VolumeStatsTask(), 15000L, volumeStatsInterval, TimeUnit.MILLISECONDS); |             _executor.scheduleAtFixedRate(new VolumeStatsTask(), DEFAULT_INITIAL_DELAY, volumeStatsInterval, TimeUnit.MILLISECONDS); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         //Schedule disk stats update task |         //Schedule disk stats update task | ||||||
| @ -467,6 +487,14 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
| 
 | 
 | ||||||
|         long period = _usageAggregationRange * ONE_MINUTE_IN_MILLISCONDS; |         long period = _usageAggregationRange * ONE_MINUTE_IN_MILLISCONDS; | ||||||
|         _diskStatsUpdateExecutor.scheduleAtFixedRate(new VmDiskStatsUpdaterTask(), (endDate - System.currentTimeMillis()), period, TimeUnit.MILLISECONDS); |         _diskStatsUpdateExecutor.scheduleAtFixedRate(new VmDiskStatsUpdaterTask(), (endDate - System.currentTimeMillis()), period, TimeUnit.MILLISECONDS); | ||||||
|  | 
 | ||||||
|  |         ManagementServerHostVO mgmtServerVo = managementServerHostDao.findByMsid(managementServerNodeId); | ||||||
|  |         if (mgmtServerVo != null) { | ||||||
|  |             msId = mgmtServerVo.getId(); | ||||||
|  |         } else { | ||||||
|  |             s_logger.warn(String.format("Cannot find management server with msid [%s]. " | ||||||
|  |                     + "Therefore, VM stats will be recorded with the management server MAC address converted as a long in the mgmt_server_id column.", managementServerNodeId)); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -568,7 +596,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|         @Override |         @Override | ||||||
|         protected void runInContext() { |         protected void runInContext() { | ||||||
|             try { |             try { | ||||||
|                 s_logger.trace("VmStatsCollector is running..."); |                 s_logger.debug("VmStatsCollector is running..."); | ||||||
| 
 | 
 | ||||||
|                 SearchCriteria<HostVO> sc = createSearchCriteriaForHostTypeRoutingStateUpAndNotInMaintenance(); |                 SearchCriteria<HostVO> sc = createSearchCriteriaForHostTypeRoutingStateUpAndNotInMaintenance(); | ||||||
|                 List<HostVO> hosts = _hostDao.search(sc, null); |                 List<HostVO> hosts = _hostDao.search(sc, null); | ||||||
| @ -577,6 +605,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
| 
 | 
 | ||||||
|                 for (HostVO host : hosts) { |                 for (HostVO host : hosts) { | ||||||
|                     List<UserVmVO> vms = _userVmDao.listRunningByHostId(host.getId()); |                     List<UserVmVO> vms = _userVmDao.listRunningByHostId(host.getId()); | ||||||
|  |                     Date timestamp = new Date(); | ||||||
|  | 
 | ||||||
|                     List<Long> vmIds = new ArrayList<Long>(); |                     List<Long> vmIds = new ArrayList<Long>(); | ||||||
| 
 | 
 | ||||||
|                     for (UserVmVO vm : vms) { |                     for (UserVmVO vm : vms) { | ||||||
| @ -594,7 +624,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|                                 UserVmVO userVmVo = _userVmDao.findById(vmId); |                                 UserVmVO userVmVo = _userVmDao.findById(vmId); | ||||||
|                                 statsForCurrentIteration.setUserVmVO(userVmVo); |                                 statsForCurrentIteration.setUserVmVO(userVmVo); | ||||||
| 
 | 
 | ||||||
|                                 storeVirtualMachineStatsInMemory(statsForCurrentIteration); |                                 persistVirtualMachineStats(statsForCurrentIteration, timestamp); | ||||||
| 
 | 
 | ||||||
|                                 if (externalStatsType == ExternalStatsProtocol.GRAPHITE) { |                                 if (externalStatsType == ExternalStatsProtocol.GRAPHITE) { | ||||||
|                                     prepareVmMetricsForGraphite(metrics, statsForCurrentIteration); |                                     prepareVmMetricsForGraphite(metrics, statsForCurrentIteration); | ||||||
| @ -619,8 +649,6 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 cleanUpVirtualMachineStats(); |  | ||||||
| 
 |  | ||||||
|             } catch (Throwable t) { |             } catch (Throwable t) { | ||||||
|                 s_logger.error("Error trying to retrieve VM stats", t); |                 s_logger.error("Error trying to retrieve VM stats", t); | ||||||
|             } |             } | ||||||
| @ -632,8 +660,90 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public VmStats getVmStats(long id) { |     /** | ||||||
|         return _VmStats.get(id); |      * <p>Previously, the VM stats cleanup process was triggered during the data collection process. | ||||||
|  |      * So, when data collection was disabled, the cleaning process was also disabled.</p> | ||||||
|  |      * | ||||||
|  |      * <p>With the introduction of persistence of VM stats, as well as the provision of historical data, | ||||||
|  |      * we created this class to allow that both the collection process and the data cleaning process | ||||||
|  |      * can be enabled/disabled independently.</p> | ||||||
|  |      */ | ||||||
|  |     class VmStatsCleaner extends ManagedContextRunnable{ | ||||||
|  |         protected void runInContext() { | ||||||
|  |             cleanUpVirtualMachineStats(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Gets the latest or the accumulation of the stats collected from a given VM. | ||||||
|  |      * | ||||||
|  |      * @param vmId the specific VM. | ||||||
|  |      * @param accumulate whether or not the stats data should be accumulated. | ||||||
|  |      * @return the latest or the accumulation of the stats for the specified VM. | ||||||
|  |      */ | ||||||
|  |     public VmStats getVmStats(long vmId, Boolean accumulate) { | ||||||
|  |         List<VmStatsVO> vmStatsVOList = vmStatsDao.findByVmIdOrderByTimestampDesc(vmId); | ||||||
|  | 
 | ||||||
|  |         if (CollectionUtils.isEmpty(vmStatsVOList)) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (accumulate != null) { | ||||||
|  |             return getLatestOrAccumulatedVmMetricsStats(vmStatsVOList, accumulate.booleanValue()); | ||||||
|  |         } | ||||||
|  |         return getLatestOrAccumulatedVmMetricsStats(vmStatsVOList, BooleanUtils.toBoolean(vmStatsIncrementMetrics.value())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Gets the latest or the accumulation of a list of VM stats.<br> | ||||||
|  |      * It extracts the stats data from the VmStatsVO. | ||||||
|  |      * | ||||||
|  |      * @param vmStatsVOList the list of VM stats. | ||||||
|  |      * @param accumulate {@code true} if the data should be accumulated, {@code false} otherwise. | ||||||
|  |      * @return the {@link VmStatsEntry} containing the latest or the accumulated stats. | ||||||
|  |      */ | ||||||
|  |     protected VmStatsEntry getLatestOrAccumulatedVmMetricsStats (List<VmStatsVO> vmStatsVOList, boolean accumulate) { | ||||||
|  |         if (accumulate) { | ||||||
|  |             return accumulateVmMetricsStats(vmStatsVOList); | ||||||
|  |         } | ||||||
|  |         return gson.fromJson(vmStatsVOList.get(0).getVmStatsData(), VmStatsEntry.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Accumulates (I/O) stats for a given VM. | ||||||
|  |      * | ||||||
|  |      * @param vmStatsVOList the list of stats for a given VM. | ||||||
|  |      * @return the {@link VmStatsEntry} containing the accumulated (I/O) stats. | ||||||
|  |      */ | ||||||
|  |     protected VmStatsEntry accumulateVmMetricsStats(List<VmStatsVO> vmStatsVOList) { | ||||||
|  |         VmStatsEntry latestVmStats = gson.fromJson(vmStatsVOList.remove(0).getVmStatsData(), VmStatsEntry.class); | ||||||
|  | 
 | ||||||
|  |         VmStatsEntry vmStatsEntry = new VmStatsEntry(); | ||||||
|  |         vmStatsEntry.setEntityType(latestVmStats.getEntityType()); | ||||||
|  |         vmStatsEntry.setVmId(latestVmStats.getVmId()); | ||||||
|  |         vmStatsEntry.setCPUUtilization(latestVmStats.getCPUUtilization()); | ||||||
|  |         vmStatsEntry.setNumCPUs(latestVmStats.getNumCPUs()); | ||||||
|  |         vmStatsEntry.setMemoryKBs(latestVmStats.getMemoryKBs()); | ||||||
|  |         vmStatsEntry.setIntFreeMemoryKBs(latestVmStats.getIntFreeMemoryKBs()); | ||||||
|  |         vmStatsEntry.setTargetMemoryKBs(latestVmStats.getTargetMemoryKBs()); | ||||||
|  |         vmStatsEntry.setNetworkReadKBs(latestVmStats.getNetworkReadKBs()); | ||||||
|  |         vmStatsEntry.setNetworkWriteKBs(latestVmStats.getNetworkWriteKBs()); | ||||||
|  |         vmStatsEntry.setDiskWriteKBs(latestVmStats.getDiskWriteKBs()); | ||||||
|  |         vmStatsEntry.setDiskReadIOs(latestVmStats.getDiskReadIOs()); | ||||||
|  |         vmStatsEntry.setDiskWriteIOs(latestVmStats.getDiskWriteIOs()); | ||||||
|  |         vmStatsEntry.setDiskReadKBs(latestVmStats.getDiskReadKBs()); | ||||||
|  | 
 | ||||||
|  |         for (VmStatsVO vmStatsVO : vmStatsVOList) { | ||||||
|  |             VmStatsEntry currentVmStatsEntry = gson.fromJson(vmStatsVO.getVmStatsData(), VmStatsEntry.class); | ||||||
|  | 
 | ||||||
|  |             vmStatsEntry.setNetworkReadKBs(vmStatsEntry.getNetworkReadKBs() + currentVmStatsEntry.getNetworkReadKBs()); | ||||||
|  |             vmStatsEntry.setNetworkWriteKBs(vmStatsEntry.getNetworkWriteKBs() + currentVmStatsEntry.getNetworkWriteKBs()); | ||||||
|  |             vmStatsEntry.setDiskReadKBs(vmStatsEntry.getDiskReadKBs() + currentVmStatsEntry.getDiskReadKBs()); | ||||||
|  |             vmStatsEntry.setDiskWriteKBs(vmStatsEntry.getDiskWriteKBs() + currentVmStatsEntry.getDiskWriteKBs()); | ||||||
|  |             vmStatsEntry.setDiskReadIOs(vmStatsEntry.getDiskReadIOs() + currentVmStatsEntry.getDiskReadIOs()); | ||||||
|  |             vmStatsEntry.setDiskWriteIOs(vmStatsEntry.getDiskWriteIOs() + currentVmStatsEntry.getDiskWriteIOs()); | ||||||
|  |         } | ||||||
|  |         return vmStatsEntry; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     class VmDiskStatsUpdaterTask extends ManagedContextRunnable { |     class VmDiskStatsUpdaterTask extends ManagedContextRunnable { | ||||||
| @ -1460,57 +1570,36 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Stores virtual machine stats in memory (map of {@link VmStatsEntry}). |      * Persists VM stats in the database. | ||||||
|  |      * @param statsForCurrentIteration the metrics stats data to persist. | ||||||
|  |      * @param timestamp the time that will be stamped. | ||||||
|      */ |      */ | ||||||
|     private void storeVirtualMachineStatsInMemory(VmStatsEntry statsForCurrentIteration) { |     protected void persistVirtualMachineStats(VmStatsEntry statsForCurrentIteration, Date timestamp) { | ||||||
|         VmStatsEntry statsInMemory = (VmStatsEntry)_VmStats.get(statsForCurrentIteration.getVmId()); |         VmStatsEntryBase vmStats = new VmStatsEntryBase(statsForCurrentIteration.getVmId(), statsForCurrentIteration.getMemoryKBs(), statsForCurrentIteration.getIntFreeMemoryKBs(), | ||||||
| 
 |                 statsForCurrentIteration.getTargetMemoryKBs(), statsForCurrentIteration.getCPUUtilization(), statsForCurrentIteration.getNetworkReadKBs(), | ||||||
|         boolean vmStatsIncrementMetrics = BooleanUtils.toBoolean(VM_STATS_INCREMENT_METRICS_IN_MEMORY.value()); |                 statsForCurrentIteration.getNetworkWriteKBs(), statsForCurrentIteration.getNumCPUs(), statsForCurrentIteration.getDiskReadKBs(), | ||||||
|         if (statsInMemory == null || !vmStatsIncrementMetrics) { |                 statsForCurrentIteration.getDiskWriteKBs(), statsForCurrentIteration.getDiskReadIOs(), statsForCurrentIteration.getDiskWriteIOs(), | ||||||
|             _VmStats.put(statsForCurrentIteration.getVmId(), statsForCurrentIteration); |                 statsForCurrentIteration.getEntityType()); | ||||||
|         } else { |         VmStatsVO vmStatsVO = new VmStatsVO(statsForCurrentIteration.getVmId(), msId, timestamp, gson.toJson(vmStats)); | ||||||
|             s_logger.debug(String.format("Increment saved values of NetworkReadKBs, NetworkWriteKBs, DiskWriteKBs, DiskReadKBs, DiskReadIOs, DiskWriteIOs, with current metrics for VM with ID [%s]. " |         s_logger.trace(String.format("Recording VM stats: [%s].", vmStatsVO.toString())); | ||||||
|                     + "To change this process, check value of 'vm.stats.increment.metrics.in.memory' configuration.", statsForCurrentIteration.getVmId())); |         vmStatsDao.persist(vmStatsVO); | ||||||
|             statsInMemory.setCPUUtilization(statsForCurrentIteration.getCPUUtilization()); |  | ||||||
|             statsInMemory.setNumCPUs(statsForCurrentIteration.getNumCPUs()); |  | ||||||
|             statsInMemory.setNetworkReadKBs(statsInMemory.getNetworkReadKBs() + statsForCurrentIteration.getNetworkReadKBs()); |  | ||||||
|             statsInMemory.setNetworkWriteKBs(statsInMemory.getNetworkWriteKBs() + statsForCurrentIteration.getNetworkWriteKBs()); |  | ||||||
|             statsInMemory.setDiskWriteKBs(statsInMemory.getDiskWriteKBs() + statsForCurrentIteration.getDiskWriteKBs()); |  | ||||||
|             statsInMemory.setDiskReadIOs(statsInMemory.getDiskReadIOs() + statsForCurrentIteration.getDiskReadIOs()); |  | ||||||
|             statsInMemory.setDiskWriteIOs(statsInMemory.getDiskWriteIOs() + statsForCurrentIteration.getDiskWriteIOs()); |  | ||||||
|             statsInMemory.setDiskReadKBs(statsInMemory.getDiskReadKBs() + statsForCurrentIteration.getDiskReadKBs()); |  | ||||||
|             statsInMemory.setMemoryKBs(statsForCurrentIteration.getMemoryKBs()); |  | ||||||
|             statsInMemory.setIntFreeMemoryKBs(statsForCurrentIteration.getIntFreeMemoryKBs()); |  | ||||||
|             statsInMemory.setTargetMemoryKBs(statsForCurrentIteration.getTargetMemoryKBs()); |  | ||||||
| 
 |  | ||||||
|             _VmStats.put(statsForCurrentIteration.getVmId(), statsInMemory); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Removes stats for a given virtual machine. |      * Removes the oldest VM stats records according to the global | ||||||
|      * @param vmId ID of the virtual machine to remove stats. |      * parameter {@code vm.stats.max.retention.time}. | ||||||
|      */ |  | ||||||
|     public void removeVirtualMachineStats(Long vmId) { |  | ||||||
|         s_logger.debug(String.format("Removing stats from VM with ID: %s .",vmId)); |  | ||||||
|         _VmStats.remove(vmId); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Removes stats of virtual machines that are not running from memory. |  | ||||||
|      */ |      */ | ||||||
|     protected void cleanUpVirtualMachineStats() { |     protected void cleanUpVirtualMachineStats() { | ||||||
|         List<Long> allRunningVmIds = new ArrayList<Long>(); |         Integer maxRetentionTime = vmStatsMaxRetentionTime.value(); | ||||||
|         for (UserVmVO vm : _userVmDao.listAllRunning()) { |         if (maxRetentionTime <= 0) { | ||||||
|             allRunningVmIds.add(vm.getId()); |             s_logger.debug(String.format("Skipping VM stats cleanup. The [%s] parameter [%s] is set to 0 or less than 0.", | ||||||
|         } |                     vmStatsMaxRetentionTime.scope(), vmStatsMaxRetentionTime.toString())); | ||||||
| 
 |             return; | ||||||
|         List<Long> vmIdsToRemoveStats = new ArrayList<Long>(_VmStats.keySet()); |  | ||||||
|         vmIdsToRemoveStats.removeAll(allRunningVmIds); |  | ||||||
| 
 |  | ||||||
|         for (Long vmId : vmIdsToRemoveStats) { |  | ||||||
|             removeVirtualMachineStats(vmId); |  | ||||||
|         } |         } | ||||||
|  |         s_logger.trace("Removing older VM stats records."); | ||||||
|  |         Date now = new Date(); | ||||||
|  |         Date limit = DateUtils.addMinutes(now, -maxRetentionTime); | ||||||
|  |         vmStatsDao.removeAllByTimestampLessThan(limit); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -1657,7 +1746,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public ConfigKey<?>[] getConfigKeys() { |     public ConfigKey<?>[] getConfigKeys() { | ||||||
|         return new ConfigKey<?>[] {vmDiskStatsInterval, vmDiskStatsIntervalMin, vmNetworkStatsInterval, vmNetworkStatsIntervalMin, StatsTimeout, statsOutputUri, VM_STATS_INCREMENT_METRICS_IN_MEMORY}; |         return new ConfigKey<?>[] {vmDiskStatsInterval, vmDiskStatsIntervalMin, vmNetworkStatsInterval, vmNetworkStatsIntervalMin, StatsTimeout, statsOutputUri, | ||||||
|  |             vmStatsIncrementMetrics, vmStatsMaxRetentionTime}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public double getImageStoreCapacityThreshold() { |     public double getImageStoreCapacityThreshold() { | ||||||
|  | |||||||
| @ -356,6 +356,7 @@ import com.cloud.vm.dao.NicExtraDhcpOptionDao; | |||||||
| import com.cloud.vm.dao.UserVmDao; | import com.cloud.vm.dao.UserVmDao; | ||||||
| import com.cloud.vm.dao.UserVmDetailsDao; | import com.cloud.vm.dao.UserVmDetailsDao; | ||||||
| import com.cloud.vm.dao.VMInstanceDao; | import com.cloud.vm.dao.VMInstanceDao; | ||||||
|  | import com.cloud.vm.dao.VmStatsDao; | ||||||
| import com.cloud.vm.snapshot.VMSnapshotManager; | import com.cloud.vm.snapshot.VMSnapshotManager; | ||||||
| import com.cloud.vm.snapshot.VMSnapshotVO; | import com.cloud.vm.snapshot.VMSnapshotVO; | ||||||
| import com.cloud.vm.snapshot.dao.VMSnapshotDao; | import com.cloud.vm.snapshot.dao.VMSnapshotDao; | ||||||
| @ -549,6 +550,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir | |||||||
|     @Inject |     @Inject | ||||||
|     private AnnotationDao annotationDao; |     private AnnotationDao annotationDao; | ||||||
|     @Inject |     @Inject | ||||||
|  |     private VmStatsDao vmStatsDao; | ||||||
|  |     @Inject | ||||||
|     protected CommandSetupHelper commandSetupHelper; |     protected CommandSetupHelper commandSetupHelper; | ||||||
|     @Autowired |     @Autowired | ||||||
|     @Qualifier("networkHelper") |     @Qualifier("networkHelper") | ||||||
| @ -5061,8 +5064,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir | |||||||
|             throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId); |             throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         statsCollector.removeVirtualMachineStats(vmId); |  | ||||||
| 
 |  | ||||||
|         _userDao.findById(userId); |         _userDao.findById(userId); | ||||||
|         boolean status = false; |         boolean status = false; | ||||||
|         try { |         try { | ||||||
| @ -5375,7 +5376,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir | |||||||
|             return vm; |             return vm; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         statsCollector.removeVirtualMachineStats(vmId); |         vmStatsDao.removeAllByVmId(vmId); | ||||||
| 
 | 
 | ||||||
|         boolean status; |         boolean status; | ||||||
|         State vmState = vm.getState(); |         State vmState = vm.getState(); | ||||||
|  | |||||||
| @ -22,12 +22,13 @@ import java.net.URI; | |||||||
| import java.net.URISyntaxException; | import java.net.URISyntaxException; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
|  | import java.util.Date; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.concurrent.ConcurrentHashMap; |  | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| 
 | 
 | ||||||
|  | import org.apache.cloudstack.framework.config.ConfigKey; | ||||||
| import org.influxdb.InfluxDB; | import org.influxdb.InfluxDB; | ||||||
| import org.influxdb.InfluxDBFactory; | import org.influxdb.InfluxDBFactory; | ||||||
| import org.influxdb.dto.BatchPoints; | import org.influxdb.dto.BatchPoints; | ||||||
| @ -36,6 +37,8 @@ import org.influxdb.dto.Point; | |||||||
| import org.junit.Assert; | import org.junit.Assert; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import org.junit.runner.RunWith; | import org.junit.runner.RunWith; | ||||||
|  | import org.mockito.ArgumentCaptor; | ||||||
|  | import org.mockito.Captor; | ||||||
| import org.mockito.InjectMocks; | import org.mockito.InjectMocks; | ||||||
| import org.mockito.Mock; | import org.mockito.Mock; | ||||||
| import org.mockito.Mockito; | import org.mockito.Mockito; | ||||||
| @ -45,12 +48,13 @@ import org.powermock.modules.junit4.PowerMockRunner; | |||||||
| import org.powermock.modules.junit4.PowerMockRunnerDelegate; | import org.powermock.modules.junit4.PowerMockRunnerDelegate; | ||||||
| 
 | 
 | ||||||
| import com.cloud.agent.api.VmDiskStatsEntry; | import com.cloud.agent.api.VmDiskStatsEntry; | ||||||
|  | import com.cloud.agent.api.VmStatsEntry; | ||||||
| import com.cloud.server.StatsCollector.ExternalStatsProtocol; | import com.cloud.server.StatsCollector.ExternalStatsProtocol; | ||||||
| import com.cloud.user.VmDiskStatisticsVO; | import com.cloud.user.VmDiskStatisticsVO; | ||||||
| import com.cloud.utils.exception.CloudRuntimeException; | import com.cloud.utils.exception.CloudRuntimeException; | ||||||
| import com.cloud.vm.UserVmVO; |  | ||||||
| import com.cloud.vm.VmStats; | import com.cloud.vm.VmStats; | ||||||
| import com.cloud.vm.dao.UserVmDao; | import com.cloud.vm.VmStatsVO; | ||||||
|  | import com.cloud.vm.dao.VmStatsDao; | ||||||
| import com.tngtech.java.junit.dataprovider.DataProvider; | import com.tngtech.java.junit.dataprovider.DataProvider; | ||||||
| import com.tngtech.java.junit.dataprovider.DataProviderRunner; | import com.tngtech.java.junit.dataprovider.DataProviderRunner; | ||||||
| 
 | 
 | ||||||
| @ -70,16 +74,25 @@ public class StatsCollectorTest { | |||||||
|     private static final String DEFAULT_DATABASE_NAME = "cloudstack"; |     private static final String DEFAULT_DATABASE_NAME = "cloudstack"; | ||||||
| 
 | 
 | ||||||
|     @Mock |     @Mock | ||||||
|     ConcurrentHashMap<Long, VmStats> vmStatsMock; |     VmStatsDao vmStatsDaoMock; | ||||||
| 
 | 
 | ||||||
|     @Mock |     @Mock | ||||||
|     VmStats singleVmStatsMock; |     VmStatsEntry statsForCurrentIterationMock; | ||||||
|  | 
 | ||||||
|  |     @Captor | ||||||
|  |     ArgumentCaptor<VmStatsVO> vmStatsVOCaptor; | ||||||
|  | 
 | ||||||
|  |     @Captor | ||||||
|  |     ArgumentCaptor<Boolean> booleanCaptor; | ||||||
| 
 | 
 | ||||||
|     @Mock |     @Mock | ||||||
|     UserVmDao userVmDaoMock; |     Boolean accumulateMock; | ||||||
| 
 | 
 | ||||||
|     @Mock |     @Mock | ||||||
|     UserVmVO userVmVOMock; |     VmStatsVO vmStatsVoMock1, vmStatsVoMock2; | ||||||
|  | 
 | ||||||
|  |     @Mock | ||||||
|  |     VmStatsEntry vmStatsEntryMock; | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void createInfluxDbConnectionTest() { |     public void createInfluxDbConnectionTest() { | ||||||
| @ -240,47 +253,127 @@ public class StatsCollectorTest { | |||||||
|         Assert.assertEquals(expected, result); |         Assert.assertEquals(expected, result); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     private void setVmStatsIncrementMetrics(String value) { | ||||||
|     public void removeVirtualMachineStatsTestRemoveOneVmStats() { |         StatsCollector.vmStatsIncrementMetrics = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.stats.increment.metrics", value, | ||||||
|         Mockito.doReturn(new Object()).when(vmStatsMock).remove(Mockito.anyLong()); |                 "When set to 'true', VM metrics(NetworkReadKBs, NetworkWriteKBs, DiskWriteKBs, DiskReadKBs, DiskReadIOs and DiskWriteIOs) that are collected from the hypervisor are summed before being returned. " | ||||||
|  |                         + "On the other hand, when set to 'false', the VM metrics API will just display the latest metrics collected.", true); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         statsCollector.removeVirtualMachineStats(1l); |     private void setVmStatsMaxRetentionTimeValue(String value) { | ||||||
| 
 |         StatsCollector.vmStatsMaxRetentionTime = new ConfigKey<Integer>("Advanced", Integer.class, "vm.stats.max.retention.time", value, | ||||||
|         Mockito.verify(vmStatsMock, Mockito.times(1)).remove(Mockito.anyLong()); |                 "The maximum time (in minutes) for keeping VM stats records in the database. The VM stats cleanup process will be disabled if this is set to 0 or less than 0.", true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void cleanUpVirtualMachineStatsTestDoNothing() { |     public void cleanUpVirtualMachineStatsTestIsDisabled() { | ||||||
|         Mockito.doReturn(new ArrayList<>()).when(userVmDaoMock).listAllRunning(); |         setVmStatsMaxRetentionTimeValue("0"); | ||||||
|         Mockito.doReturn(new ConcurrentHashMap<Long, VmStats>(new HashMap<>()).keySet()) |  | ||||||
|         .when(vmStatsMock).keySet(); |  | ||||||
| 
 | 
 | ||||||
|         statsCollector.cleanUpVirtualMachineStats(); |         statsCollector.cleanUpVirtualMachineStats(); | ||||||
| 
 | 
 | ||||||
|         Mockito.verify(statsCollector, Mockito.never()).removeVirtualMachineStats(Mockito.anyLong()); |         Mockito.verify(vmStatsDaoMock, Mockito.never()).removeAllByTimestampLessThan(Mockito.any()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void cleanUpVirtualMachineStatsTestRemoveOneVmStats() { |     public void cleanUpVirtualMachineStatsTestIsEnabled() { | ||||||
|         Mockito.doReturn(new ArrayList<>()).when(userVmDaoMock).listAllRunning(); |         setVmStatsMaxRetentionTimeValue("1"); | ||||||
|         Mockito.doReturn(1l).when(userVmVOMock).getId(); |  | ||||||
|         Mockito.doReturn(new ConcurrentHashMap<Long, VmStats>(Map.of(1l, singleVmStatsMock)).keySet()) |  | ||||||
|         .when(vmStatsMock).keySet(); |  | ||||||
| 
 | 
 | ||||||
|         statsCollector.cleanUpVirtualMachineStats(); |         statsCollector.cleanUpVirtualMachineStats(); | ||||||
| 
 | 
 | ||||||
|         Mockito.verify(vmStatsMock, Mockito.times(1)).remove(Mockito.anyLong()); |         Mockito.verify(vmStatsDaoMock).removeAllByTimestampLessThan(Mockito.any()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void cleanUpVirtualMachineStatsTestRemoveOnlyOneVmStats() { |     public void persistVirtualMachineStatsTestPersistsSuccessfully() { | ||||||
|         Mockito.doReturn(1l).when(userVmVOMock).getId(); |         statsCollector.msId = 1L; | ||||||
|         Mockito.doReturn(Arrays.asList(userVmVOMock)).when(userVmDaoMock).listAllRunning(); |         Date timestamp = new Date(); | ||||||
|         Mockito.doReturn(new ConcurrentHashMap<Long, VmStats>(Map.of(1l, singleVmStatsMock, 2l, singleVmStatsMock)).keySet()) |         VmStatsEntry statsForCurrentIteration = new VmStatsEntry(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, "vm"); | ||||||
|         .when(vmStatsMock).keySet(); |         Mockito.doReturn(new VmStatsVO()).when(vmStatsDaoMock).persist(Mockito.any()); | ||||||
|  |         String expectedVmStatsStr = "{\"vmId\":2,\"cpuUtilization\":6.0,\"networkReadKBs\":7.0,\"networkWriteKBs\":8.0,\"diskReadIOs\":12.0,\"diskWriteIOs\":13.0,\"diskReadKBs\":10.0" | ||||||
|  |                 + ",\"diskWriteKBs\":11.0,\"memoryKBs\":3.0,\"intFreeMemoryKBs\":4.0,\"targetMemoryKBs\":5.0,\"numCPUs\":9,\"entityType\":\"vm\"}"; | ||||||
| 
 | 
 | ||||||
|         statsCollector.cleanUpVirtualMachineStats(); |         statsCollector.persistVirtualMachineStats(statsForCurrentIteration, timestamp); | ||||||
| 
 | 
 | ||||||
|         Mockito.verify(vmStatsMock, Mockito.times(1)).remove(Mockito.anyLong()); |         Mockito.verify(vmStatsDaoMock).persist(vmStatsVOCaptor.capture()); | ||||||
|  |         VmStatsVO actual = vmStatsVOCaptor.getAllValues().get(0); | ||||||
|  |         Assert.assertEquals(Long.valueOf(2L), actual.getVmId()); | ||||||
|  |         Assert.assertEquals(Long.valueOf(1L), actual.getMgmtServerId()); | ||||||
|  |         Assert.assertEquals(expectedVmStatsStr, actual.getVmStatsData()); | ||||||
|  |         Assert.assertEquals(timestamp, actual.getTimestamp()); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void getVmStatsTestWithAccumulateNotNull() { | ||||||
|  |         Mockito.doReturn(Arrays.asList(vmStatsVoMock1)).when(vmStatsDaoMock).findByVmIdOrderByTimestampDesc(Mockito.anyLong()); | ||||||
|  |         Mockito.doReturn(true).when(accumulateMock).booleanValue(); | ||||||
|  |         Mockito.doReturn(vmStatsEntryMock).when(statsCollector).getLatestOrAccumulatedVmMetricsStats(Mockito.anyList(), Mockito.anyBoolean()); | ||||||
|  | 
 | ||||||
|  |         VmStats result = statsCollector.getVmStats(1L, accumulateMock); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(statsCollector).getLatestOrAccumulatedVmMetricsStats(Mockito.anyList(), booleanCaptor.capture()); | ||||||
|  |         boolean actualArg = booleanCaptor.getValue().booleanValue(); | ||||||
|  |         Assert.assertEquals(false, actualArg); | ||||||
|  |         Assert.assertEquals(vmStatsEntryMock, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void getVmStatsTestWithNullAccumulate() { | ||||||
|  |         setVmStatsIncrementMetrics("true"); | ||||||
|  |         Mockito.doReturn(Arrays.asList(vmStatsVoMock1)).when(vmStatsDaoMock).findByVmIdOrderByTimestampDesc(Mockito.anyLong()); | ||||||
|  |         Mockito.doReturn(vmStatsEntryMock).when(statsCollector).getLatestOrAccumulatedVmMetricsStats(Mockito.anyList(), Mockito.anyBoolean()); | ||||||
|  | 
 | ||||||
|  |         VmStats result = statsCollector.getVmStats(1L, null); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(statsCollector).getLatestOrAccumulatedVmMetricsStats(Mockito.anyList(), booleanCaptor.capture()); | ||||||
|  |         boolean actualArg = booleanCaptor.getValue().booleanValue(); | ||||||
|  |         Assert.assertEquals(true, actualArg); | ||||||
|  |         Assert.assertEquals(vmStatsEntryMock, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void getLatestOrAccumulatedVmMetricsStatsTestAccumulate() { | ||||||
|  |         Mockito.doReturn(null).when(statsCollector).accumulateVmMetricsStats(Mockito.anyList()); | ||||||
|  | 
 | ||||||
|  |         statsCollector.getLatestOrAccumulatedVmMetricsStats(Arrays.asList(vmStatsVoMock1), true); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(statsCollector).accumulateVmMetricsStats(Mockito.anyList()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void getLatestOrAccumulatedVmMetricsStatsTestLatest() { | ||||||
|  |         statsCollector.getLatestOrAccumulatedVmMetricsStats(Arrays.asList(vmStatsVoMock1), false); | ||||||
|  | 
 | ||||||
|  |         Mockito.verify(statsCollector, Mockito.never()).accumulateVmMetricsStats(Mockito.anyList()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void accumulateVmMetricsStatsTest() { | ||||||
|  |         String fakeStatsData1 = "{\"vmId\":1,\"cpuUtilization\":1.0,\"networkReadKBs\":1.0," | ||||||
|  |                 + "\"networkWriteKBs\":1.1,\"diskReadIOs\":3.0,\"diskWriteIOs\":3.1,\"diskReadKBs\":2.0," | ||||||
|  |                 + "\"diskWriteKBs\":2.1,\"memoryKBs\":1.0,\"intFreeMemoryKBs\":1.0," | ||||||
|  |                 + "\"targetMemoryKBs\":1.0,\"numCPUs\":1,\"entityType\":\"vm\"}"; | ||||||
|  |         String fakeStatsData2 = "{\"vmId\":1,\"cpuUtilization\":10.0,\"networkReadKBs\":1.0," | ||||||
|  |                 + "\"networkWriteKBs\":1.1,\"diskReadIOs\":3.0,\"diskWriteIOs\":3.1,\"diskReadKBs\":2.0," | ||||||
|  |                 + "\"diskWriteKBs\":2.1,\"memoryKBs\":1.0,\"intFreeMemoryKBs\":1.0," | ||||||
|  |                 + "\"targetMemoryKBs\":1.0,\"numCPUs\":1,\"entityType\":\"vm\"}"; | ||||||
|  |         Mockito.doReturn(fakeStatsData1).when(vmStatsVoMock1).getVmStatsData(); | ||||||
|  |         Mockito.doReturn(fakeStatsData2).when(vmStatsVoMock2).getVmStatsData(); | ||||||
|  | 
 | ||||||
|  |         VmStatsEntry result = statsCollector.accumulateVmMetricsStats(new ArrayList<VmStatsVO>( | ||||||
|  |                 Arrays.asList(vmStatsVoMock1, vmStatsVoMock2))); | ||||||
|  | 
 | ||||||
|  |         Assert.assertEquals("vm", result.getEntityType()); | ||||||
|  |         Assert.assertEquals(1, result.getVmId()); | ||||||
|  |         Assert.assertEquals(1.0, result.getCPUUtilization(), 0); | ||||||
|  |         Assert.assertEquals(1, result.getNumCPUs()); | ||||||
|  |         Assert.assertEquals(1.0, result.getMemoryKBs(), 0); | ||||||
|  |         Assert.assertEquals(1.0, result.getIntFreeMemoryKBs(), 0); | ||||||
|  |         Assert.assertEquals(1.0, result.getTargetMemoryKBs(), 0); | ||||||
|  |         Assert.assertEquals(2.0, result.getNetworkReadKBs(), 0); | ||||||
|  |         Assert.assertEquals(2.2, result.getNetworkWriteKBs(), 0); | ||||||
|  |         Assert.assertEquals(4.0, result.getDiskReadKBs(), 0); | ||||||
|  |         Assert.assertEquals(4.2, result.getDiskWriteKBs(), 0); | ||||||
|  |         Assert.assertEquals(6.0, result.getDiskReadIOs(), 0); | ||||||
|  |         Assert.assertEquals(6.2, result.getDiskWriteIOs(), 0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -54,7 +54,6 @@ import com.cloud.event.UsageEventVO; | |||||||
| import com.cloud.exception.AgentUnavailableException; | import com.cloud.exception.AgentUnavailableException; | ||||||
| import com.cloud.exception.CloudException; | import com.cloud.exception.CloudException; | ||||||
| import com.cloud.exception.ConcurrentOperationException; | import com.cloud.exception.ConcurrentOperationException; | ||||||
| import com.cloud.server.StatsCollector; |  | ||||||
| import com.cloud.service.ServiceOfferingVO; | import com.cloud.service.ServiceOfferingVO; | ||||||
| import com.cloud.storage.Volume.Type; | import com.cloud.storage.Volume.Type; | ||||||
| import com.cloud.storage.VolumeVO; | import com.cloud.storage.VolumeVO; | ||||||
| @ -62,6 +61,7 @@ import com.cloud.vm.UserVmManager; | |||||||
| import com.cloud.vm.UserVmManagerImpl; | import com.cloud.vm.UserVmManagerImpl; | ||||||
| import com.cloud.vm.UserVmVO; | import com.cloud.vm.UserVmVO; | ||||||
| import com.cloud.vm.VirtualMachine; | import com.cloud.vm.VirtualMachine; | ||||||
|  | import com.cloud.vm.dao.VmStatsDao; | ||||||
| 
 | 
 | ||||||
| @RunWith(MockitoJUnitRunner.class) | @RunWith(MockitoJUnitRunner.class) | ||||||
| public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplTestBase { | public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplTestBase { | ||||||
| @ -77,7 +77,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT | |||||||
|     private UserVmManager userVmManager; |     private UserVmManager userVmManager; | ||||||
| 
 | 
 | ||||||
|     @Mock |     @Mock | ||||||
|     private StatsCollector statsCollectorMock; |     private VmStatsDao vmStatsDaoMock; | ||||||
| 
 | 
 | ||||||
|     Map<String, Object> oldFields = new HashMap<>(); |     Map<String, Object> oldFields = new HashMap<>(); | ||||||
|     UserVmVO vm = mock(UserVmVO.class); |     UserVmVO vm = mock(UserVmVO.class); | ||||||
| @ -204,7 +204,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT | |||||||
|     // volume. |     // volume. | ||||||
|     public void runningVMRootVolumeUsageEvent() |     public void runningVMRootVolumeUsageEvent() | ||||||
|             throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException { |             throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException { | ||||||
|         Mockito.doNothing().when(statsCollectorMock).removeVirtualMachineStats(Mockito.anyLong()); |         Mockito.doNothing().when(vmStatsDaoMock).removeAllByVmId(Mockito.anyLong()); | ||||||
|         Mockito.lenient().when(_vmMgr.destroyVm(nullable(Long.class), nullable(Boolean.class))).thenReturn(vm); |         Mockito.lenient().when(_vmMgr.destroyVm(nullable(Long.class), nullable(Boolean.class))).thenReturn(vm); | ||||||
|         List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false); |         List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false); | ||||||
|         UsageEventVO event = emittedEvents.get(0); |         UsageEventVO event = emittedEvents.get(0); | ||||||
|  | |||||||
| @ -31,6 +31,13 @@ export default { | |||||||
|       docHelp: 'adminguide/virtual_machines.html', |       docHelp: 'adminguide/virtual_machines.html', | ||||||
|       permission: ['listVirtualMachinesMetrics'], |       permission: ['listVirtualMachinesMetrics'], | ||||||
|       resourceType: 'UserVm', |       resourceType: 'UserVm', | ||||||
|  |       params: () => { | ||||||
|  |         var params = {} | ||||||
|  |         if (store.getters.metrics) { | ||||||
|  |           params = { state: 'running' } | ||||||
|  |         } | ||||||
|  |         return params | ||||||
|  |       }, | ||||||
|       filters: () => { |       filters: () => { | ||||||
|         const filters = ['running', 'stopped'] |         const filters = ['running', 'stopped'] | ||||||
|         if (!(store.getters.project && store.getters.project.id)) { |         if (!(store.getters.project && store.getters.project.id)) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user