CLOUDSTACK-1192: Add Disk I/O Statistics

This commit is contained in:
Wei Zhou 2013-06-01 08:00:48 +02:00
parent 8deeb90a6d
commit b9b0168da4
37 changed files with 2353 additions and 3 deletions

View File

@ -0,0 +1,30 @@
// 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;
public interface VmDiskStats {
// vm related disk stats
public Long getIORead();
public Long getIOWrite();
public Long getBytesRead();
public Long getBytesWrite();
}

View File

@ -23,5 +23,13 @@ public interface VmStats {
public double getNetworkReadKBs();
public double getNetworkWriteKBs();
public double getDiskReadIOs();
public double getDiskWriteIOs();
public double getDiskReadKBs();
public double getDiskWriteKBs();
}

View File

@ -137,6 +137,18 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp
@SerializedName("networkkbswrite") @Param(description="the outgoing network traffic on the host")
private Long networkKbsWrite;
@SerializedName("diskkbsread") @Param(description="the read (bytes) of disk on the vm")
private Long diskKbsRead;
@SerializedName("diskkbswrite") @Param(description="the write (bytes) of disk on the vm")
private Long diskKbsWrite;
@SerializedName("diskioread") @Param(description="the read (io) of disk on the vm")
private Long diskIORead;
@SerializedName("diskiowrite") @Param(description="the write (io) of disk on the vm")
private Long diskIOWrite;
@SerializedName("guestosid") @Param(description="Os type ID of the virtual machine")
private String guestOsId;
@ -300,6 +312,22 @@ public class UserVmResponse extends BaseResponse implements ControlledEntityResp
public void setIsoDisplayText(String isoDisplayText) {
this.isoDisplayText = isoDisplayText;
}
public void setDiskKbsRead(Long diskKbsRead) {
this.diskKbsRead = diskKbsRead;
}
public void setDiskKbsWrite(Long diskKbsWrite) {
this.diskKbsWrite = diskKbsWrite;
}
public void setDiskIORead(Long diskIORead) {
this.diskIORead = diskIORead;
}
public void setDiskIOWrite(Long diskIOWrite) {
this.diskIOWrite = diskIOWrite;
}
public void setServiceOfferingId(String serviceOfferingId) {
this.serviceOfferingId = serviceOfferingId;

View File

@ -36,6 +36,10 @@ public class UsageTypes {
public static final int PORT_FORWARDING_RULE = 12;
public static final int NETWORK_OFFERING = 13;
public static final int VPN_USERS = 14;
public static final int VM_DISK_IO_READ = 21;
public static final int VM_DISK_IO_WRITE = 22;
public static final int VM_DISK_BYTES_READ = 23;
public static final int VM_DISK_BYTES_WRITE = 24;
public static List<UsageTypeResponse> listUsageTypes(){
List<UsageTypeResponse> responseList = new ArrayList<UsageTypeResponse>();
@ -53,6 +57,10 @@ public class UsageTypes {
responseList.add(new UsageTypeResponse(PORT_FORWARDING_RULE, "Port Forwarding Usage"));
responseList.add(new UsageTypeResponse(NETWORK_OFFERING, "Network Offering Usage"));
responseList.add(new UsageTypeResponse(VPN_USERS, "VPN users usage"));
responseList.add(new UsageTypeResponse(VM_DISK_IO_READ, "VM Disk usage(I/O Read)"));
responseList.add(new UsageTypeResponse(VM_DISK_IO_WRITE, "VM Disk usage(I/O Write)"));
responseList.add(new UsageTypeResponse(VM_DISK_BYTES_READ, "VM Disk usage(Bytes Read)"));
responseList.add(new UsageTypeResponse(VM_DISK_BYTES_WRITE, "VM Disk usage(Bytes Write)"));
return responseList;
}
}

View File

@ -464,10 +464,14 @@ label.disabled=Disabled
label.disabling.vpn.access=Disabling VPN Access
label.disk.allocated=Disk Allocated
label.disk.offering=Disk Offering
label.disk.read.bytes=Disk Read (Bytes)
label.disk.read.io=Disk Read (IO)
label.disk.size.gb=Disk Size (in GB)
label.disk.size=Disk Size
label.disk.total=Disk Total
label.disk.volume=Disk Volume
label.disk.write.bytes=Disk Write (Bytes)
label.disk.write.io=Disk Write (IO)
label.display.name=Display name
label.display.text=Display Text
label.dns.1=DNS 1

View File

@ -341,11 +341,13 @@
<bean id="usageVMInstanceDaoImpl" class="com.cloud.usage.dao.UsageVMInstanceDaoImpl" />
<bean id="usageVPNUserDaoImpl" class="com.cloud.usage.dao.UsageVPNUserDaoImpl" />
<bean id="usageVolumeDaoImpl" class="com.cloud.usage.dao.UsageVolumeDaoImpl" />
<bean id="usageVmDiskDaoImpl" class="com.cloud.usage.dao.UsageVmDiskDaoImpl" />
<bean id="userAccountDaoImpl" class="com.cloud.user.dao.UserAccountDaoImpl" />
<bean id="userAccountJoinDaoImpl" class="com.cloud.api.query.dao.UserAccountJoinDaoImpl" />
<bean id="userIpv6AddressDaoImpl" class="com.cloud.network.dao.UserIpv6AddressDaoImpl" />
<bean id="userStatisticsDaoImpl" class="com.cloud.user.dao.UserStatisticsDaoImpl" />
<bean id="userStatsLogDaoImpl" class="com.cloud.user.dao.UserStatsLogDaoImpl" />
<bean id="userVmDiskStatsDaoImpl" class="com.cloud.user.dao.VmDiskStatisticsDaoImpl" />
<bean id="userVmCloneSettingDaoImpl" class="com.cloud.vm.dao.UserVmCloneSettingDaoImpl" />
<bean id="userVmDaoImpl" class="com.cloud.vm.dao.UserVmDaoImpl" />
<bean id="userVmDetailsDaoImpl" class="com.cloud.vm.dao.UserVmDetailsDaoImpl" />

View File

@ -0,0 +1,47 @@
// 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 java.util.HashMap;
import java.util.List;
import com.cloud.agent.api.LogLevel.Log4jLevel;
@LogLevel(Log4jLevel.Trace)
public class GetVmDiskStatsAnswer extends Answer {
String hostName;
HashMap<String, List<VmDiskStatsEntry>> vmDiskStatsMap;
public GetVmDiskStatsAnswer(GetVmDiskStatsCommand cmd, String details, String hostName, HashMap<String, List<VmDiskStatsEntry>> vmDiskStatsMap) {
super(cmd, true, details);
this.hostName = hostName;
this.vmDiskStatsMap = vmDiskStatsMap;
}
public String getHostName() {
return hostName;
}
public HashMap<String, List<VmDiskStatsEntry>> getVmDiskStatsMap() {
return vmDiskStatsMap;
}
protected GetVmDiskStatsAnswer() {
//no-args constructor for json serialization-deserialization
}
}

View File

@ -0,0 +1,54 @@
// 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 java.util.List;
import com.cloud.agent.api.LogLevel.Log4jLevel;
@LogLevel(Log4jLevel.Trace)
public class GetVmDiskStatsCommand extends Command {
List<String> vmNames;
String hostGuid;
String hostName;
protected GetVmDiskStatsCommand() {
}
public GetVmDiskStatsCommand(List<String> vmNames, String hostGuid, String hostName) {
this.vmNames = vmNames;
this.hostGuid = hostGuid;
this.hostName = hostName;
}
public List<String> getVmNames() {
return vmNames;
}
public String getHostGuid(){
return this.hostGuid;
}
public String getHostName(){
return this.hostName;
}
@Override
public boolean executeInSequence() {
return false;
}
}

View File

@ -0,0 +1,90 @@
// 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.VmDiskStats;
public class VmDiskStatsEntry implements VmDiskStats {
String vmName;
String path;
Long ioRead = 0L;
Long ioWrite = 0L;
Long bytesWrite = 0L;
Long bytesRead = 0L;
public VmDiskStatsEntry() {
}
public VmDiskStatsEntry(String vmName, String path, Long ioWrite, Long ioRead, Long bytesWrite, Long bytesRead) {
this.ioRead = ioRead;
this.ioWrite = ioWrite;
this.bytesRead = bytesRead;
this.bytesWrite = bytesWrite;
this.vmName = vmName;
this.path = path;
}
public void setVmName(String vmName) {
this.vmName = vmName;
}
public String getVmName() {
return vmName;
}
public void setPath(String path) {
this.path = path;
}
public String getPath() {
return path;
}
public void setBytesRead(Long bytesRead) {
this.bytesRead = bytesRead;
}
public Long getBytesRead() {
return bytesRead;
}
public void setBytesWrite(Long bytesWrite) {
this.bytesWrite = bytesWrite;
}
public Long getBytesWrite() {
return bytesWrite;
}
public void setIORead(Long ioRead) {
this.ioRead = ioRead;
}
public Long getIORead() {
return ioRead;
}
public void setIOWrite(Long ioWrite) {
this.ioWrite = ioWrite;
}
public Long getIOWrite() {
return ioWrite;
}
}

View File

@ -23,6 +23,10 @@ public class VmStatsEntry implements VmStats {
double cpuUtilization;
double networkReadKBs;
double networkWriteKBs;
double diskReadIOs;
double diskWriteIOs;
double diskReadKBs;
double diskWriteKBs;
int numCPUs;
String entityType;
@ -37,6 +41,18 @@ public class VmStatsEntry implements VmStats {
this.numCPUs = numCPUs;
this.entityType = entityType;
}
public VmStatsEntry(double cpuUtilization, double networkReadKBs, double networkWriteKBs,
double diskReadKBs, double diskWriteKBs, int numCPUs, String entityType)
{
this.cpuUtilization = cpuUtilization;
this.networkReadKBs = networkReadKBs;
this.networkWriteKBs = networkWriteKBs;
this.diskReadKBs = diskReadKBs;
this.diskWriteKBs = diskWriteKBs;
this.numCPUs = numCPUs;
this.entityType = entityType;
}
public double getCPUUtilization() {
return cpuUtilization;
@ -62,6 +78,38 @@ public class VmStatsEntry implements VmStats {
this.networkWriteKBs = networkWriteKBs;
}
public double getDiskReadIOs() {
return diskReadIOs;
}
public void setDiskReadIOs(double diskReadIOs) {
this.diskReadIOs = diskReadIOs;
}
public double getDiskWriteIOs() {
return diskWriteIOs;
}
public void setDiskWriteIOs(double diskWriteIOs) {
this.diskWriteIOs = diskWriteIOs;
}
public double getDiskReadKBs() {
return diskReadKBs;
}
public void setDiskReadKBs(double diskReadKBs) {
this.diskReadKBs = diskReadKBs;
}
public double getDiskWriteKBs() {
return diskWriteKBs;
}
public void setDiskWriteKBs(double diskWriteKBs) {
this.diskWriteKBs = diskWriteKBs;
}
public int getNumCPUs() {
return numCPUs;
}

View File

@ -0,0 +1,180 @@
// 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.usage;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="usage_vm_disk")
public class UsageVmDiskVO {
@Id
@Column(name="account_id")
private long accountId;
@Column(name="zone_id")
private long zoneId;
@Column(name="vm_id")
private Long vmId;
@Column(name="volume_id")
private Long volumeId;
@Column(name="io_read")
private long ioRead;
@Column(name="io_write")
private long ioWrite;
@Column(name="agg_io_write")
private long aggIOWrite;
@Column(name="agg_io_read")
private long aggIORead;
@Column(name="bytes_read")
private long bytesRead;
@Column(name="bytes_write")
private long bytesWrite;
@Column(name="agg_bytes_write")
private long aggBytesWrite;
@Column(name="agg_bytes_read")
private long aggBytesRead;
@Column(name="event_time_millis")
private long eventTimeMillis = 0;
protected UsageVmDiskVO() {
}
public UsageVmDiskVO(Long accountId, long zoneId, Long vmId, Long volumeId, long ioRead, long ioWrite, long aggIORead, long aggIOWrite,
long bytesRead, long bytesWrite, long aggBytesRead, long aggBytesWrite, long eventTimeMillis) {
this.accountId = accountId;
this.zoneId = zoneId;
this.vmId = vmId;
this.volumeId = volumeId;
this.ioRead = ioRead;
this.ioWrite = ioWrite;
this.aggIOWrite = aggIOWrite;
this.aggIORead = aggIORead;
this.bytesRead = bytesRead;
this.bytesWrite = bytesWrite;
this.aggBytesWrite = aggBytesWrite;
this.aggBytesRead = aggBytesRead;
this.eventTimeMillis = eventTimeMillis;
}
public long getAccountId() {
return accountId;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
public long getZoneId() {
return zoneId;
}
public void setZoneId(long zoneId) {
this.zoneId = zoneId;
}
public Long getIORead() {
return ioRead;
}
public void setIORead(Long ioRead) {
this.ioRead = ioRead;
}
public Long getIOWrite() {
return ioWrite;
}
public void setIOWrite(Long ioWrite) {
this.ioWrite = ioWrite;
}
public Long getBytesRead() {
return bytesRead;
}
public void setBytesRead(Long bytesRead) {
this.bytesRead = bytesRead;
}
public Long getBytesWrite() {
return bytesWrite;
}
public void setBytesWrite(Long bytesWrite) {
this.bytesWrite = bytesWrite;
}
public long getEventTimeMillis() {
return eventTimeMillis;
}
public void setEventTimeMillis(long eventTimeMillis) {
this.eventTimeMillis = eventTimeMillis;
}
public Long getVmId() {
return vmId;
}
public Long getVolumeId() {
return volumeId;
}
public long getAggIOWrite() {
return aggIOWrite;
}
public void setAggIOWrite(long aggIOWrite) {
this.aggIOWrite = aggIOWrite;
}
public long getAggIORead() {
return aggIORead;
}
public void setAggIORead(long aggIORead) {
this.aggIORead = aggIORead;
}
public long getAggBytesWrite() {
return aggBytesWrite;
}
public void setAggBytesWrite(long aggBytesWrite) {
this.aggBytesWrite = aggBytesWrite;
}
public long getAggBytesRead() {
return aggBytesRead;
}
public void setAggBytesRead(long aggBytesRead) {
this.aggBytesRead = aggBytesRead;
}
}

View File

@ -21,6 +21,7 @@ import java.util.List;
import com.cloud.usage.UsageVO;
import com.cloud.user.AccountVO;
import com.cloud.user.UserStatisticsVO;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.SearchCriteria;
@ -36,4 +37,7 @@ public interface UsageDao extends GenericDao<UsageVO, Long> {
Long getLastAccountId();
Long getLastUserStatsId();
List<Long> listPublicTemplatesByAccount(long accountId);
Long getLastVmDiskStatsId();
void updateVmDiskStats(List<VmDiskStatisticsVO> vmNetStats);
void saveVmDiskStats(List<VmDiskStatisticsVO> vmNetStats);
}

View File

@ -32,6 +32,7 @@ import org.springframework.stereotype.Component;
import com.cloud.usage.UsageVO;
import com.cloud.user.AccountVO;
import com.cloud.user.UserStatisticsVO;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.utils.DateUtil;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
@ -56,6 +57,13 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
private static final String GET_LAST_USER_STATS = "SELECT id FROM cloud_usage.user_statistics ORDER BY id DESC LIMIT 1";
private static final String GET_PUBLIC_TEMPLATES_BY_ACCOUNTID = "SELECT id FROM cloud.vm_template WHERE account_id = ? AND public = '1' AND removed IS NULL";
private static final String GET_LAST_VM_DISK_STATS = "SELECT id FROM cloud_usage.vm_disk_statistics ORDER BY id DESC LIMIT 1";
private static final String INSERT_VM_DISK_STATS = "INSERT INTO cloud_usage.vm_disk_statistics (id, data_center_id, account_id, vm_id, volume_id, net_io_read, net_io_write, current_io_read, " +
"current_io_write, agg_io_read, agg_io_write, net_bytes_read, net_bytes_write, current_bytes_read, current_bytes_write, agg_bytes_read, agg_bytes_write) " +
" VALUES (?,?,?,?,?,?,?,?,?,?, ?, ?, ?, ?,?, ?, ?)";
private static final String UPDATE_VM_DISK_STATS = "UPDATE cloud_usage.vm_disk_statistics SET net_io_read=?, net_io_write=?, current_io_read=?, current_io_write=?, agg_io_read=?, agg_io_write=?, " +
"net_bytes_read=?, net_bytes_write=?, current_bytes_read=?, current_bytes_write=?, agg_bytes_read=?, agg_bytes_write=? WHERE id=?";
protected final static TimeZone s_gmtTimeZone = TimeZone.getTimeZone("GMT");
public UsageDaoImpl () {}
@ -270,4 +278,101 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
}
return templateList;
}
@Override
public Long getLastVmDiskStatsId() {
Transaction txn = Transaction.currentTxn();
PreparedStatement pstmt = null;
String sql = GET_LAST_VM_DISK_STATS;
try {
pstmt = txn.prepareAutoCloseStatement(sql);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
return Long.valueOf(rs.getLong(1));
}
} catch (Exception ex) {
s_logger.error("error getting last vm disk stats id", ex);
}
return null;
}
@Override
public void updateVmDiskStats(List<VmDiskStatisticsVO> vmDiskStats) {
Transaction txn = Transaction.currentTxn();
try {
txn.start();
String sql = UPDATE_VM_DISK_STATS;
PreparedStatement pstmt = null;
pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
for (VmDiskStatisticsVO vmDiskStat : vmDiskStats) {
pstmt.setLong(1, vmDiskStat.getNetIORead());
pstmt.setLong(2, vmDiskStat.getNetIOWrite());
pstmt.setLong(3, vmDiskStat.getCurrentIORead());
pstmt.setLong(4, vmDiskStat.getCurrentIOWrite());
pstmt.setLong(5, vmDiskStat.getAggIORead());
pstmt.setLong(6, vmDiskStat.getAggIOWrite());
pstmt.setLong(7, vmDiskStat.getNetBytesRead());
pstmt.setLong(8, vmDiskStat.getNetBytesWrite());
pstmt.setLong(9, vmDiskStat.getCurrentBytesRead());
pstmt.setLong(10, vmDiskStat.getCurrentBytesWrite());
pstmt.setLong(11, vmDiskStat.getAggBytesRead());
pstmt.setLong(12, vmDiskStat.getAggBytesWrite());
pstmt.setLong(13, vmDiskStat.getId());
pstmt.addBatch();
}
pstmt.executeBatch();
txn.commit();
} catch (Exception ex) {
txn.rollback();
s_logger.error("error saving vm disk stats to cloud_usage db", ex);
throw new CloudRuntimeException(ex.getMessage());
}
}
@Override
public void saveVmDiskStats(List<VmDiskStatisticsVO> vmDiskStats) {
Transaction txn = Transaction.currentTxn();
try {
txn.start();
String sql = INSERT_VM_DISK_STATS;
PreparedStatement pstmt = null;
pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
for (VmDiskStatisticsVO vmDiskStat : vmDiskStats) {
pstmt.setLong(1, vmDiskStat.getId());
pstmt.setLong(2, vmDiskStat.getDataCenterId());
pstmt.setLong(3, vmDiskStat.getAccountId());
if(vmDiskStat.getVmId() != null){
pstmt.setLong(4, vmDiskStat.getVmId());
} else {
pstmt.setNull(4, Types.BIGINT);
}
if(vmDiskStat.getVolumeId() != null){
pstmt.setLong(5, vmDiskStat.getVolumeId());
} else {
pstmt.setNull(5, Types.BIGINT);
}
pstmt.setLong(6, vmDiskStat.getNetIORead());
pstmt.setLong(7, vmDiskStat.getNetIOWrite());
pstmt.setLong(8, vmDiskStat.getCurrentIORead());
pstmt.setLong(9, vmDiskStat.getCurrentIOWrite());
pstmt.setLong(10, vmDiskStat.getAggIORead());
pstmt.setLong(11, vmDiskStat.getAggIOWrite());
pstmt.setLong(12, vmDiskStat.getNetBytesRead());
pstmt.setLong(13, vmDiskStat.getNetBytesWrite());
pstmt.setLong(14, vmDiskStat.getCurrentBytesRead());
pstmt.setLong(15, vmDiskStat.getCurrentBytesWrite());
pstmt.setLong(16, vmDiskStat.getAggBytesRead());
pstmt.setLong(17, vmDiskStat.getAggBytesWrite());
pstmt.addBatch();
}
pstmt.executeBatch();
txn.commit();
} catch (Exception ex) {
txn.rollback();
s_logger.error("error saving vm disk stats to cloud_usage db", ex);
throw new CloudRuntimeException(ex.getMessage());
}
}
}

View File

@ -0,0 +1,29 @@
// 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.usage.dao;
import java.util.List;
import java.util.Map;
import com.cloud.usage.UsageVmDiskVO;
import com.cloud.utils.db.GenericDao;
public interface UsageVmDiskDao extends GenericDao<UsageVmDiskVO, Long> {
Map<String, UsageVmDiskVO> getRecentVmDiskStats();
void deleteOldStats(long maxEventTime);
void saveUsageVmDisks(List<UsageVmDiskVO> usageVmDisks);
}

View File

@ -0,0 +1,139 @@
// 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.usage.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.usage.UsageVmDiskVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
@Local(value={UsageVmDiskDao.class})
public class UsageVmDiskDaoImpl extends GenericDaoBase<UsageVmDiskVO, Long> implements UsageVmDiskDao {
private static final Logger s_logger = Logger.getLogger(UsageVMInstanceDaoImpl.class.getName());
private static final String SELECT_LATEST_STATS = "SELECT uvd.account_id, uvd.zone_id, uvd.vm_id, uvd.volume_id, uvd.io_read, uvd.io_write, uvd.agg_io_read, uvd.agg_io_write, " +
"uvd.bytes_read, uvd.bytes_write, uvd.agg_bytes_read, uvd.agg_bytes_write, uvd.event_time_millis " +
"FROM cloud_usage.usage_vm_disk uvd INNER JOIN (SELECT vmdiskusage.account_id as acct_id, vmdiskusage.zone_id as z_id, max(vmdiskusage.event_time_millis) as max_date " +
"FROM cloud_usage.usage_vm_disk vmdiskusage " +
"GROUP BY vmdiskusage.account_id, vmdiskusage.zone_id " +
") joinnet on uvd.account_id = joinnet.acct_id and uvd.zone_id = joinnet.z_id and uvd.event_time_millis = joinnet.max_date";
private static final String DELETE_OLD_STATS = "DELETE FROM cloud_usage.usage_vm_disk WHERE event_time_millis < ?";
private static final String INSERT_USAGE_VM_DISK = "INSERT INTO cloud_usage.usage_vm_disk (account_id, zone_id, vm_id, volume_id, io_read, io_write, agg_io_read, agg_io_write, bytes_read, bytes_write, agg_bytes_read, agg_bytes_write, event_time_millis) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)";
public UsageVmDiskDaoImpl() {
}
@Override
public Map<String, UsageVmDiskVO> getRecentVmDiskStats() {
Transaction txn = Transaction.open(Transaction.USAGE_DB);
String sql = SELECT_LATEST_STATS;
PreparedStatement pstmt = null;
try {
pstmt = txn.prepareAutoCloseStatement(sql);
ResultSet rs = pstmt.executeQuery();
Map<String, UsageVmDiskVO> returnMap = new HashMap<String, UsageVmDiskVO>();
while (rs.next()) {
long accountId = rs.getLong(1);
long zoneId = rs.getLong(2);
long vmId = rs.getLong(3);
Long volumeId = rs.getLong(4);
long ioRead = rs.getLong(5);
long ioWrite = rs.getLong(6);
long aggIORead = rs.getLong(7);
long aggIOWrite = rs.getLong(8);
long bytesRead = rs.getLong(9);
long bytesWrite = rs.getLong(10);
long aggBytesRead = rs.getLong(11);
long aggBytesWrite = rs.getLong(12);
long eventTimeMillis = rs.getLong(13);
if(vmId != 0){
returnMap.put(zoneId + "-" + accountId+ "-Vm-" + vmId+ "-Disk-" + volumeId, new UsageVmDiskVO(accountId, zoneId, vmId, volumeId, ioRead, ioWrite, aggIORead, aggIOWrite, bytesRead, bytesWrite, aggBytesRead, aggBytesWrite, eventTimeMillis));
} else {
returnMap.put(zoneId + "-" + accountId, new UsageVmDiskVO(accountId, zoneId, vmId, volumeId, ioRead, ioWrite, aggIORead, aggIOWrite, bytesRead, bytesWrite, aggBytesRead, aggBytesWrite, eventTimeMillis));
}
}
return returnMap;
} catch (Exception ex) {
s_logger.error("error getting recent usage disk stats", ex);
} finally {
txn.close();
}
return null;
}
@Override
public void deleteOldStats(long maxEventTime) {
Transaction txn = Transaction.currentTxn();
String sql = DELETE_OLD_STATS;
PreparedStatement pstmt = null;
try {
txn.start();
pstmt = txn.prepareAutoCloseStatement(sql);
pstmt.setLong(1, maxEventTime);
pstmt.executeUpdate();
txn.commit();
} catch (Exception ex) {
txn.rollback();
s_logger.error("error deleting old usage disk stats", ex);
}
}
@Override
public void saveUsageVmDisks(List<UsageVmDiskVO> usageVmDisks) {
Transaction txn = Transaction.currentTxn();
try {
txn.start();
String sql = INSERT_USAGE_VM_DISK;
PreparedStatement pstmt = null;
pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
for (UsageVmDiskVO usageVmDisk : usageVmDisks) {
pstmt.setLong(1, usageVmDisk.getAccountId());
pstmt.setLong(2, usageVmDisk.getZoneId());
pstmt.setLong(3, usageVmDisk.getVmId());
pstmt.setLong(4, usageVmDisk.getVolumeId());
pstmt.setLong(5, usageVmDisk.getIORead());
pstmt.setLong(6, usageVmDisk.getIOWrite());
pstmt.setLong(7, usageVmDisk.getAggIORead());
pstmt.setLong(8, usageVmDisk.getAggIOWrite());
pstmt.setLong(9, usageVmDisk.getBytesRead());
pstmt.setLong(10, usageVmDisk.getBytesWrite());
pstmt.setLong(11, usageVmDisk.getAggBytesRead());
pstmt.setLong(12, usageVmDisk.getAggBytesWrite());
pstmt.setLong(13, usageVmDisk.getEventTimeMillis());
pstmt.addBatch();
}
pstmt.executeBatch();
txn.commit();
} catch (Exception ex) {
txn.rollback();
s_logger.error("error saving usage_vm_disk to cloud_usage db", ex);
throw new CloudRuntimeException(ex.getMessage());
}
}
}

View File

@ -0,0 +1,216 @@
// 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.user;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="vm_disk_statistics")
public class VmDiskStatisticsVO {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private Long id;
@Column(name="data_center_id", updatable=false)
private long dataCenterId;
@Column(name="account_id", updatable=false)
private long accountId;
@Column(name="vm_id")
private Long vmId;
@Column(name="volume_id")
private Long volumeId;
@Column(name="net_io_read")
private long netIORead;
@Column(name="net_io_write")
private long netIOWrite;
@Column(name="current_io_read")
private long currentIORead;
@Column(name="current_io_write")
private long currentIOWrite;
@Column(name="agg_io_read")
private long aggIORead;
@Column(name="agg_io_write")
private long aggIOWrite;
@Column(name="net_bytes_read")
private long netBytesRead;
@Column(name="net_bytes_write")
private long netBytesWrite;
@Column(name="current_bytes_read")
private long currentBytesRead;
@Column(name="current_bytes_write")
private long currentBytesWrite;
@Column(name="agg_bytes_read")
private long aggBytesRead;
@Column(name="agg_bytes_write")
private long aggBytesWrite;
protected VmDiskStatisticsVO() {
}
public VmDiskStatisticsVO(long accountId, long dcId, Long vmId, Long volumeId) {
this.accountId = accountId;
this.dataCenterId = dcId;
this.vmId = vmId;
this.volumeId = volumeId;
this.netBytesRead = 0;
this.netBytesWrite = 0;
this.currentBytesRead = 0;
this.currentBytesWrite = 0;
this.netBytesRead = 0;
this.netBytesWrite = 0;
this.currentBytesRead = 0;
this.currentBytesWrite = 0;
}
public long getAccountId() {
return accountId;
}
public Long getId() {
return id;
}
public long getDataCenterId() {
return dataCenterId;
}
public Long getVmId() {
return vmId;
}
public Long getVolumeId() {
return volumeId;
}
public long getCurrentIORead() {
return currentIORead;
}
public void setCurrentIORead(long currentIORead) {
this.currentIORead = currentIORead;
}
public long getCurrentIOWrite() {
return currentIOWrite;
}
public void setCurrentIOWrite(long currentIOWrite) {
this.currentIOWrite = currentIOWrite;
}
public long getNetIORead() {
return netIORead;
}
public long getNetIOWrite() {
return netIOWrite;
}
public void setNetIORead(long netIORead) {
this.netIORead = netIORead;
}
public void setNetIOWrite(long netIOWrite) {
this.netIOWrite = netIOWrite;
}
public long getAggIORead() {
return aggIORead;
}
public void setAggIORead(long aggIORead) {
this.aggIORead = aggIORead;
}
public long getAggIOWrite() {
return aggIOWrite;
}
public void setAggIOWrite(long aggIOWrite) {
this.aggIOWrite = aggIOWrite;
}
public long getCurrentBytesRead() {
return currentBytesRead;
}
public void setCurrentBytesRead(long currentBytesRead) {
this.currentBytesRead = currentBytesRead;
}
public long getCurrentBytesWrite() {
return currentBytesWrite;
}
public void setCurrentBytesWrite(long currentBytesWrite) {
this.currentBytesWrite = currentBytesWrite;
}
public long getNetBytesRead() {
return netBytesRead;
}
public long getNetBytesWrite() {
return netBytesWrite;
}
public void setNetBytesRead(long netBytesRead) {
this.netBytesRead = netBytesRead;
}
public void setNetBytesWrite(long netBytesWrite) {
this.netBytesWrite = netBytesWrite;
}
public long getAggBytesRead() {
return aggBytesRead;
}
public void setAggBytesRead(long aggBytesRead) {
this.aggBytesRead = aggBytesRead;
}
public long getAggBytesWrite() {
return aggBytesWrite;
}
public void setAggBytesWrite(long aggBytesWrite) {
this.aggBytesWrite = aggBytesWrite;
}
}

View File

@ -0,0 +1,35 @@
// 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.user.dao;
import java.util.Date;
import java.util.List;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.utils.db.GenericDao;
public interface VmDiskStatisticsDao extends GenericDao<VmDiskStatisticsVO, Long> {
VmDiskStatisticsVO findBy(long accountId, long dcId, long vmId, long volumeId);
VmDiskStatisticsVO lock(long accountId, long dcId, long vmId, long volumeId);
List<VmDiskStatisticsVO> listBy(long accountId);
List<VmDiskStatisticsVO> listActiveAndRecentlyDeleted(Date minRemovedDate, int startIndex, int limit);
List<VmDiskStatisticsVO> listUpdatedStats();
}

View File

@ -0,0 +1,134 @@
// 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.user.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.utils.DateUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
@Component
@Local(value={VmDiskStatisticsDao.class})
public class VmDiskStatisticsDaoImpl extends GenericDaoBase<VmDiskStatisticsVO, Long> implements VmDiskStatisticsDao {
private static final Logger s_logger = Logger.getLogger(VmDiskStatisticsDaoImpl.class);
private static final String ACTIVE_AND_RECENTLY_DELETED_SEARCH = "SELECT vns.id, vns.data_center_id, vns.account_id, vns.vm_id, vns.volume_id, vns.agg_io_read, vns.agg_io_write, vns.agg_bytes_read, vns.agg_bytes_write " +
"FROM vm_disk_statistics vns, account a " +
"WHERE vns.account_id = a.id AND (a.removed IS NULL OR a.removed >= ?) " +
"ORDER BY vns.id";
private static final String UPDATED_VM_NETWORK_STATS_SEARCH = "SELECT id, current_io_read, current_io_write, net_io_read, net_io_write, agg_io_read, agg_io_write, " +
"current_bytes_read, current_bytes_write, net_bytes_read, net_bytes_write, agg_bytes_read, agg_bytes_write " +
"from vm_disk_statistics " +
"where (agg_io_read < net_io_read + current_io_read) OR (agg_io_write < net_io_write + current_io_write) OR " +
"(agg_bytes_read < net_bytes_read + current_bytes_read) OR (agg_bytes_write < net_bytes_write + current_bytes_write)";
private final SearchBuilder<VmDiskStatisticsVO> AllFieldsSearch;
private final SearchBuilder<VmDiskStatisticsVO> AccountSearch;
public VmDiskStatisticsDaoImpl() {
AccountSearch = createSearchBuilder();
AccountSearch.and("account", AccountSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
AccountSearch.done();
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and("account", AllFieldsSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("dc", AllFieldsSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("volume", AllFieldsSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("vm", AllFieldsSearch.entity().getVmId(), SearchCriteria.Op.EQ);
AllFieldsSearch.done();
}
@Override
public VmDiskStatisticsVO findBy(long accountId, long dcId, long vmId, long volumeId) {
SearchCriteria<VmDiskStatisticsVO> sc = AllFieldsSearch.create();
sc.setParameters("account", accountId);
sc.setParameters("dc", dcId);
sc.setParameters("volume", volumeId);
sc.setParameters("vm", vmId);
return findOneBy(sc);
}
@Override
public VmDiskStatisticsVO lock(long accountId, long dcId, long vmId, long volumeId) {
SearchCriteria<VmDiskStatisticsVO> sc = AllFieldsSearch.create();
sc.setParameters("account", accountId);
sc.setParameters("dc", dcId);
sc.setParameters("volume", volumeId);
sc.setParameters("vm", vmId);
return lockOneRandomRow(sc, true);
}
@Override
public List<VmDiskStatisticsVO> listBy(long accountId) {
SearchCriteria<VmDiskStatisticsVO> sc = AccountSearch.create();
sc.setParameters("account", accountId);
return search(sc, null);
}
@Override
public List<VmDiskStatisticsVO> listActiveAndRecentlyDeleted(Date minRemovedDate, int startIndex, int limit) {
List<VmDiskStatisticsVO> vmDiskStats = new ArrayList<VmDiskStatisticsVO>();
if (minRemovedDate == null) return vmDiskStats;
Transaction txn = Transaction.currentTxn();
try {
String sql = ACTIVE_AND_RECENTLY_DELETED_SEARCH + " LIMIT " + startIndex + "," + limit;
PreparedStatement pstmt = null;
pstmt = txn.prepareAutoCloseStatement(sql);
pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), minRemovedDate));
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
vmDiskStats.add(toEntityBean(rs, false));
}
} catch (Exception ex) {
s_logger.error("error saving vm disk stats to cloud_usage db", ex);
}
return vmDiskStats;
}
@Override
public List<VmDiskStatisticsVO> listUpdatedStats() {
List<VmDiskStatisticsVO> vmDiskStats = new ArrayList<VmDiskStatisticsVO>();
Transaction txn = Transaction.currentTxn();
try {
PreparedStatement pstmt = null;
pstmt = txn.prepareAutoCloseStatement(UPDATED_VM_NETWORK_STATS_SEARCH);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
vmDiskStats.add(toEntityBean(rs, false));
}
} catch (Exception ex) {
s_logger.error("error lisitng updated vm disk stats", ex);
}
return vmDiskStats;
}
}

