CLOUDSTACK-9867: VM snapshot on primary storage usage metrics (#2035)

VM snapshot on primary storage usage metrics.
This commit is contained in:
Abhinandan Prateek 2017-12-28 14:57:10 +05:30 committed by Rohit Yadav
parent 26759d1d13
commit 391952da5b
15 changed files with 555 additions and 4 deletions

View File

@ -241,6 +241,8 @@ public class EventTypes {
// Snapshots
public static final String EVENT_SNAPSHOT_CREATE = "SNAPSHOT.CREATE";
public static final String EVENT_SNAPSHOT_ON_PRIMARY = "SNAPSHOT.ON_PRIMARY";
public static final String EVENT_SNAPSHOT_OFF_PRIMARY = "SNAPSHOT.OFF_PRIMARY";
public static final String EVENT_SNAPSHOT_DELETE = "SNAPSHOT.DELETE";
public static final String EVENT_SNAPSHOT_REVERT = "SNAPSHOT.REVERT";
public static final String EVENT_SNAPSHOT_POLICY_CREATE = "SNAPSHOTPOLICY.CREATE";
@ -462,6 +464,8 @@ public class EventTypes {
// vm snapshot events
public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE";
public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE";
public static final String EVENT_VM_SNAPSHOT_ON_PRIMARY = "VMSNAPSHOT.ON_PRIMARY";
public static final String EVENT_VM_SNAPSHOT_OFF_PRIMARY = "VMSNAPSHOT.OFF_PRIMARY";
public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERTTO";
// external network device events
@ -711,6 +715,8 @@ public class EventTypes {
// Snapshots
entityEventDetails.put(EVENT_SNAPSHOT_CREATE, Snapshot.class);
entityEventDetails.put(EVENT_SNAPSHOT_DELETE, Snapshot.class);
entityEventDetails.put(EVENT_SNAPSHOT_ON_PRIMARY, Snapshot.class);
entityEventDetails.put(EVENT_SNAPSHOT_OFF_PRIMARY, Snapshot.class);
entityEventDetails.put(EVENT_SNAPSHOT_POLICY_CREATE, SnapshotPolicy.class);
entityEventDetails.put(EVENT_SNAPSHOT_POLICY_UPDATE, SnapshotPolicy.class);
entityEventDetails.put(EVENT_SNAPSHOT_POLICY_DELETE, SnapshotPolicy.class);

View File

@ -43,6 +43,7 @@ public class UsageTypes {
public static final int VM_DISK_BYTES_WRITE = 24;
public static final int VM_SNAPSHOT = 25;
public static final int VOLUME_SECONDARY = 26;
public static final int VM_SNAPSHOT_ON_PRIMARY = 27;
public static List<UsageTypeResponse> listUsageTypes() {
List<UsageTypeResponse> responseList = new ArrayList<UsageTypeResponse>();
@ -65,6 +66,7 @@ public class UsageTypes {
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)"));
responseList.add(new UsageTypeResponse(VM_SNAPSHOT, "VM Snapshot storage usage"));
responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage"));
return responseList;
}
}

View File

@ -490,6 +490,23 @@ INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid, hypervisor_type, hypervi
INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) SELECT UUID(),'Xenserver', '7.2.0', guest_os_name, guest_os_id, utc_timestamp(), 0 FROM `cloud`.`guest_os_hypervisor` WHERE hypervisor_type='Xenserver' AND hypervisor_version='7.1.0' AND guest_os_id not in (1,2,3,4,56,101,56,58,93,94,50,51,87,88,89,90,91,92,26,27,28,29,40,41,42,43,44,45,96,97,107,108,109,110,151,152,153);
-- Add table to track primary storage in use for snapshots
DROP TABLE IF EXISTS `cloud_usage`.`usage_snapshot_on_primary`;
CREATE TABLE `cloud_usage`.`usage_snapshot_on_primary` (
`id` bigint(20) unsigned NOT NULL,
`zone_id` bigint(20) unsigned NOT NULL,
`account_id` bigint(20) unsigned NOT NULL,
`domain_id` bigint(20) unsigned NOT NULL,
`vm_id` bigint(20) unsigned NOT NULL,
`name` varchar(128),
`type` int(1) unsigned NOT NULL,
`physicalsize` bigint(20),
`virtualsize` bigint(20),
`created` datetime NOT NULL,
`deleted` datetime,
INDEX `i_usage_snapshot_on_primary` (`account_id`,`id`,`vm_id`,`created`)
) ENGINE=InnoDB CHARSET=utf8;
-- Change monitor patch for apache2 in systemvm
UPDATE `cloud`.`monitoring_services` SET pidfile="/var/run/apache2/apache2.pid" WHERE process_name="apache2" AND service_name="apache2";

View File

@ -0,0 +1,145 @@
// 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 java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.cloudstack.api.InternalIdentity;
@Entity
@Table(name = "usage_snapshot_on_primary")
public class UsageSnapshotOnPrimaryVO implements InternalIdentity {
@Column(name = "id")
// volumeId
private long id;
@Column(name = "zone_id")
private long zoneId;
@Column(name = "account_id")
private long accountId;
@Column(name = "domain_id")
private long domainId;
@Column(name = "vm_id")
private long vmId;
@Column(name = "name")
private String name;
@Column(name = "type")
private int snapshotType;
@Column(name = "physicalsize")
private long physicalSize;
@Column(name = "created")
@Temporal(value = TemporalType.TIMESTAMP)
private Date created = null;
@Column(name = "deleted")
@Temporal(value = TemporalType.TIMESTAMP)
private Date deleted;
@Column(name = "virtualsize")
private Long virtualSize;
protected UsageSnapshotOnPrimaryVO() {
}
public UsageSnapshotOnPrimaryVO(long id, long zoneId, long accountId, long domainId, long vmId, String name, int type, long virtualSize, long physicalSize, Date created, Date deleted) {
this.id = id;
this.zoneId = zoneId;
this.accountId = accountId;
this.domainId = domainId;
this.snapshotType = type;
this.physicalSize = physicalSize;
this.virtualSize = virtualSize;
this.created = created;
this.vmId = vmId;
this.name = name;
this.deleted = deleted;
}
public long getZoneId() {
return zoneId;
}
public long getAccountId() {
return accountId;
}
public long getDomainId() {
return domainId;
}
public int getSnapshotType() {
return snapshotType;
}
public long getPhysicalSize() {
return physicalSize;
}
public Long getVirtualSize() {
return virtualSize;
}
public Date getDeleted() {
return deleted;
}
public void setDeleted(Date deleted) {
this.deleted = deleted;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public long getVmId() {
return vmId;
}
public String getName() {
return name;
}
@Override
public long getId() {
return this.id;
}
@Override
public String toString() {
return "UsageSnapshotOnPrimaryVO [id=" + id + ", zoneId=" + zoneId + ", accountId=" + accountId + ", domainId=" + domainId + ", vmId=" + vmId + ", name=" + name
+ ", snapshotType=" + snapshotType + ", physicalSize=" + physicalSize + ", created=" + created + ", deleted=" + deleted + ", virtualSize=" + virtualSize + "]";
}
}

View File

@ -120,4 +120,10 @@ public class UsageVMSnapshotVO implements InternalIdentity {
return this.id;
}
@Override
public String toString() {
return "UsageVMSnapshotVO [id=" + id + ", zoneId=" + zoneId + ", accountId=" + accountId + ", domainId=" + domainId + ", vmId=" + vmId + ", diskOfferingId="
+ diskOfferingId + ", size=" + size + ", created=" + created + ", processed=" + processed + "]";
}
}

View File

@ -0,0 +1,31 @@
// 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.Date;
import java.util.List;
import com.cloud.usage.UsageSnapshotOnPrimaryVO;
import com.cloud.utils.db.GenericDao;
public interface UsageVMSnapshotOnPrimaryDao extends GenericDao<UsageSnapshotOnPrimaryVO, Long> {
public void updateDeleted(UsageSnapshotOnPrimaryVO usage);
public List<UsageSnapshotOnPrimaryVO> getUsageRecords(Long accountId, Long domainId, Date startDate, Date endDate);
}

View File

@ -0,0 +1,117 @@
// 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.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.usage.UsageSnapshotOnPrimaryVO;
import com.cloud.utils.DateUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.TransactionLegacy;
@Component
public class UsageVMSnapshotOnPrimaryDaoImpl extends GenericDaoBase<UsageSnapshotOnPrimaryVO, Long> implements UsageVMSnapshotOnPrimaryDao {
public static final Logger s_logger = Logger.getLogger(UsageVMSnapshotOnPrimaryDaoImpl.class.getName());
protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT id, zone_id, account_id, domain_id, vm_id, name, type, physicalsize, virtualsize, created, deleted "
+ " FROM usage_snapshot_on_primary" + " WHERE account_id = ? " + " AND ( (created < ? AND deleted is NULL)"
+ " OR ( deleted BETWEEN ? AND ?)) ORDER BY created asc";
protected static final String UPDATE_DELETED = "UPDATE usage_snapshot_on_primary SET deleted = ? WHERE account_id = ? AND id = ? and vm_id = ? and created = ?";
@Override
public void updateDeleted(UsageSnapshotOnPrimaryVO usage) {
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
PreparedStatement pstmt = null;
try {
txn.start();
pstmt = txn.prepareAutoCloseStatement(UPDATE_DELETED);
pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), usage.getDeleted()));
pstmt.setLong(2, usage.getAccountId());
pstmt.setLong(3, usage.getId());
pstmt.setLong(4, usage.getVmId());
pstmt.setString(5, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), usage.getCreated()));
pstmt.executeUpdate();
txn.commit();
} catch (Exception e) {
txn.rollback();
s_logger.warn("Error updating UsageSnapshotOnPrimaryVO", e);
} finally {
txn.close();
}
}
@Override
public List<UsageSnapshotOnPrimaryVO> getUsageRecords(Long accountId, Long domainId, Date startDate, Date endDate) {
List<UsageSnapshotOnPrimaryVO> usageRecords = new ArrayList<UsageSnapshotOnPrimaryVO>();
String sql = GET_USAGE_RECORDS_BY_ACCOUNT;
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
PreparedStatement pstmt = null;
try {
int i = 1;
pstmt = txn.prepareAutoCloseStatement(sql);
pstmt.setLong(i++, accountId);
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
s_logger.debug("GET_USAGE_RECORDS_BY_ACCOUNT " + pstmt);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
//id, zone_id, account_id, domain_iVMSnapshotVOd, vm_id, disk_offering_id, size, created, deleted
Long vId = Long.valueOf(rs.getLong(1));
Long zoneId = Long.valueOf(rs.getLong(2));
Long acctId = Long.valueOf(rs.getLong(3));
Long dId = Long.valueOf(rs.getLong(4));
Long vmId = Long.valueOf(rs.getLong(5));
String name = String.valueOf(rs.getString(6));
Integer type = Integer.valueOf(rs.getInt(7));
Long physicalSize = Long.valueOf(rs.getLong(8));
Long virtaulSize = Long.valueOf(rs.getLong(9));
Date createdDate = null;
Date deleteDate = null;
String createdTS = rs.getString(10);
String deleted = rs.getString(11);
if (createdTS != null) {
createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS);
}
if (deleted != null) {
deleteDate = DateUtil.parseDateString(s_gmtTimeZone, deleted);
}
usageRecords.add(new UsageSnapshotOnPrimaryVO(vId, zoneId, acctId, dId, vmId, name, type, virtaulSize, physicalSize, createdDate, deleteDate));
}
} catch (Exception e) {
txn.rollback();
s_logger.warn("Error getting usage records", e);
} finally {
txn.close();
}
return usageRecords;
}
}