View File

@ -57,6 +57,10 @@ public class UserVmData {
private String cpuUsed;
private Long networkKbsRead;
private Long networkKbsWrite;
private Long diskKbsRead;
private Long diskKbsWrite;
private Long diskIORead;
private Long diskIOWrite;
private Long guestOsId;
private Long rootDeviceId;
private String rootDeviceType;
@ -364,6 +368,38 @@ public class UserVmData {
this.networkKbsWrite = networkKbsWrite;
}
public Long getDiskKbsRead() {
return diskKbsRead;
}
public void setDiskKbsRead(Long diskKbsRead) {
this.diskKbsRead = diskKbsRead;
}
public Long getDiskKbsWrite() {
return diskKbsWrite;
}
public void setDiskKbsWrite(Long diskKbsWrite) {
this.diskKbsWrite = diskKbsWrite;
}
public Long getDiskIORead() {
return diskIORead;
}
public void setDiskIORead(Long diskIORead) {
this.diskIORead = diskIORead;
}
public Long getDiskIOWrite() {
return diskIOWrite;
}
public void setDiskIOWrite(Long diskIOWrite) {
this.diskIOWrite = diskIOWrite;
}
public Long getGuestOsId() {
return guestOsId;
}

View File

@ -63,6 +63,7 @@ import org.apache.cloudstack.utils.qemu.QemuImgFile;
import org.apache.cloudstack.utils.qemu.QemuImgException;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.DomainBlockStats;
import org.libvirt.DomainInfo;
import org.libvirt.DomainInterfaceStats;
import org.libvirt.DomainSnapshot;
@ -99,6 +100,8 @@ import com.cloud.agent.api.GetHostStatsAnswer;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetStorageStatsAnswer;
import com.cloud.agent.api.GetStorageStatsCommand;
import com.cloud.agent.api.GetVmDiskStatsAnswer;
import com.cloud.agent.api.GetVmDiskStatsCommand;
import com.cloud.agent.api.GetVmStatsAnswer;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.GetVncPortAnswer;
@ -145,6 +148,7 @@ import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.UnPlugNicAnswer;
import com.cloud.agent.api.UnPlugNicCommand;
import com.cloud.agent.api.UpgradeSnapshotCommand;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.check.CheckSshAnswer;
import com.cloud.agent.api.check.CheckSshCommand;
@ -1117,6 +1121,8 @@ ServerResource {
return execute((StopCommand) cmd);
} else if (cmd instanceof GetVmStatsCommand) {
return execute((GetVmStatsCommand) cmd);
} else if (cmd instanceof GetVmDiskStatsCommand) {
return execute((GetVmDiskStatsCommand) cmd);
} else if (cmd instanceof RebootRouterCommand) {
return execute((RebootRouterCommand) cmd);
} else if (cmd instanceof RebootCommand) {
@ -3007,6 +3013,26 @@ ServerResource {
}
}
protected GetVmDiskStatsAnswer execute(GetVmDiskStatsCommand cmd) {
List<String> vmNames = cmd.getVmNames();
try {
HashMap<String, List<VmDiskStatsEntry>> vmDiskStatsNameMap = new HashMap<String, List<VmDiskStatsEntry>>();
Connect conn = LibvirtConnection.getConnection();
for (String vmName : vmNames) {
List<VmDiskStatsEntry> statEntry = getVmDiskStat(conn, vmName);
if (statEntry == null) {
continue;
}
vmDiskStatsNameMap.put(vmName, statEntry);
}
return new GetVmDiskStatsAnswer(cmd, "", cmd.getHostName(), vmDiskStatsNameMap);
} catch (LibvirtException e) {
s_logger.debug("Can't get vm disk stats: " + e.toString());
return new GetVmDiskStatsAnswer(cmd, null, null, null);
}
}
protected GetVmStatsAnswer execute(GetVmStatsCommand cmd) {
List<String> vmNames = cmd.getVmNames();
try {
@ -4512,10 +4538,46 @@ ServerResource {
}
}
private List<VmDiskStatsEntry> getVmDiskStat(Connect conn, String vmName)
throws LibvirtException {
Domain dm = null;
try {
dm = getDomain(conn, vmName);
List<VmDiskStatsEntry> stats = new ArrayList<VmDiskStatsEntry>();
List<DiskDef> disks = getDisks(conn, vmName);
for (DiskDef disk : disks) {
DomainBlockStats blockStats = dm.blockStats(disk.getDiskLabel());
String path = disk.getDiskPath(); // for example, path = /mnt/pool_uuid/disk_path/
String diskPath = null;
if (path != null) {
String[] token = path.split("/");
if (token.length > 3) {
diskPath = token[3];
VmDiskStatsEntry stat = new VmDiskStatsEntry(vmName, diskPath, blockStats.wr_req, blockStats.rd_req, blockStats.wr_bytes, blockStats.rd_bytes);
stats.add(stat);
}
}
}
return stats;
} finally {
if (dm != null) {
dm.free();
}
}
}
private class vmStats {
long _usedTime;
long _tx;
long _rx;
long _io_rd;
long _io_wr;
long _bytes_rd;
long _bytes_wr;
Calendar _timestamp;
}
@ -4572,10 +4634,44 @@ ServerResource {
stats.setNetworkWriteKBs(deltatx / 1024);
}
/* get disk stats */
List<DiskDef> disks = getDisks(conn, vmName);
long io_rd = 0;
long io_wr = 0;
long bytes_rd = 0;
long bytes_wr = 0;
for (DiskDef disk : disks) {
DomainBlockStats blockStats = dm.blockStats(disk.getDiskLabel());
io_rd += blockStats.rd_req;
io_wr += blockStats.wr_req;
bytes_rd += blockStats.rd_bytes;
bytes_wr += blockStats.wr_bytes;
}
if (oldStats != null) {
long deltaiord = io_rd - oldStats._io_rd;
if (deltaiord > 0)
stats.setDiskReadIOs(deltaiord);
long deltaiowr = io_wr - oldStats._io_wr;
if (deltaiowr > 0)
stats.setDiskWriteIOs(deltaiowr);
long deltabytesrd = bytes_rd - oldStats._bytes_rd;
if (deltabytesrd > 0)
stats.setDiskReadKBs(deltabytesrd / 1024);
long deltabyteswr = bytes_wr - oldStats._bytes_wr;
if (deltabyteswr > 0)
stats.setDiskWriteKBs(deltabyteswr / 1024);
}
/* save to Hashmap */
vmStats newStat = new vmStats();
newStat._usedTime = info.cpuTime;
newStat._rx = rx;
newStat._tx = tx;
newStat._io_rd = io_rd;
newStat._io_wr = io_wr;
newStat._bytes_rd = bytes_rd;
newStat._bytes_wr = bytes_wr;
newStat._timestamp = now;
_vmStats.put(vmName, newStat);
return stats;

View File

@ -57,6 +57,8 @@ import com.cloud.agent.api.GetHostStatsAnswer;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetStorageStatsAnswer;
import com.cloud.agent.api.GetStorageStatsCommand;
import com.cloud.agent.api.GetVmDiskStatsAnswer;
import com.cloud.agent.api.GetVmDiskStatsCommand;
import com.cloud.agent.api.GetVmStatsAnswer;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.GetVncPortAnswer;
@ -111,6 +113,7 @@ import com.cloud.agent.api.UnPlugNicAnswer;
import com.cloud.agent.api.UnPlugNicCommand;
import com.cloud.agent.api.UpdateHostPasswordCommand;
import com.cloud.agent.api.UpgradeSnapshotCommand;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.check.CheckSshAnswer;
import com.cloud.agent.api.check.CheckSshCommand;
@ -236,6 +239,7 @@ import com.xensource.xenapi.Types.VmBadPowerState;
import com.xensource.xenapi.Types.VmPowerState;
import com.xensource.xenapi.Types.XenAPIException;
import com.xensource.xenapi.VBD;
import com.xensource.xenapi.VBDMetrics;
import com.xensource.xenapi.VDI;
import com.xensource.xenapi.VIF;
import com.xensource.xenapi.VLAN;
@ -482,6 +486,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return execute((GetHostStatsCommand) cmd);
} else if (clazz == GetVmStatsCommand.class) {
return execute((GetVmStatsCommand) cmd);
} else if (cmd instanceof GetVmDiskStatsCommand) {
return execute((GetVmDiskStatsCommand) cmd);
} else if (clazz == CheckHealthCommand.class) {
return execute((CheckHealthCommand) cmd);
} else if (clazz == StopCommand.class) {
@ -2584,6 +2590,80 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return hostStats;
}
protected GetVmDiskStatsAnswer execute( GetVmDiskStatsCommand cmd) {
Connection conn = getConnection();
List<String> vmNames = cmd.getVmNames();
HashMap<String, List<VmDiskStatsEntry>> vmDiskStatsNameMap = new HashMap<String, List<VmDiskStatsEntry>>();
if( vmNames.size() == 0 ) {
return new GetVmDiskStatsAnswer(cmd, "", cmd.getHostName(),vmDiskStatsNameMap);
}
try {
// Determine the UUIDs of the requested VMs
List<String> vmUUIDs = new ArrayList<String>();
for (String vmName : vmNames) {
VM vm = getVM(conn, vmName);
vmUUIDs.add(vm.getUuid(conn));
}
HashMap<String, List<VmDiskStatsEntry>> vmDiskStatsUUIDMap = getVmDiskStats(conn, cmd, vmUUIDs, cmd.getHostGuid());
if( vmDiskStatsUUIDMap == null ) {
return new GetVmDiskStatsAnswer(cmd, "", cmd.getHostName(), vmDiskStatsNameMap);
}
for (String vmUUID : vmDiskStatsUUIDMap.keySet()) {
List<VmDiskStatsEntry> vmDiskStatsUUID = vmDiskStatsUUIDMap.get(vmUUID);
String vmName = vmNames.get(vmUUIDs.indexOf(vmUUID));
for (VmDiskStatsEntry vmDiskStat : vmDiskStatsUUID) {
vmDiskStat.setVmName(vmName);
}
vmDiskStatsNameMap.put(vmName, vmDiskStatsUUID);
}
return new GetVmDiskStatsAnswer(cmd, "", cmd.getHostName(),vmDiskStatsNameMap);
} catch (XenAPIException e) {
String msg = "Unable to get VM disk stats" + e.toString();
s_logger.warn(msg, e);
return new GetVmDiskStatsAnswer(cmd, "", cmd.getHostName(),vmDiskStatsNameMap);
} catch (XmlRpcException e) {
String msg = "Unable to get VM disk stats" + e.getMessage();
s_logger.warn(msg, e);
return new GetVmDiskStatsAnswer(cmd, "", cmd.getHostName(),vmDiskStatsNameMap);
}
}
private HashMap<String, List<VmDiskStatsEntry>> getVmDiskStats(Connection conn, GetVmDiskStatsCommand cmd, List<String> vmUUIDs, String hostGuid) {
HashMap<String, List<VmDiskStatsEntry>> vmResponseMap = new HashMap<String, List<VmDiskStatsEntry>>();
for (String vmUUID : vmUUIDs) {
vmResponseMap.put(vmUUID, new ArrayList<VmDiskStatsEntry>());
}
try {
for (String vmUUID : vmUUIDs) {
VM vm = VM.getByUuid(conn, vmUUID);
List<VmDiskStatsEntry> vmDiskStats = new ArrayList<VmDiskStatsEntry>();
for (VBD vbd : vm.getVBDs(conn)) {
if (!vbd.getType(conn).equals(Types.VbdType.CD)) {
VmDiskStatsEntry stats = new VmDiskStatsEntry();
VBDMetrics record = vbd.getMetrics(conn);
stats.setPath(vbd.getVDI(conn).getUuid(conn));
stats.setBytesRead((long)(record.getIoReadKbs(conn) * 1024));
stats.setBytesWrite((long)(record.getIoWriteKbs(conn) * 1024));
vmDiskStats.add(stats);
}
}
vmResponseMap.put(vmUUID, vmDiskStats);
}
} catch (Exception e) {
s_logger.warn("Error while collecting disk stats from : ", e);
return null;
}
return vmResponseMap;
}
protected GetVmStatsAnswer execute( GetVmStatsCommand cmd) {
Connection conn = getConnection();
List<String> vmNames = cmd.getVmNames();
@ -2693,6 +2773,29 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
try {
for (String vmUUID : vmUUIDs) {
VM vm = VM.getByUuid(conn, vmUUID);
VmStatsEntry stats = vmResponseMap.get(vmUUID);
double diskReadKBs = 0;
double diskWriteKBs = 0;
for (VBD vbd : vm.getVBDs(conn)) {
VBDMetrics record = vbd.getMetrics(conn);
diskReadKBs += record.getIoReadKbs(conn);
diskWriteKBs += record.getIoWriteKbs(conn);
}
if (stats == null) {
stats = new VmStatsEntry();
}
stats.setDiskReadKBs(diskReadKBs);
stats.setDiskWriteKBs(diskWriteKBs);
vmResponseMap.put(vmUUID, stats);
}
} catch (Exception e) {
s_logger.warn("Error while collecting disk stats from : ", e);
return null;
}
return vmResponseMap;
}

View File

@ -3397,6 +3397,17 @@ public class ApiResponseHelper implements ResponseGenerator {
NetworkVO network = _entityMgr.findByIdIncludingRemoved(NetworkVO.class, usageRecord.getNetworkId().toString());
usageRecResponse.setNetworkId(network.getUuid());
} else if(usageRecord.getUsageType() == UsageTypes.VM_DISK_IO_READ || usageRecord.getUsageType() == UsageTypes.VM_DISK_IO_WRITE ||
usageRecord.getUsageType() == UsageTypes.VM_DISK_BYTES_READ || usageRecord.getUsageType() == UsageTypes.VM_DISK_BYTES_WRITE){
//Device Type
usageRecResponse.setType(usageRecord.getType());
//VM Instance Id
VMInstanceVO vm = _entityMgr.findByIdIncludingRemoved(VMInstanceVO.class, usageRecord.getUsageId().toString());
usageRecResponse.setUsageId(vm.getUuid());
//Volume ID
VolumeVO volume = _entityMgr.findByIdIncludingRemoved(VolumeVO.class, usageRecord.getUsageId().toString());
usageRecResponse.setUsageId(volume.getUuid());
} else if(usageRecord.getUsageType() == UsageTypes.VOLUME){
//Volume ID
VolumeVO volume = _entityMgr.findByIdIncludingRemoved(VolumeVO.class, usageRecord.getUsageId().toString());

View File

@ -160,6 +160,18 @@ public class UserVmJoinDaoImpl extends GenericDaoBase<UserVmJoinVO, Long> implem
Double networkKbWrite = Double.valueOf(vmStats.getNetworkWriteKBs());
userVmResponse.setNetworkKbsWrite(networkKbWrite.longValue());
Double diskKbsRead = Double.valueOf(vmStats.getDiskReadKBs());
userVmResponse.setDiskKbsRead(diskKbsRead.longValue());
Double diskKbsWrite = Double.valueOf(vmStats.getDiskWriteKBs());
userVmResponse.setDiskKbsWrite(diskKbsWrite.longValue());
Double diskIORead = Double.valueOf(vmStats.getDiskReadIOs());
userVmResponse.setDiskIORead(diskIORead.longValue());
Double diskIOWrite = Double.valueOf(vmStats.getDiskWriteIOs());
userVmResponse.setDiskIOWrite(diskIOWrite.longValue());
}
}

View File

@ -229,6 +229,7 @@ public enum Config {
NetworkGcInterval("Advanced", ManagementServer.class, Integer.class, "network.gc.interval", "600", "Seconds to wait before checking for networks to shutdown", null),
CapacitySkipcountingHours("Advanced", ManagementServer.class, Integer.class, "capacity.skipcounting.hours", "3600", "Time (in seconds) to wait before release VM's cpu and memory when VM in stopped state", null),
VmStatsInterval("Advanced", ManagementServer.class, Integer.class, "vm.stats.interval", "60000", "The interval (in milliseconds) when vm stats are retrieved from agents.", null),
VmDiskStatsInterval("Advanced", ManagementServer.class, Integer.class, "vm.disk.stats.interval", "0", "Interval (in seconds) to report vm disk statistics.", null),
VmTransitionWaitInterval("Advanced", ManagementServer.class, Integer.class, "vm.tranisition.wait.interval", "3600", "Time (in seconds) to wait before taking over a VM in transition state", null),
VmDestroyForcestop("Advanced", ManagementServer.class, Boolean.class, "vm.destroy.forcestop", "false", "On destroy, force-stop takes this value ", null),

View File

@ -17,11 +17,14 @@
package com.cloud.server;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@ -45,8 +48,11 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.api.GetFileStatsCommand;
import com.cloud.agent.api.GetStorageStatsCommand;
import com.cloud.agent.api.HostStatsEntry;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.manager.Commands;
import com.cloud.cluster.ManagementServerHostVO;
import com.cloud.cluster.dao.ManagementServerHostDao;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.host.Host;
@ -59,19 +65,31 @@ import com.cloud.resource.ResourceState;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.StorageStats;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeStats;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.secondary.SecondaryStorageVmManager;
import com.cloud.user.UserStatisticsVO;
import com.cloud.user.UserStatsLogVO;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.user.dao.VmDiskStatisticsDao;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.component.ComponentMethodInterceptable;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.net.MacAddress;
import com.cloud.vm.NicVO;
import com.cloud.vm.UserVmManager;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VmStats;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.UserVmDao;
/**
@ -96,6 +114,8 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
@Inject private SecondaryStorageVmManager _ssvmMgr;
@Inject private ResourceManager _resourceMgr;
@Inject private ConfigurationDao _configDao;
@Inject private VmDiskStatisticsDao _vmDiskStatsDao;
@Inject private ManagementServerHostDao _msHostDao;
private ConcurrentHashMap<Long, HostStats> _hostStats = new ConcurrentHashMap<Long, HostStats>();
private final ConcurrentHashMap<Long, VmStats> _VmStats = new ConcurrentHashMap<Long, VmStats>();
@ -107,6 +127,15 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
long hostAndVmStatsInterval = -1L;
long storageStatsInterval = -1L;
long volumeStatsInterval = -1L;
int vmDiskStatsInterval = 0;
private ScheduledExecutorService _diskStatsUpdateExecutor;
private int _usageAggregationRange = 1440;
private String _usageTimeZone = "GMT";
private final long mgmtSrvrId = MacAddress.getMacAddress().toLong();
private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 5; // 5 seconds
private static final int USAGE_AGGREGATION_RANGE_MIN = 10; // 10 minutes, same to com.cloud.usage.UsageManagerImpl.USAGE_AGGREGATION_RANGE_MIN
private boolean _dailyOrHourly = false;
//private final GlobalLock m_capacityCheckLock = GlobalLock.getInternLock("capacity.check");
@ -136,6 +165,7 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
hostAndVmStatsInterval = NumbersUtil.parseLong(configs.get("vm.stats.interval"), 60000L);
storageStatsInterval = NumbersUtil.parseLong(configs.get("storage.stats.interval"), 60000L);
volumeStatsInterval = NumbersUtil.parseLong(configs.get("volume.stats.interval"), -1L);
vmDiskStatsInterval = NumbersUtil.parseInt(configs.get("vm.disk.stats.interval"), 0);
if (hostStatsInterval > 0) {
_executor.scheduleWithFixedDelay(new HostCollector(), 15000L, hostStatsInterval, TimeUnit.MILLISECONDS);
@ -148,6 +178,12 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
if (storageStatsInterval > 0) {
_executor.scheduleWithFixedDelay(new StorageCollector(), 15000L, storageStatsInterval, TimeUnit.MILLISECONDS);
}
if (vmDiskStatsInterval > 0) {
if (vmDiskStatsInterval < 300)
vmDiskStatsInterval = 300;
_executor.scheduleAtFixedRate(new VmDiskStatsTask(), vmDiskStatsInterval, vmDiskStatsInterval, TimeUnit.SECONDS);
}
// -1 means we don't even start this thread to pick up any data.
if (volumeStatsInterval > 0) {
@ -155,6 +191,49 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
} else {
s_logger.info("Disabling volume stats collector");
}
//Schedule disk stats update task
_diskStatsUpdateExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DiskStatsUpdater"));
String aggregationRange = configs.get("usage.stats.job.aggregation.range");
_usageAggregationRange = NumbersUtil.parseInt(aggregationRange, 1440);
_usageTimeZone = configs.get("usage.aggregation.timezone");
if(_usageTimeZone == null){
_usageTimeZone = "GMT";
}
TimeZone usageTimezone = TimeZone.getTimeZone(_usageTimeZone);
Calendar cal = Calendar.getInstance(usageTimezone);
cal.setTime(new Date());
long endDate = 0;
int HOURLY_TIME = 60;
final int DAILY_TIME = 60 * 24;
if (_usageAggregationRange == DAILY_TIME) {
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.roll(Calendar.DAY_OF_YEAR, true);
cal.add(Calendar.MILLISECOND, -1);
endDate = cal.getTime().getTime();
_dailyOrHourly = true;
} else if (_usageAggregationRange == HOURLY_TIME) {
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.roll(Calendar.HOUR_OF_DAY, true);
cal.add(Calendar.MILLISECOND, -1);
endDate = cal.getTime().getTime();
_dailyOrHourly = true;
} else {
endDate = cal.getTime().getTime();
_dailyOrHourly = false;
}
if (_usageAggregationRange < USAGE_AGGREGATION_RANGE_MIN) {
s_logger.warn("Usage stats job aggregation range is to small, using the minimum value of " + USAGE_AGGREGATION_RANGE_MIN);
_usageAggregationRange = USAGE_AGGREGATION_RANGE_MIN;
}
_diskStatsUpdateExecutor.scheduleAtFixedRate(new VmDiskStatsUpdaterTask(), (endDate - System.currentTimeMillis()),
(_usageAggregationRange * 60 * 1000), TimeUnit.MILLISECONDS);
}
class HostCollector implements Runnable {
@ -249,6 +328,10 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
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());
_VmStats.put(vmId, statsInMemory);
}
@ -270,6 +353,175 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc
public VmStats getVmStats(long id) {
return _VmStats.get(id);
}
class VmDiskStatsUpdaterTask implements Runnable {
@Override
public void run() {
GlobalLock scanLock = GlobalLock.getInternLock("vm.disk.stats");
try {
if(scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) {
//Check for ownership
//msHost in UP state with min id should run the job
ManagementServerHostVO msHost = _msHostDao.findOneInUpState(new Filter(ManagementServerHostVO.class, "id", true, 0L, 1L));
if(msHost == null || (msHost.getMsid() != mgmtSrvrId)){
s_logger.debug("Skipping aggregate disk stats update");
scanLock.unlock();
return;
}
Transaction txn = Transaction.open(Transaction.CLOUD_DB);
try {
txn.start();
//get all stats with delta > 0
List<VmDiskStatisticsVO> updatedVmNetStats = _vmDiskStatsDao.listUpdatedStats();
for(VmDiskStatisticsVO stat : updatedVmNetStats){
if (_dailyOrHourly) {
//update agg bytes
stat.setAggBytesRead(stat.getCurrentBytesRead() + stat.getNetBytesRead());
stat.setAggBytesWrite(stat.getCurrentBytesWrite() + stat.getNetBytesWrite());
stat.setAggIORead(stat.getCurrentIORead() + stat.getNetIORead());
stat.setAggIOWrite(stat.getCurrentIOWrite() + stat.getNetIOWrite());
_vmDiskStatsDao.update(stat.getId(), stat);
}
}
s_logger.debug("Successfully updated aggregate vm disk stats");
txn.commit();
} catch (Exception e){
txn.rollback();
s_logger.debug("Failed to update aggregate disk stats", e);
} finally {
scanLock.unlock();
txn.close();
}
}
} catch (Exception e){
s_logger.debug("Exception while trying to acquire disk stats lock", e);
} finally {
scanLock.releaseRef();
}
}
}
class VmDiskStatsTask implements Runnable {
@Override
public void run() {
// collect the vm disk statistics(total) from hypervisor. added by weizhou, 2013.03.
Transaction txn = Transaction.open(Transaction.CLOUD_DB);
try {
txn.start();
SearchCriteria<HostVO> sc = _hostDao.createSearchCriteria();
sc.addAnd("status", SearchCriteria.Op.EQ, Status.Up.toString());
sc.addAnd("resourceState", SearchCriteria.Op.NIN, ResourceState.Maintenance, ResourceState.PrepareForMaintenance, ResourceState.ErrorInMaintenance);
sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.Routing.toString());
List<HostVO> hosts = _hostDao.search(sc, null);
for (HostVO host : hosts) {
List<UserVmVO> vms = _userVmDao.listRunningByHostId(host.getId());
List<Long> vmIds = new ArrayList<Long>();
for (UserVmVO vm : vms) {
if (vm.getType() == VirtualMachine.Type.User) // user vm
vmIds.add(vm.getId());
}
HashMap<Long, List<VmDiskStatsEntry>> vmDiskStatsById = _userVmMgr.getVmDiskStatistics(host.getId(), host.getName(), vmIds);
if (vmDiskStatsById == null)
continue;
Set<Long> vmIdSet = vmDiskStatsById.keySet();
for(Long vmId : vmIdSet)
{
List<VmDiskStatsEntry> vmDiskStats = vmDiskStatsById.get(vmId);
if (vmDiskStats == null)
continue;
UserVmVO userVm = _userVmDao.findById(vmId);
for (VmDiskStatsEntry vmDiskStat:vmDiskStats) {
SearchCriteria<VolumeVO> sc_volume = _volsDao.createSearchCriteria();
sc_volume.addAnd("path", SearchCriteria.Op.EQ, vmDiskStat.getPath());
VolumeVO volume = _volsDao.search(sc_volume, null).get(0);
VmDiskStatisticsVO previousVmDiskStats = _vmDiskStatsDao.findBy(userVm.getAccountId(), userVm.getDataCenterId(), vmId, volume.getId());
VmDiskStatisticsVO vmDiskStat_lock = _vmDiskStatsDao.lock(userVm.getAccountId(), userVm.getDataCenterId(), vmId, volume.getId());
if ((vmDiskStat.getBytesRead() == 0) && (vmDiskStat.getBytesWrite() == 0)
&& (vmDiskStat.getIORead() == 0) && (vmDiskStat.getIOWrite() == 0)) {
s_logger.debug("IO/bytes read and write are all 0. Not updating vm_disk_statistics");
continue;
}
if (vmDiskStat_lock == null) {
s_logger.warn("unable to find vm disk stats from host for account: " + userVm.getAccountId() + " with vmId: " + userVm.getId()+ " and volumeId:" + volume.getId());
continue;
}
if (previousVmDiskStats != null
&& ((previousVmDiskStats.getCurrentBytesRead() != vmDiskStat_lock.getCurrentBytesRead())
|| (previousVmDiskStats.getCurrentBytesWrite() != vmDiskStat_lock.getCurrentBytesWrite())
|| (previousVmDiskStats.getCurrentIORead() != vmDiskStat_lock.getCurrentIORead())
|| (previousVmDiskStats.getCurrentIOWrite() != vmDiskStat_lock.getCurrentIOWrite()))) {
s_logger.debug("vm disk stats changed from the time GetVmDiskStatsCommand was sent. " +
"Ignoring current answer. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Read(Bytes): " + vmDiskStat.getBytesRead() + " write(Bytes): " + vmDiskStat.getBytesWrite() +
" Read(IO): " + vmDiskStat.getIORead() + " write(IO): " + vmDiskStat.getIOWrite());
continue;
}
if (vmDiskStat_lock.getCurrentBytesRead() > vmDiskStat.getBytesRead()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Read # of bytes that's less than the last one. " +
"Assuming something went wrong and persisting it. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Reported: " + vmDiskStat.getBytesRead() + " Stored: " + vmDiskStat_lock.getCurrentBytesRead());
}
vmDiskStat_lock.setNetBytesRead(vmDiskStat_lock.getNetBytesRead() + vmDiskStat_lock.getCurrentBytesRead());
}
vmDiskStat_lock.setCurrentBytesRead(vmDiskStat.getBytesRead());
if (vmDiskStat_lock.getCurrentBytesWrite() > vmDiskStat.getBytesWrite()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Write # of bytes that's less than the last one. " +
"Assuming something went wrong and persisting it. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Reported: " + vmDiskStat.getBytesWrite() + " Stored: " + vmDiskStat_lock.getCurrentBytesWrite());
}
vmDiskStat_lock.setNetBytesWrite(vmDiskStat_lock.getNetBytesWrite() + vmDiskStat_lock.getCurrentBytesWrite());
}
vmDiskStat_lock.setCurrentBytesWrite(vmDiskStat.getBytesWrite());
if (vmDiskStat_lock.getCurrentIORead() > vmDiskStat.getIORead()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Read # of IO that's less than the last one. " +
"Assuming something went wrong and persisting it. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Reported: " + vmDiskStat.getIORead() + " Stored: " + vmDiskStat_lock.getCurrentIORead());
}
vmDiskStat_lock.setNetIORead(vmDiskStat_lock.getNetIORead() + vmDiskStat_lock.getCurrentIORead());
}
vmDiskStat_lock.setCurrentIORead(vmDiskStat.getIORead());
if (vmDiskStat_lock.getCurrentIOWrite() > vmDiskStat.getIOWrite()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Write # of IO that's less than the last one. " +
"Assuming something went wrong and persisting it. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Reported: " + vmDiskStat.getIOWrite() + " Stored: " + vmDiskStat_lock.getCurrentIOWrite());
}
vmDiskStat_lock.setNetIOWrite(vmDiskStat_lock.getNetIOWrite() + vmDiskStat_lock.getCurrentIOWrite());
}
vmDiskStat_lock.setCurrentIOWrite(vmDiskStat.getIOWrite());
if (! _dailyOrHourly) {
//update agg bytes
vmDiskStat_lock.setAggBytesWrite(vmDiskStat_lock.getNetBytesWrite() + vmDiskStat_lock.getCurrentBytesWrite());
vmDiskStat_lock.setAggBytesRead(vmDiskStat_lock.getNetBytesRead() + vmDiskStat_lock.getCurrentBytesRead());
vmDiskStat_lock.setAggIOWrite(vmDiskStat_lock.getNetIOWrite() + vmDiskStat_lock.getCurrentIOWrite());
vmDiskStat_lock.setAggIORead(vmDiskStat_lock.getNetIORead() + vmDiskStat_lock.getCurrentIORead());
}
_vmDiskStatsDao.update(vmDiskStat_lock.getId(), vmDiskStat_lock);
}
}
}
txn.commit();
} catch (Exception e) {
s_logger.warn("Error while collecting vm disk stats from hosts", e);
} finally {
txn.close();
}
}
}
class StorageCollector implements Runnable {
@Override

View File

@ -128,9 +128,11 @@ import com.cloud.template.TemplateManager;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.user.UserContext;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.user.dao.VmDiskStatisticsDao;
import com.cloud.uservm.UserVm;
import com.cloud.utils.EnumUtils;
import com.cloud.utils.NumbersUtil;
@ -280,6 +282,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
@Inject
protected ResourceTagDao _resourceTagDao;
@Inject
protected VmDiskStatisticsDao _vmDiskStatsDao;
@Inject
protected VMSnapshotDao _vmSnapshotDao;
@Inject
protected List<StoragePoolAllocator> _storagePoolAllocators;
@ -1558,6 +1562,13 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
} else {
_volsDao.attachVolume(volume.getId(), vm.getId(), deviceId);
}
// insert record for disk I/O statistics
VmDiskStatisticsVO diskstats = _vmDiskStatsDao.findBy(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volume.getId());
if (diskstats == null) {
diskstats = new VmDiskStatisticsVO(vm.getAccountId(), vm.getDataCenterId(),vm.getId(), volume.getId());
_vmDiskStatsDao.persist(diskstats);
}
return _volsDao.findById(volume.getId());
} else {
if (answer != null) {
@ -1895,6 +1906,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
.getPoolId());
cmd.setPoolUuid(volumePool.getUuid());
// Collect vm disk statistics from host before stopping Vm
_userVmMgr.collectVmDiskStatistics(vm);
try {
answer = _agentMgr.send(vm.getHostId(), cmd);
} catch (Exception e) {

View File

@ -20,6 +20,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.exception.*;
@ -65,6 +66,8 @@ public interface UserVmManager extends VirtualMachineGuru<UserVmVO>, UserVmServi
*/
HashMap<Long, VmStatsEntry> getVirtualMachineStatistics(long hostId, String hostName, List<Long> vmIds);
HashMap<Long, List<VmDiskStatsEntry>> getVmDiskStatistics(long hostId, String hostName, List<Long> vmIds);
boolean deleteVmGroup(long groupId);
boolean addInstanceToGroup(long userVmId, String group);
@ -95,4 +98,6 @@ public interface UserVmManager extends VirtualMachineGuru<UserVmVO>, UserVmServi
boolean upgradeVirtualMachine(Long id, Long serviceOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException;
boolean setupVmForPvlan(boolean add, Long hostId, NicProfile nic);
void collectVmDiskStatistics (UserVmVO userVm);
}

View File

@ -66,6 +66,8 @@ import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
import com.cloud.agent.AgentManager.OnError;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.GetVmDiskStatsAnswer;
import com.cloud.agent.api.GetVmDiskStatsCommand;
import com.cloud.agent.api.GetVmStatsAnswer;
import com.cloud.agent.api.GetVmStatsCommand;
import com.cloud.agent.api.PlugNicAnswer;
@ -75,6 +77,7 @@ import com.cloud.agent.api.StartAnswer;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.UnPlugNicAnswer;
import com.cloud.agent.api.UnPlugNicCommand;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.VirtualMachineTO;
@ -213,9 +216,11 @@ import com.cloud.user.SSHKeyPairVO;
import com.cloud.user.User;
import com.cloud.user.UserContext;
import com.cloud.user.UserVO;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.SSHKeyPairDao;
import com.cloud.user.dao.UserDao;
import com.cloud.user.dao.VmDiskStatisticsDao;
import com.cloud.uservm.UserVm;
import com.cloud.utils.Journal;
import com.cloud.utils.NumbersUtil;
@ -239,6 +244,7 @@ import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.dao.InstanceGroupDao;
import com.cloud.vm.dao.InstanceGroupVMMapDao;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.SecondaryStorageVmDao;
import com.cloud.vm.dao.UserVmCloneSettingDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao;
@ -394,6 +400,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
protected GuestOSCategoryDao _guestOSCategoryDao;
@Inject
UsageEventDao _usageEventDao;
@Inject
SecondaryStorageVmDao _secondaryDao;
@Inject
VmDiskStatisticsDao _vmDiskStatsDao;
@Inject
protected VMSnapshotDao _vmSnapshotDao;
@Inject
@ -411,6 +423,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
protected ScheduledExecutorService _executor = null;
protected int _expungeInterval;
protected int _expungeDelay;
protected boolean _dailyOrHourly = false;
protected String _name;
protected String _instance;
@ -1098,6 +1111,41 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
}
}
@Override
public HashMap<Long, List<VmDiskStatsEntry>> getVmDiskStatistics(long hostId, String hostName, List<Long> vmIds) throws CloudRuntimeException {
HashMap<Long, List<VmDiskStatsEntry>> vmDiskStatsById = new HashMap<Long, List<VmDiskStatsEntry>>();
if (vmIds.isEmpty()) {
return vmDiskStatsById;
}
List<String> vmNames = new ArrayList<String>();
for (Long vmId : vmIds) {
UserVmVO vm = _vmDao.findById(vmId);
vmNames.add(vm.getInstanceName());
}
Answer answer = _agentMgr.easySend(hostId, new GetVmDiskStatsCommand(vmNames, _hostDao.findById(hostId).getGuid(), hostName));
if (answer == null || !answer.getResult()) {
s_logger.warn("Unable to obtain VM disk statistics.");
return null;
} else {
HashMap<String, List<VmDiskStatsEntry>> vmDiskStatsByName = ((GetVmDiskStatsAnswer)answer).getVmDiskStatsMap();
if (vmDiskStatsByName == null) {
s_logger.warn("Unable to obtain VM disk statistics.");
return null;
}
for (String vmName : vmDiskStatsByName.keySet()) {
vmDiskStatsById.put(vmIds.get(vmNames.indexOf(vmName)), vmDiskStatsByName.get(vmName));
}
}
return vmDiskStatsById;
}
@Override
public boolean upgradeVirtualMachine(Long vmId, Long newServiceOfferingId) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException{
@ -1397,6 +1445,18 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
_executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("UserVm-Scavenger"));
String aggregationRange = configs.get("usage.stats.job.aggregation.range");
int _usageAggregationRange = NumbersUtil.parseInt(aggregationRange, 1440);
int HOURLY_TIME = 60;
final int DAILY_TIME = 60 * 24;
if (_usageAggregationRange == DAILY_TIME) {
_dailyOrHourly = true;
} else if (_usageAggregationRange == HOURLY_TIME) {
_dailyOrHourly = true;
} else {
_dailyOrHourly = false;
}
_itMgr.registerGuru(VirtualMachine.Type.User, this);
VirtualMachine.State.getStateMachine().registerListener(
@ -2929,6 +2989,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
userVm.setPrivateMacAddress(nic.getMacAddress());
}
}
List<VolumeVO> volumes = _volsDao.findByInstance(userVm.getId());
VmDiskStatisticsVO diskstats = null;
for (VolumeVO volume : volumes) {
diskstats = _vmDiskStatsDao.findBy(userVm.getAccountId(), userVm.getDataCenterId(),userVm.getId(), volume.getId());
if (diskstats == null) {
diskstats = new VmDiskStatisticsVO(userVm.getAccountId(), userVm.getDataCenterId(),userVm.getId(), volume.getId());
_vmDiskStatsDao.persist(diskstats);
}
}
return true;
}
@ -3308,6 +3379,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
boolean status;
State vmState = vm.getState();
// Collect vm disk statistics from host before stopping Vm
collectVmDiskStatistics(vm);
try {
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
status = vmEntity.destroy(new Long(userId).toString());
@ -3344,6 +3418,122 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
ex.addProxyObject(vm.getUuid(), "vmId");
throw ex;
}
}
@Override
public void collectVmDiskStatistics (UserVmVO userVm) {
// Collect vm disk statistics from host before stopping Vm
long hostId = userVm.getHostId();
List<String> vmNames = new ArrayList<String>();
vmNames.add(userVm.getInstanceName());
HostVO host = _hostDao.findById(hostId);
GetVmDiskStatsAnswer diskStatsAnswer = null;
try {
diskStatsAnswer = (GetVmDiskStatsAnswer) _agentMgr.easySend(hostId, new GetVmDiskStatsCommand(vmNames, host.getGuid(), host.getName()));
} catch (Exception e) {
s_logger.warn("Error while collecting disk stats for vm: " + userVm.getHostName() + " from host: " + host.getName(), e);
return;
}
if (diskStatsAnswer != null) {
if (!diskStatsAnswer.getResult()) {
s_logger.warn("Error while collecting disk stats vm: " + userVm.getHostName() + " from host: " + host.getName() + "; details: " + diskStatsAnswer.getDetails());
return;
}
Transaction txn = Transaction.open(Transaction.CLOUD_DB);
try {
txn.start();
HashMap<String, List<VmDiskStatsEntry>> vmDiskStatsByName = diskStatsAnswer.getVmDiskStatsMap();
List<VmDiskStatsEntry> vmDiskStats = vmDiskStatsByName.get(userVm.getInstanceName());
if (vmDiskStats == null)
return;
for (VmDiskStatsEntry vmDiskStat:vmDiskStats) {
SearchCriteria<VolumeVO> sc_volume = _volsDao.createSearchCriteria();
sc_volume.addAnd("path", SearchCriteria.Op.EQ, vmDiskStat.getPath());
VolumeVO volume = _volsDao.search(sc_volume, null).get(0);
VmDiskStatisticsVO previousVmDiskStats = _vmDiskStatsDao.findBy(userVm.getAccountId(), userVm.getDataCenterId(), userVm.getId(), volume.getId());
VmDiskStatisticsVO vmDiskStat_lock = _vmDiskStatsDao.lock(userVm.getAccountId(), userVm.getDataCenterId(), userVm.getId(), volume.getId());
if ((vmDiskStat.getIORead() == 0) && (vmDiskStat.getIOWrite() == 0) && (vmDiskStat.getBytesRead() == 0) && (vmDiskStat.getBytesWrite() == 0)) {
s_logger.debug("Read/Write of IO and Bytes are both 0. Not updating vm_disk_statistics");
continue;
}
if (vmDiskStat_lock == null) {
s_logger.warn("unable to find vm disk stats from host for account: " + userVm.getAccountId() + " with vmId: " + userVm.getId()+ " and volumeId:" + volume.getId());
continue;
}
if (previousVmDiskStats != null
&& ((previousVmDiskStats.getCurrentIORead() != vmDiskStat_lock.getCurrentIORead())
|| ((previousVmDiskStats.getCurrentIOWrite() != vmDiskStat_lock.getCurrentIOWrite())
|| (previousVmDiskStats.getCurrentBytesRead() != vmDiskStat_lock.getCurrentBytesRead())
|| (previousVmDiskStats.getCurrentBytesWrite() != vmDiskStat_lock.getCurrentBytesWrite())))) {
s_logger.debug("vm disk stats changed from the time GetVmDiskStatsCommand was sent. " +
"Ignoring current answer. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" IO Read: " + vmDiskStat.getIORead() + " IO Write: " + vmDiskStat.getIOWrite() +
" Bytes Read: " + vmDiskStat.getBytesRead() + " Bytes Write: " + vmDiskStat.getBytesWrite());
continue;
}
if (vmDiskStat_lock.getCurrentIORead() > vmDiskStat.getIORead()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Read # of IO that's less than the last one. " +
"Assuming something went wrong and persisting it. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Reported: " + vmDiskStat.getIORead() + " Stored: " + vmDiskStat_lock.getCurrentIORead());
}
vmDiskStat_lock.setNetIORead(vmDiskStat_lock.getNetIORead() + vmDiskStat_lock.getCurrentIORead());
}
vmDiskStat_lock.setCurrentIORead(vmDiskStat.getIORead());
if (vmDiskStat_lock.getCurrentIOWrite() > vmDiskStat.getIOWrite()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Write # of IO that's less than the last one. " +
"Assuming something went wrong and persisting it. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Reported: " + vmDiskStat.getIOWrite() + " Stored: " + vmDiskStat_lock.getCurrentIOWrite());
}
vmDiskStat_lock.setNetIOWrite(vmDiskStat_lock.getNetIOWrite() + vmDiskStat_lock.getCurrentIOWrite());
}
vmDiskStat_lock.setCurrentIOWrite(vmDiskStat.getIOWrite());
if (vmDiskStat_lock.getCurrentBytesRead() > vmDiskStat.getBytesRead()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Read # of Bytes that's less than the last one. " +
"Assuming something went wrong and persisting it. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Reported: " + vmDiskStat.getBytesRead() + " Stored: " + vmDiskStat_lock.getCurrentBytesRead());
}
vmDiskStat_lock.setNetBytesRead(vmDiskStat_lock.getNetBytesRead() + vmDiskStat_lock.getCurrentBytesRead());
}
vmDiskStat_lock.setCurrentBytesRead(vmDiskStat.getBytesRead());
if (vmDiskStat_lock.getCurrentBytesWrite() > vmDiskStat.getBytesWrite()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Write # of Bytes that's less than the last one. " +
"Assuming something went wrong and persisting it. Host: " + host.getName() + " . VM: " + vmDiskStat.getVmName() +
" Reported: " + vmDiskStat.getBytesWrite() + " Stored: " + vmDiskStat_lock.getCurrentBytesWrite());
}
vmDiskStat_lock.setNetBytesWrite(vmDiskStat_lock.getNetBytesWrite() + vmDiskStat_lock.getCurrentBytesWrite());
}
vmDiskStat_lock.setCurrentBytesWrite(vmDiskStat.getBytesWrite());
if (! _dailyOrHourly) {
//update agg bytes
vmDiskStat_lock.setAggIORead(vmDiskStat_lock.getNetIORead() + vmDiskStat_lock.getCurrentIORead());
vmDiskStat_lock.setAggIOWrite(vmDiskStat_lock.getNetIOWrite() + vmDiskStat_lock.getCurrentIOWrite());
vmDiskStat_lock.setAggBytesRead(vmDiskStat_lock.getNetBytesRead() + vmDiskStat_lock.getCurrentBytesRead());
vmDiskStat_lock.setAggBytesWrite(vmDiskStat_lock.getNetBytesWrite() + vmDiskStat_lock.getCurrentBytesWrite());
}
_vmDiskStatsDao.update(vmDiskStat_lock.getId(), vmDiskStat_lock);
}
txn.commit();
} catch (Exception e) {
txn.rollback();
s_logger.warn("Unable to update vm disk statistics for vm: " + userVm.getId() + " from host: " + hostId, e);
} finally {
txn.close();
}
}
}