View File

@ -49,6 +49,8 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.log4j.Logger;
import com.cloud.storage.CreateSnapshotPayload;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
@ -216,6 +218,8 @@ public class SnapshotServiceImpl implements SnapshotService {
try {
result = future.get();
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_ON_PRIMARY, snap.getAccountId(), snap.getDataCenterId(), snap.getId(),
snap.getName(), null, null, snapshotOnPrimary.getSize(), snapshotOnPrimary.getSize(), snap.getClass().getName(), snap.getUuid());
return result;
} catch (InterruptedException e) {
s_logger.debug("Failed to create snapshot", e);

View File

@ -19,6 +19,9 @@ package org.apache.cloudstack.storage.snapshot;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.to.DiskTO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
@ -147,6 +150,7 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase {
* @return true if snapshot is removed, false otherwise
*/
@ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_OFF_PRIMARY, eventDescription = "deleting snapshot", async = true)
private boolean cleanupSnapshotOnPrimaryStore(long snapshotId) {
SnapshotObject snapshotObj = (SnapshotObject)snapshotDataFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
@ -176,6 +180,8 @@ public class StorageSystemSnapshotStrategy extends SnapshotStrategyBase {
snapshotSvr.deleteSnapshot(snapshotObj);
snapshotObj.processEvent(Snapshot.Event.OperationSucceeded);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_OFF_PRIMARY, snapshotObj.getAccountId(), snapshotObj.getDataCenterId(), snapshotId,
snapshotObj.getName(), null, null, 0L, snapshotObj.getClass().getName(), snapshotObj.getUuid());
}
catch (Exception e) {
s_logger.debug("Failed to delete snapshot: ", e);

View File

@ -42,6 +42,8 @@ import org.apache.cloudstack.storage.datastore.PrimaryDataStoreImpl;
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
import org.apache.cloudstack.utils.identity.ManagementServerNode;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
@ -97,7 +99,6 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
SnapshotInfo parentSnapshot = snapshot.getParent();
if (parentSnapshot != null && snapshot.getPath().equalsIgnoreCase(parentSnapshot.getPath())) {
s_logger.debug("backup an empty snapshot");
// don't need to backup this snapshot
SnapshotDataStoreVO parentSnapshotOnBackupStore = snapshotStoreDao.findBySnapshot(parentSnapshot.getId(), DataStoreRole.Image);
if (parentSnapshotOnBackupStore != null && parentSnapshotOnBackupStore.getState() == State.Ready) {
@ -254,7 +255,6 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
}
if (snapshotVO.getState() == Snapshot.State.CreatedOnPrimary) {
s_logger.debug("delete snapshot on primary storage:");
snapshotVO.setState(Snapshot.State.Destroyed);
snapshotDao.update(snapshotId, snapshotVO);
return true;
@ -428,6 +428,8 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
SnapshotDataStoreVO snapshotDataStoreVO = snapshotStoreDao.findByStoreSnapshot(primaryStore.getRole(), primaryStore.getId(), parentSnapshotId);
if (snapshotDataStoreVO != null) {
parentSnapshotId = snapshotDataStoreVO.getParentSnapshotId();
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_OFF_PRIMARY, parent.getAccountId(), parent.getDataCenterId(), parent.getId(),
parent.getName(), null, null, 0L, 0L, parent.getClass().getName(), parent.getUuid());
snapshotStoreDao.remove(snapshotDataStoreVO.getId());
} else {
parentSnapshotId = null;

View File

@ -119,6 +119,14 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot
List<VolumeObjectTO> volumeTOs = vmSnapshotHelper.getVolumeTOList(userVm.getId());
long prev_chain_size = 0;
long virtual_size=0;
for (VolumeObjectTO volume : volumeTOs) {
virtual_size += volume.getSize();
VolumeVO volumeVO = volumeDao.findById(volume.getId());
prev_chain_size += volumeVO.getVmSnapshotChainSize() == null ? 0 : volumeVO.getVmSnapshotChainSize();
}
VMSnapshotTO current = null;
VMSnapshotVO currentSnapshot = vmSnapshotDao.findCurrentSnapshotByVmId(userVm.getId());
if (currentSnapshot != null)
@ -150,10 +158,12 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot
processAnswer(vmSnapshotVO, userVm, answer, hostId);
s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName());
result = true;
long new_chain_size=0;
for (VolumeObjectTO volumeTo : answer.getVolumeTOs()) {
publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_CREATE, vmSnapshot, userVm, volumeTo);
new_chain_size += volumeTo.getSize();
}
publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_ON_PRIMARY, vmSnapshot, userVm, new_chain_size - prev_chain_size, virtual_size);
return vmSnapshot;
} else {
String errMsg = "Creating VM snapshot: " + vmSnapshot.getName() + " failed";
@ -208,9 +218,12 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot
if (answer != null && answer.getResult()) {
DeleteVMSnapshotAnswer deleteVMSnapshotAnswer = (DeleteVMSnapshotAnswer)answer;
processAnswer(vmSnapshotVO, userVm, answer, hostId);
long full_chain_size=0;
for (VolumeObjectTO volumeTo : deleteVMSnapshotAnswer.getVolumeTOs()) {
publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_DELETE, vmSnapshot, userVm, volumeTo);
full_chain_size += volumeTo.getSize();
}
publishUsageEvent(EventTypes.EVENT_VM_SNAPSHOT_OFF_PRIMARY, vmSnapshot, userVm, full_chain_size, 0L);
return true;
} else {
String errMsg = (answer == null) ? null : answer.getDetails();
@ -328,6 +341,15 @@ public class DefaultVMSnapshotStrategy extends ManagerBase implements VMSnapshot
volumeTo.getSize(), VMSnapshot.class.getName(), vmSnapshot.getUuid());
}
private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm, Long vmSnapSize, Long virtualSize) {
try {
UsageEventUtils.publishUsageEvent(type, vmSnapshot.getAccountId(), userVm.getDataCenterId(), userVm.getId(), vmSnapshot.getName(), 0L, 0L, vmSnapSize, virtualSize,
VMSnapshot.class.getName(), vmSnapshot.getUuid());
} catch (Exception e) {
s_logger.error("Failed to publis usage event " + type, e);
}
}
@Override
public boolean revertVMSnapshot(VMSnapshot vmSnapshot) {
VMSnapshotVO vmSnapshotVO = (VMSnapshotVO)vmSnapshot;

View File

@ -209,6 +209,7 @@ public class DefaultEndPointSelector implements EndPointSelector {
@Override
public EndPoint select(DataObject srcData, DataObject destData, StorageAction action) {
s_logger.error("IR24 select BACKUPSNAPSHOT from primary to secondary " + srcData.getId() + " dest=" + destData.getId());
if (action == StorageAction.BACKUPSNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
SnapshotInfo srcSnapshot = (SnapshotInfo)srcData;
VolumeInfo volumeInfo = srcSnapshot.getBaseVolume();

View File

@ -55,6 +55,7 @@ public class QuotaTypes extends UsageTypes {
quotaTypeList.put(VM_DISK_BYTES_READ, new QuotaTypes(VM_DISK_BYTES_READ, "VM_DISK_BYTES_READ", "GB", "VM Disk usage(Bytes Read)"));
quotaTypeList.put(VM_DISK_BYTES_WRITE, new QuotaTypes(VM_DISK_BYTES_WRITE, "VPN_USERS", "GB", "VM Disk usage(Bytes Write)"));
quotaTypeList.put(VM_SNAPSHOT, new QuotaTypes(VM_SNAPSHOT, "VM_SNAPSHOT", "GB-Month", "VM Snapshot storage usage"));
quotaTypeList.put(VM_SNAPSHOT_ON_PRIMARY, new QuotaTypes(VM_SNAPSHOT_ON_PRIMARY, "VM_SNAPSHOT_ON_PRIMARY", "GB-Month", "VM Snapshot primary storage usage"));
quotaTypeList.put(CPU_CLOCK_RATE, new QuotaTypes(CPU_CLOCK_RATE, "CPU_CLOCK_RATE", "Compute-Month", "Quota tariff for using 1 CPU of clock rate 100MHz"));
quotaTypeList.put(CPU_NUMBER, new QuotaTypes(CPU_NUMBER, "CPU_NUMBER", "Compute-Month", "Quota tariff for running VM that has 1vCPU"));
quotaTypeList.put(MEMORY, new QuotaTypes(MEMORY, "MEMORY", "Compute-Month", "Quota tariff for using 1MB of RAM"));

View File

@ -57,6 +57,7 @@ import com.cloud.usage.dao.UsageNetworkDao;
import com.cloud.usage.dao.UsageNetworkOfferingDao;
import com.cloud.usage.dao.UsagePortForwardingRuleDao;
import com.cloud.usage.dao.UsageSecurityGroupDao;
import com.cloud.usage.dao.UsageVMSnapshotOnPrimaryDao;
import com.cloud.usage.dao.UsageStorageDao;
import com.cloud.usage.dao.UsageVMInstanceDao;
import com.cloud.usage.dao.UsageVMSnapshotDao;
@ -75,6 +76,7 @@ import com.cloud.usage.parser.VMSnapshotUsageParser;
import com.cloud.usage.parser.VPNUserUsageParser;
import com.cloud.usage.parser.VmDiskUsageParser;
import com.cloud.usage.parser.VolumeUsageParser;
import com.cloud.usage.parser.VMSanpshotOnPrimaryParser;
import com.cloud.user.Account;
import com.cloud.user.AccountVO;
import com.cloud.user.UserStatisticsVO;
@ -87,6 +89,7 @@ import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.TransactionLegacy;
@ -145,6 +148,8 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
@Inject
private UsageVMSnapshotDao _usageVMSnapshotDao;
@Inject
private UsageVMSnapshotOnPrimaryDao _usageSnapshotOnPrimaryDao;
@Inject
private QuotaManager _quotaManager;
@Inject
private QuotaAlertManager _alertManager;
@ -939,6 +944,18 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
s_logger.debug("VM Snapshot usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")");
}
}
parsed = VMSnapshotUsageParser.parse(account, currentStartDate, currentEndDate);
if (s_logger.isDebugEnabled()) {
if (!parsed) {
s_logger.debug("VM Snapshot usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")");
}
}
parsed = VMSanpshotOnPrimaryParser.parse(account, currentStartDate, currentEndDate);
if (s_logger.isDebugEnabled()) {
if (!parsed) {
s_logger.debug("VM Snapshot on primary usage successfully parsed? " + parsed + " (for account: " + account.getAccountName() + ", id: " + account.getId() + ")");
}
}
return parsed;
}
@ -968,6 +985,8 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
createSecurityGroupEvent(event);
} else if (isVmSnapshotEvent(eventType)) {
createVMSnapshotEvent(event);
} else if (isVmSnapshotOnPrimaryEvent(eventType)) {
createVmSnapshotOnPrimaryEvent(event);
}
}
@ -1043,6 +1062,12 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
return (eventType.equals(EventTypes.EVENT_VM_SNAPSHOT_CREATE) || eventType.equals(EventTypes.EVENT_VM_SNAPSHOT_DELETE));
}
private boolean isVmSnapshotOnPrimaryEvent(String eventType) {
if (eventType == null)
return false;
return (eventType.equals(EventTypes.EVENT_VM_SNAPSHOT_ON_PRIMARY) || eventType.equals(EventTypes.EVENT_VM_SNAPSHOT_OFF_PRIMARY));
}
private void createVMHelperEvent(UsageEventVO event) {
// One record for handling VM.START and VM.STOP
@ -1806,6 +1831,43 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna
_usageVMSnapshotDao.persist(vsVO);
}
private void createVmSnapshotOnPrimaryEvent(UsageEventVO event) {
Long vmId = event.getResourceId();
String name = event.getResourceName();
if (EventTypes.EVENT_VM_SNAPSHOT_ON_PRIMARY.equals(event.getType())) {
Long zoneId = event.getZoneId();
Long accountId = event.getAccountId();
long physicalsize = (event.getSize() == null) ? 0 : event.getSize();
long virtualsize = (event.getVirtualSize() == null) ? 0 : event.getVirtualSize();
Date created = event.getCreateDate();
Account acct = _accountDao.findByIdIncludingRemoved(event.getAccountId());
Long domainId = acct.getDomainId();
UsageSnapshotOnPrimaryVO vsVO = new UsageSnapshotOnPrimaryVO(vmId, zoneId, accountId, domainId, vmId, name, 0, virtualsize, physicalsize, created, null);
if (s_logger.isDebugEnabled()) {
s_logger.debug("createSnapshotOnPrimaryEvent UsageSnapshotOnPrimaryVO " + vsVO);
}
_usageSnapshotOnPrimaryDao.persist(vsVO);
} else if (EventTypes.EVENT_VM_SNAPSHOT_OFF_PRIMARY.equals(event.getType())) {
QueryBuilder<UsageSnapshotOnPrimaryVO> sc = QueryBuilder.create(UsageSnapshotOnPrimaryVO.class);
sc.and(sc.entity().getAccountId(), SearchCriteria.Op.EQ, event.getAccountId());
sc.and(sc.entity().getId(), SearchCriteria.Op.EQ, vmId);
sc.and(sc.entity().getName(), SearchCriteria.Op.EQ, name);
sc.and(sc.entity().getDeleted(), SearchCriteria.Op.NULL);
List<UsageSnapshotOnPrimaryVO> vmsnaps = sc.list();
if (vmsnaps.size() > 1) {
s_logger.warn("More that one usage entry for vm snapshot: " + name + " for vm id:" + vmId + " assigned to account: " + event.getAccountId()
+ "; marking them all as deleted...");
}
for (UsageSnapshotOnPrimaryVO vmsnap : vmsnaps) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("deleting vm snapshot name: " + vmsnap.getName() + " from account: " + vmsnap.getAccountId());
}
vmsnap.setDeleted(event.getCreateDate()); // there really shouldn't be more than one
_usageSnapshotOnPrimaryDao.updateDeleted(vmsnap);
}
}
}
private class Heartbeat extends ManagedContextRunnable {
@Override
protected void runInContext() {

View File

@ -0,0 +1,129 @@
// 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.text.DecimalFormat;
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.springframework.stereotype.Component;
import org.apache.cloudstack.usage.UsageTypes;
import com.cloud.usage.UsageSnapshotOnPrimaryVO;
import com.cloud.usage.UsageVO;
import com.cloud.usage.dao.UsageDao;
import com.cloud.usage.dao.UsageVMSnapshotOnPrimaryDao;
import com.cloud.user.AccountVO;
@Component
public class VMSanpshotOnPrimaryParser {
public static final Logger s_logger = Logger.getLogger(VMSanpshotOnPrimaryParser.class.getName());
private static UsageDao s_usageDao;
private static UsageVMSnapshotOnPrimaryDao s_usageSnapshotOnPrimaryDao;
@Inject
private UsageDao _usageDao;
@Inject
private UsageVMSnapshotOnPrimaryDao _usageSnapshotOnPrimaryDao;
@PostConstruct
void init() {
s_usageDao = _usageDao;
s_usageSnapshotOnPrimaryDao = _usageSnapshotOnPrimaryDao;
}
public static boolean parse(AccountVO account, Date startDate, Date endDate) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Parsing all VmSnapshot on primary usage events for account: " + account.getId());
}
if ((endDate == null) || endDate.after(new Date())) {
endDate = new Date();
}
List<UsageSnapshotOnPrimaryVO> usageUsageVMSnapshots = s_usageSnapshotOnPrimaryDao.getUsageRecords(account.getId(), account.getDomainId(), startDate, endDate);
if (usageUsageVMSnapshots.isEmpty()) {
s_logger.debug("No VM snapshot on primary usage events for this period");
return true;
}
Map<String, UsageSnapshotOnPrimaryVO> unprocessedUsage = new HashMap<String, UsageSnapshotOnPrimaryVO>();
for (UsageSnapshotOnPrimaryVO usageRec : usageUsageVMSnapshots) {
s_logger.debug("usageRec for VMsnap on primary " + usageRec.toString());
String key = usageRec.getName();
if (usageRec.getPhysicalSize() == 0) {
usageRec.setDeleted(new Date());
s_usageSnapshotOnPrimaryDao.updateDeleted(usageRec);
} else {
unprocessedUsage.put(key, usageRec);
}
}
for (String key : unprocessedUsage.keySet()) {
UsageSnapshotOnPrimaryVO usageRec = unprocessedUsage.get(key);
Date created = usageRec.getCreated();
if (created.before(startDate)) {
created = startDate;
}
Date endDateEffective = endDate;
if (usageRec.getDeleted() != null && usageRec.getDeleted().before(endDate)){
endDateEffective = usageRec.getDeleted();
s_logger.debug("Remoevd vm snapshot found endDateEffective " + endDateEffective + " period end data " + endDate);
}
long duration = (endDateEffective.getTime() - created.getTime()) + 1;
createUsageRecord(UsageTypes.VM_SNAPSHOT_ON_PRIMARY, duration, created, endDateEffective, account, usageRec.getId(), usageRec.getName(), usageRec.getZoneId(),
usageRec.getVirtualSize(), usageRec.getPhysicalSize());
}
return true;
}
private static void createUsageRecord(int usageType, long runningTime, Date startDate, Date endDate, AccountVO account, long vmId, String name, long zoneId, long virtualSize,
long physicalSize) {
// Our smallest increment is hourly for now
if (s_logger.isDebugEnabled()) {
s_logger.debug("Total running time " + runningTime + "ms");
}
float usage = runningTime / 1000f / 60f / 60f;
DecimalFormat dFormat = new DecimalFormat("#.######");
String usageDisplay = dFormat.format(usage);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating VMSnapshot On Primary usage record for vm: " + vmId + ", usage: " + usageDisplay + ", startDate: " + startDate + ", endDate: " + endDate
+ ", for account: " + account.getId());
}
// Create the usage record
String usageDesc = "VMSnapshot On Primary Usage: " + "VM Id: " + vmId;
usageDesc += " Size: " + virtualSize;
UsageVO usageRecord = new UsageVO(zoneId, account.getId(), account.getDomainId(), usageDesc, usageDisplay + " Hrs", usageType, new Double(usage), vmId, name, null, null,
vmId, physicalSize, virtualSize, startDate, endDate);
s_usageDao.persist(usageRecord);
}
}