View File

@ -74,6 +74,7 @@ under the License.
<param name="cache.time.to.live">300</param>
</dao>
<dao name="UserStats" class="com.cloud.user.dao.UserStatisticsDaoImpl"/>
<dao name="VmDiskStats" class="com.cloud.user.dao.VmDiskStatisticsDaoImpl"/>
<dao name="Disk Template" class="com.cloud.storage.dao.DiskTemplateDaoImpl">
<param name="cache.size">50</param>
<param name="cache.time.to.live">-1</param>

View File

@ -47,6 +47,7 @@ import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
import org.springframework.stereotype.Component;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.VirtualMachineTO;
@ -168,6 +169,12 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager,
return null;
}
@Override
public HashMap<Long, List<VmDiskStatsEntry>> getVmDiskStatistics(long hostId, String hostName, List<Long> vmIds) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean deleteVmGroup(long groupId) {
// TODO Auto-generated method stub
@ -461,4 +468,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager,
// TODO Auto-generated method stub
return false;
}
@Override
public void collectVmDiskStatistics (UserVmVO userVm) {
// TODO Auto-generated method stub
}
}

View File

@ -1771,6 +1771,82 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'manag
UPDATE `cloud`.`snapshots` set swift_id=null where swift_id=0;
DROP TABLE IF EXISTS `cloud`.`vm_disk_statistics`;
CREATE TABLE `cloud`.`vm_disk_statistics` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`data_center_id` bigint(20) unsigned NOT NULL,
`account_id` bigint(20) unsigned NOT NULL,
`vm_id` bigint(20) unsigned NOT NULL,
`volume_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`net_io_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`net_io_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`current_io_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`current_io_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_io_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_io_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`net_bytes_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`net_bytes_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`current_bytes_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`current_bytes_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_bytes_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_bytes_write` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `account_id` (`account_id`,`data_center_id`,`vm_id`,`volume_id`),
KEY `i_vm_disk_statistics__account_id` (`account_id`),
KEY `i_vm_disk_statistics__account_id_data_center_id` (`account_id`,`data_center_id`),
CONSTRAINT `fk_vm_disk_statistics__account_id` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
insert into `cloud`.`vm_disk_statistics`(data_center_id,account_id,vm_id,volume_id)
select volumes.data_center_id, volumes.account_id, vm_instance.id, volumes.id from volumes,vm_instance where vm_instance.vm_type="User" and vm_instance.state<>"Expunging" and volumes.instance_id=vm_instance.id order by vm_instance.id;
DROP TABLE IF EXISTS `cloud_usage`.`vm_disk_statistics`;
CREATE TABLE `cloud_usage`.`vm_disk_statistics` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`data_center_id` bigint(20) unsigned NOT NULL,
`account_id` bigint(20) unsigned NOT NULL,
`vm_id` bigint(20) unsigned NOT NULL,
`volume_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`net_io_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`net_io_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`current_io_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`current_io_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_io_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_io_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`net_bytes_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`net_bytes_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`current_bytes_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`current_bytes_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_bytes_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_bytes_write` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `account_id` (`account_id`,`data_center_id`,`vm_id`,`volume_id`)
) ENGINE=InnoDB CHARSET=utf8;
insert into `cloud_usage`.`vm_disk_statistics` select * from `cloud`.`vm_disk_statistics`;
DROP TABLE IF EXISTS `cloud_usage`.`usage_vm_disk`;
CREATE TABLE `cloud_usage`.`usage_vm_disk` (
`account_id` bigint(20) unsigned NOT NULL,
`zone_id` bigint(20) unsigned NOT NULL,
`vm_id` bigint(20) unsigned NOT NULL,
`volume_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`io_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`io_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_io_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_io_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`bytes_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`bytes_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_bytes_read` bigint(20) unsigned NOT NULL DEFAULT '0',
`agg_bytes_write` bigint(20) unsigned NOT NULL DEFAULT '0',
`event_time_millis` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`account_id`,`zone_id`,`vm_id`,`volume_id`,`event_time_millis`)
) ENGINE=InnoDB CHARSET=utf8;
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.disk.stats.interval', 0, 'Interval (in seconds) to report vm disk statistics.');
-- Re-enable foreign key checking, at the end of the upgrade path
SET foreign_key_checks = 1;

View File

@ -469,11 +469,15 @@ dictionary = {
'label.disable.vpn': '<fmt:message key="label.disable.vpn" />',
'label.disabling.vpn.access': '<fmt:message key="label.disabling.vpn.access" />',
'label.disk.allocated': '<fmt:message key="label.disk.allocated" />',
'label.disk.read.bytes': '<fmt:message key="label.disk.read.bytes" />',
'label.disk.read.io': '<fmt:message key="label.disk.read.io" />',
'label.disk.offering': '<fmt:message key="label.disk.offering" />',
'label.disk.size': '<fmt:message key="label.disk.size" />',
'label.disk.size.gb': '<fmt:message key="label.disk.size.gb" />',
'label.disk.total': '<fmt:message key="label.disk.total" />',
'label.disk.volume': '<fmt:message key="label.disk.volume" />',
'label.disk.write.bytes': '<fmt:message key="label.disk.write.bytes" />',
'label.disk.write.io': '<fmt:message key="label.disk.write.io" />',
'label.display.name': '<fmt:message key="label.display.name" />',
'label.display.text': '<fmt:message key="label.display.text" />',
'label.dns.1': '<fmt:message key="label.dns.1" />',

View File

@ -1648,7 +1648,11 @@
totalCPU: { label: 'label.total.cpu' },
cpuused: { label: 'label.cpu.utilized' },
networkkbsread: { label: 'label.network.read' },
networkkbswrite: { label: 'label.network.write' }
networkkbswrite: { label: 'label.network.write' },
diskkbsread: { label: 'label.disk.read.bytes' },
diskkbswrite: { label: 'label.disk.write.bytes' },
diskioread: { label: 'label.disk.read.io' },
diskiowrite: { label: 'label.disk.write.io' }
},
dataProvider: function(args) {
$.ajax({
@ -1662,7 +1666,11 @@
totalCPU: jsonObj.cpunumber + " x " + cloudStack.converters.convertHz(jsonObj.cpuspeed),
cpuused: jsonObj.cpuused,
networkkbsread: (jsonObj.networkkbsread == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.networkkbsread * 1024),
networkkbswrite: (jsonObj.networkkbswrite == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.networkkbswrite * 1024)
networkkbswrite: (jsonObj.networkkbswrite == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.networkkbswrite * 1024),
diskkbsread: (jsonObj.diskkbsread == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.diskkbsread * 1024),
diskkbswrite: (jsonObj.diskkbswrite == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.diskkbswrite * 1024),
diskioread: (jsonObj.diskioread == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.diskioread * 1024),
diskiowrite: (jsonObj.diskiowrite == null)? "N/A": cloudStack.converters.convertBytes(jsonObj.diskiowrite * 1024)
}
});
}

View File

@ -54,6 +54,7 @@ import com.cloud.usage.dao.UsageSecurityGroupDao;
import com.cloud.usage.dao.UsageStorageDao;
import com.cloud.usage.dao.UsageVMInstanceDao;
import com.cloud.usage.dao.UsageVPNUserDao;
import com.cloud.usage.dao.UsageVmDiskDao;
import com.cloud.usage.dao.UsageVolumeDao;
import com.cloud.usage.parser.IPAddressUsageParser;
import com.cloud.usage.parser.LoadBalancerUsageParser;
@ -64,13 +65,15 @@ import com.cloud.usage.parser.SecurityGroupUsageParser;
import com.cloud.usage.parser.StorageUsageParser;
import com.cloud.usage.parser.VMInstanceUsageParser;
import com.cloud.usage.parser.VPNUserUsageParser;
import com.cloud.usage.parser.VmDiskUsageParser;
import com.cloud.usage.parser.VolumeUsageParser;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.UserStatisticsVO;
import com.cloud.user.VmDiskStatisticsVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserStatisticsDao;
import com.cloud.user.dao.VmDiskStatisticsDao;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
@ -108,6 +111,8 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
@Inject private UsageVPNUserDao m_usageVPNUserDao;
@Inject private UsageSecurityGroupDao m_usageSecurityGroupDao;
@Inject private UsageJobDao m_usageJobDao;
@Inject private VmDiskStatisticsDao m_vmDiskStatsDao;
@Inject private UsageVmDiskDao m_usageVmDiskDao;
@Inject protected AlertManager _alertMgr;
@Inject protected UsageEventDao _usageEventDao;
@Inject ConfigurationDao _configDao;
@ -121,6 +126,7 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
TimeZone m_usageTimezone = TimeZone.getTimeZone("GMT");;
private final GlobalLock m_heartbeatLock = GlobalLock.getInternLock("usage.job.heartbeat.check");
private List<UsageNetworkVO> usageNetworks = new ArrayList<UsageNetworkVO>();
private List<UsageVmDiskVO> usageVmDisks = new ArrayList<UsageVmDiskVO>();
private final ScheduledExecutorService m_executor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Usage-Job"));
private final ScheduledExecutorService m_heartbeatExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Usage-HB"));
@ -389,6 +395,8 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
List<AccountVO> accounts = null;
List<UserStatisticsVO> userStats = null;
Map<String, UsageNetworkVO> networkStats = null;
List<VmDiskStatisticsVO> vmDiskStats = null;
Map<String, UsageVmDiskVO> vmDiskUsages = null;
Transaction userTxn = Transaction.open(Transaction.CLOUD_DB);
try {
Long limit = Long.valueOf(500);
@ -479,6 +487,46 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
}
offset = new Long(offset.longValue() + limit.longValue());
} while ((userStats != null) && !userStats.isEmpty());
// reset offset
offset = Long.valueOf(0);
// get all the vm network stats to create usage_vm_network records for the vm network usage
Long lastVmDiskStatsId = m_usageDao.getLastVmDiskStatsId();
if (lastVmDiskStatsId == null) {
lastVmDiskStatsId = Long.valueOf(0);
}
SearchCriteria<VmDiskStatisticsVO> sc4 = m_vmDiskStatsDao.createSearchCriteria();
sc4.addAnd("id", SearchCriteria.Op.LTEQ, lastVmDiskStatsId);
do {
Filter filter = new Filter(VmDiskStatisticsVO.class, "id", true, offset, limit);
vmDiskStats = m_vmDiskStatsDao.search(sc4, filter);
if ((vmDiskStats != null) && !vmDiskStats.isEmpty()) {
// now copy the accounts to cloud_usage db
m_usageDao.updateVmDiskStats(vmDiskStats);
}
offset = new Long(offset.longValue() + limit.longValue());
} while ((vmDiskStats != null) && !vmDiskStats.isEmpty());
// reset offset
offset = Long.valueOf(0);
sc4 = m_vmDiskStatsDao.createSearchCriteria();
sc4.addAnd("id", SearchCriteria.Op.GT, lastVmDiskStatsId);
do {
Filter filter = new Filter(VmDiskStatisticsVO.class, "id", true, offset, limit);
vmDiskStats = m_vmDiskStatsDao.search(sc4, filter);
if ((vmDiskStats != null) && !vmDiskStats.isEmpty()) {
// now copy the accounts to cloud_usage db
m_usageDao.saveVmDiskStats(vmDiskStats);
}
offset = new Long(offset.longValue() + limit.longValue());
} while ((vmDiskStats != null) && !vmDiskStats.isEmpty());
} finally {
userTxn.close();
}
@ -565,6 +613,53 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
s_logger.debug("created network stats helper entries for " + numAcctsProcessed + " accts");
}
// get vm disk stats in order to compute vm disk usage
vmDiskUsages = m_usageVmDiskDao.getRecentVmDiskStats();
// Keep track of user stats for an account, across all of its public IPs
Map<String, VmDiskStatisticsVO> aggregatedDiskStats = new HashMap<String, VmDiskStatisticsVO>();
startIndex = 0;
do {
vmDiskStats = m_vmDiskStatsDao.listActiveAndRecentlyDeleted(recentlyDeletedDate, startIndex, 500);
if (vmDiskUsages != null) {
for (VmDiskStatisticsVO vmDiskStat : vmDiskStats) {
if(vmDiskStat.getVmId() != null){
String hostKey = vmDiskStat.getDataCenterId() + "-" + vmDiskStat.getAccountId()+"-Vm-" + vmDiskStat.getVmId()+"-Disk-" + vmDiskStat.getVolumeId();
VmDiskStatisticsVO hostAggregatedStat = aggregatedDiskStats.get(hostKey);
if (hostAggregatedStat == null) {
hostAggregatedStat = new VmDiskStatisticsVO(vmDiskStat.getAccountId(), vmDiskStat.getDataCenterId(), vmDiskStat.getVmId(),vmDiskStat.getVolumeId());
}
hostAggregatedStat.setAggIORead(hostAggregatedStat.getAggIORead() + vmDiskStat.getAggIORead());
hostAggregatedStat.setAggIOWrite(hostAggregatedStat.getAggIOWrite() + vmDiskStat.getAggIOWrite());
hostAggregatedStat.setAggBytesRead(hostAggregatedStat.getAggBytesRead() + vmDiskStat.getAggBytesRead());
hostAggregatedStat.setAggBytesWrite(hostAggregatedStat.getAggBytesWrite() + vmDiskStat.getAggBytesWrite());
aggregatedDiskStats.put(hostKey, hostAggregatedStat);
}
}
}
startIndex += 500;
} while ((userStats != null) && !userStats.isEmpty());
// loop over the user stats, create delta entries in the usage_disk helper table
numAcctsProcessed = 0;
usageVmDisks.clear();
for (String key : aggregatedDiskStats.keySet()) {
UsageVmDiskVO currentVmDiskStats = null;
if (vmDiskStats != null) {
currentVmDiskStats = vmDiskUsages.get(key);
}
createVmDiskHelperEntry(aggregatedDiskStats.get(key), currentVmDiskStats, endDateMillis);
numAcctsProcessed++;
}
m_usageVmDiskDao.saveUsageVmDisks(usageVmDisks);
if (s_logger.isDebugEnabled()) {
s_logger.debug("created vm disk stats helper entries for " + numAcctsProcessed + " accts");
}
// commit the helper records, then start a new transaction
usageTxn.commit();
usageTxn.start();
@ -701,6 +796,13 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
}
}
parsed = VmDiskUsageParser.parse(account, currentStartDate, currentEndDate);
if (s_logger.isDebugEnabled()) {
if (!parsed) {
s_logger.debug("vm disk usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")");
}
}
parsed = VolumeUsageParser.parse(account, currentStartDate, currentEndDate);
if (s_logger.isDebugEnabled()) {
if (!parsed) {
@ -1006,6 +1108,59 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
usageNetworks.add(usageNetworkVO);
}
private void createVmDiskHelperEntry(VmDiskStatisticsVO vmDiskStat, UsageVmDiskVO usageVmDiskStat, long timestamp) {
long currentAccountedIORead = 0L;
long currentAccountedIOWrite = 0L;
long currentAccountedBytesRead = 0L;
long currentAccountedBytesWrite = 0L;
if (usageVmDiskStat != null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("getting current accounted bytes for... accountId: " + usageVmDiskStat.getAccountId() + " in zone: " + vmDiskStat.getDataCenterId() + "; aiw: " + vmDiskStat.getAggIOWrite() +
"; air: " + usageVmDiskStat.getAggIORead() + "; abw: " + vmDiskStat.getAggBytesWrite() + "; abr: " + usageVmDiskStat.getAggBytesRead());
}
currentAccountedIORead = usageVmDiskStat.getAggIORead();
currentAccountedIOWrite = usageVmDiskStat.getAggIOWrite();
currentAccountedBytesRead = usageVmDiskStat.getAggBytesRead();
currentAccountedBytesWrite = usageVmDiskStat.getAggBytesWrite();
}
long ioRead = vmDiskStat.getAggIORead() - currentAccountedIORead;
long ioWrite = vmDiskStat.getAggIOWrite() - currentAccountedIOWrite;
long bytesRead = vmDiskStat.getAggBytesRead() - currentAccountedBytesRead;
long bytesWrite = vmDiskStat.getAggBytesWrite() - currentAccountedBytesWrite;
if (ioRead < 0) {
s_logger.warn("Calculated negative value for io read: " + ioRead + ", vm disk stats say: " + vmDiskStat.getAggIORead() + ", previous vm disk usage was: " + currentAccountedIORead);
ioRead = 0;
}
if (ioWrite < 0) {
s_logger.warn("Calculated negative value for io write: " + ioWrite + ", vm disk stats say: " + vmDiskStat.getAggIOWrite() + ", previous vm disk usage was: " + currentAccountedIOWrite);
ioWrite = 0;
}
if (bytesRead < 0) {
s_logger.warn("Calculated negative value for bytes read: " + bytesRead + ", vm disk stats say: " + vmDiskStat.getAggBytesRead() + ", previous vm disk usage was: " + currentAccountedBytesRead);
bytesRead = 0;
}
if (bytesWrite < 0) {
s_logger.warn("Calculated negative value for bytes write: " + bytesWrite + ", vm disk stats say: " + vmDiskStat.getAggBytesWrite() + ", previous vm disk usage was: " + currentAccountedBytesWrite);
bytesWrite = 0;
}
long vmId = 0;
if(vmDiskStat.getVmId() != null){
vmId = vmDiskStat.getVmId();
}
UsageVmDiskVO usageVmDiskVO = new UsageVmDiskVO(vmDiskStat.getAccountId(), vmDiskStat.getDataCenterId(), vmId, vmDiskStat.getVolumeId(), ioRead, ioWrite,
vmDiskStat.getAggIORead(), vmDiskStat.getAggIOWrite(), bytesRead, bytesWrite, vmDiskStat.getAggBytesRead(), vmDiskStat.getAggBytesWrite(), timestamp);
if (s_logger.isDebugEnabled()) {
s_logger.debug("creating vmDiskHelperEntry... accountId: " + vmDiskStat.getAccountId() + " in zone: " + vmDiskStat.getDataCenterId() + "; aiw: " + vmDiskStat.getAggIOWrite() + "; air: " + vmDiskStat.getAggIORead() +
"; curAIR: " + currentAccountedIORead + "; curAIW: " + currentAccountedIOWrite + "; uir: " + ioRead + "; uiw: " + ioWrite + "; abw: " + vmDiskStat.getAggBytesWrite() + "; abr: " + vmDiskStat.getAggBytesRead() +
"; curABR: " + currentAccountedBytesRead + "; curABW: " + currentAccountedBytesWrite + "; ubr: " + bytesRead + "; ubw: " + bytesWrite);
}
usageVmDisks.add(usageVmDiskVO);
}
private void createIPHelperEvent(UsageEventVO event) {
String ipAddress = event.getResourceName();

View File

@ -0,0 +1,208 @@
// 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
// 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.usage.parser;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.apache.cloudstack.usage.UsageTypes;
import com.cloud.usage.UsageVO;
import com.cloud.usage.UsageVmDiskVO;
import com.cloud.usage.dao.UsageDao;
import com.cloud.usage.dao.UsageVmDiskDao;
import com.cloud.user.AccountVO;
import com.cloud.utils.db.SearchCriteria;
import org.springframework.stereotype.Component;
@Component
public class VmDiskUsageParser {
public static final Logger s_logger = Logger.getLogger(VmDiskUsageParser.class.getName());
private static UsageDao m_usageDao;
private static UsageVmDiskDao m_usageVmDiskDao;
@Inject private UsageDao _usageDao;
@Inject private UsageVmDiskDao _usageVmDiskDao;
@PostConstruct
void init() {
m_usageDao = _usageDao;
m_usageVmDiskDao = _usageVmDiskDao;
}
public static boolean parse(AccountVO account, Date startDate, Date endDate) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Parsing all Vm Disk usage events for account: " + account.getId());
}
if ((endDate == null) || endDate.after(new Date())) {
endDate = new Date();
}
// - query usage_disk table for all entries for userId with
// event_date in the given range
SearchCriteria<UsageVmDiskVO> sc = m_usageVmDiskDao.createSearchCriteria();
sc.addAnd("accountId", SearchCriteria.Op.EQ, account.getId());
sc.addAnd("eventTimeMillis", SearchCriteria.Op.BETWEEN, startDate.getTime(), endDate.getTime());
List<UsageVmDiskVO> usageVmDiskVOs = m_usageVmDiskDao.search(sc, null);
Map<String, VmDiskInfo> vmDiskUsageByZone = new HashMap<String, VmDiskInfo>();
// Calculate the bytes since last parsing
for (UsageVmDiskVO usageVmDisk : usageVmDiskVOs) {
long zoneId = usageVmDisk.getZoneId();
String key = ""+zoneId;
if(usageVmDisk.getVmId() != 0){
key += "-Vm-" + usageVmDisk.getVmId()+"-Disk-" + usageVmDisk.getVolumeId();
}
VmDiskInfo vmDiskInfo = vmDiskUsageByZone.get(key);
long ioRead = usageVmDisk.getIORead();
long ioWrite = usageVmDisk.getIOWrite();
long bytesRead = usageVmDisk.getBytesRead();
long bytesWrite = usageVmDisk.getBytesWrite();
if (vmDiskInfo != null) {
ioRead += vmDiskInfo.getIORead();
ioWrite += vmDiskInfo.getIOWrite();
bytesRead += vmDiskInfo.getBytesRead();
bytesWrite += vmDiskInfo.getBytesWrite();
}
vmDiskUsageByZone.put(key, new VmDiskInfo(zoneId, usageVmDisk.getVmId(), usageVmDisk.getVolumeId(), ioRead, ioWrite, bytesRead, bytesWrite));
}
for (String key : vmDiskUsageByZone.keySet()) {
VmDiskInfo vmDiskInfo = vmDiskUsageByZone.get(key);
long ioRead = vmDiskInfo.getIORead();
long ioWrite = vmDiskInfo.getIOWrite();
long bytesRead = vmDiskInfo.getBytesRead();
long bytesWrite = vmDiskInfo.getBytesWrite();
if ((ioRead > 0L) || (ioWrite > 0L) || (bytesRead > 0L) || (bytesWrite > 0L)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating vm disk usage record, io read:" + ioRead + ", io write: " + ioWrite + "bytes read:" + bytesRead + ", bytes write: " + bytesWrite + "for account: "
+ account.getId() + " in availability zone " + vmDiskInfo.getZoneId() + ", start: " + startDate + ", end: " + endDate);
}
Long vmId = null;
// Create the usage record for bytes read
String usageDesc = "disk bytes read";
if(vmDiskInfo.getVmId() != 0){
vmId = vmDiskInfo.getVmId();
usageDesc += " for Vm: "+vmDiskInfo.getVmId()+" and Volume: "+ vmDiskInfo.getVolumeId();
}
UsageVO usageRecord = new UsageVO(vmDiskInfo.getZoneId(), account.getId(), account.getDomainId(), usageDesc, ioRead + " io read",
UsageTypes.VM_DISK_IO_READ, new Double(ioRead), vmId, "VirtualMachine", vmDiskInfo.getVolumeId(), startDate, endDate);
m_usageDao.persist(usageRecord);
// Create the usage record for bytes write
usageDesc = "disk bytes write";
if(vmDiskInfo.getVmId() != 0){
usageDesc += " for Vm: "+vmDiskInfo.getVmId()+" and Volume: "+ vmDiskInfo.getVolumeId();
}
usageRecord = new UsageVO(vmDiskInfo.getZoneId(), account.getId(), account.getDomainId(), usageDesc, ioWrite + " io write",
UsageTypes.VM_DISK_BYTES_WRITE, new Double(ioWrite), vmId, "VirtualMachine", vmDiskInfo.getVolumeId(), startDate, endDate);
m_usageDao.persist(usageRecord);
// Create the usage record for bytes read
usageDesc = "disk bytes read";
if(vmDiskInfo.getVmId() != 0){
vmId = vmDiskInfo.getVmId();
usageDesc += " for Vm: "+vmDiskInfo.getVmId()+" and Volume: "+ vmDiskInfo.getVolumeId();
}
usageRecord = new UsageVO(vmDiskInfo.getZoneId(), account.getId(), account.getDomainId(), usageDesc, bytesRead + " bytes read",
UsageTypes.VM_DISK_BYTES_READ, new Double(bytesRead), vmId, "VirtualMachine", vmDiskInfo.getVolumeId(), startDate, endDate);
m_usageDao.persist(usageRecord);
// Create the usage record for bytes write
usageDesc = "disk bytes write";
if(vmDiskInfo.getVmId() != 0){
usageDesc += " for Vm: "+vmDiskInfo.getVmId()+" and Volume: "+ vmDiskInfo.getVolumeId();
}
usageRecord = new UsageVO(vmDiskInfo.getZoneId(), account.getId(), account.getDomainId(), usageDesc, bytesWrite + " bytes write",
UsageTypes.VM_DISK_BYTES_WRITE, new Double(bytesWrite), vmId, "VirtualMachine", vmDiskInfo.getVolumeId(), startDate, endDate);
m_usageDao.persist(usageRecord);
} else {
// Don't charge anything if there were zero bytes processed
if (s_logger.isDebugEnabled()) {
s_logger.debug("No vm disk usage record (0 bytes used) generated for account: " + account.getId());
}
}
}
return true;
}
private static class VmDiskInfo {
private long zoneId;
private long vmId;
private Long volumeId;
private long ioRead;
private long ioWrite;
private long bytesRead;
private long bytesWrite;
public VmDiskInfo(long zoneId, long vmId, Long volumeId, long ioRead, long ioWrite, long bytesRead, long bytesWrite) {
this.zoneId = zoneId;
this.vmId = vmId;
this.volumeId = volumeId;
this.ioRead = ioRead;
this.ioWrite = ioWrite;
this.bytesRead = bytesRead;
this.bytesWrite = bytesWrite;
}
public long getZoneId() {
return zoneId;
}
public long getVmId() {
return vmId;
}
public Long getVolumeId() {
return volumeId;
}
public long getIORead() {
return ioRead;
}
public long getIOWrite() {
return ioWrite;
}
public long getBytesRead() {
return bytesRead;
}
public long getBytesWrite() {
return bytesWrite;
}
}
}

View File

@ -46,6 +46,8 @@ public class UsageManagerTest extends TestCase {
@Inject
NetworkUsageParser netParser = null;
@Inject
VmDiskUsageParser vmdiskParser = null;
@Inject
PortForwardingUsageParser pfParser = null;
@Inject
SecurityGroupUsageParser sgParser = null;
@ -87,6 +89,7 @@ public class UsageManagerTest extends TestCase {
lbParser.parse(account, startDate, endDate);
noParser.parse(account, startDate, endDate);
netParser.parse(account, startDate, endDate);
vmdiskParser.parse(account, startDate, endDate);
pfParser.parse(account, startDate, endDate);
sgParser.parse(account, startDate, endDate);
stParser.parse(account, startDate, endDate);

View File

@ -53,6 +53,7 @@ import java.io.IOException;
UsagePortForwardingRuleDaoImpl.class,
UsageNetworkOfferingDaoImpl.class,
UsageVPNUserDaoImpl.class,
UsageVmDiskDaoImpl.class,
UsageSecurityGroupDaoImpl.class,
ConfigurationDaoImpl.class,
UsageManagerImpl.class,
@ -64,6 +65,7 @@ import java.io.IOException;
PortForwardingUsageParser.class,
SecurityGroupUsageParser.class,
StorageUsageParser.class,
VmDiskUsageParser.class,
VolumeUsageParser.class,
VPNUserUsageParser.class,
UserStatisticsDaoImpl.class},