Skip to content

Commit bfc0871

Browse files
nvazquezPaul Angus
authored andcommitted
Display VM snapshot tags on usage records (apache#3560)
* Refactor usage helper tables to include VM snapshot id * Fix resource type and resource id while listing usage records * Add defensive checks
1 parent 7ac9f00 commit bfc0871

File tree

12 files changed

+152
-28
lines changed

12 files changed

+152
-28
lines changed

engine/components-api/src/main/java/com/cloud/event/UsageEventUtils.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import javax.annotation.PostConstruct;
2626
import javax.inject.Inject;
2727

28+
import org.apache.commons.collections.MapUtils;
2829
import org.apache.log4j.Logger;
2930
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3031

@@ -69,6 +70,12 @@ void init() {
6970
s_configDao = configDao;
7071
}
7172

73+
public static void publishUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId,
74+
Long size, String entityType, String entityUUID, Map<String, String> details) {
75+
saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size, details);
76+
publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID);
77+
}
78+
7279
public static void publishUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId,
7380
Long size, String entityType, String entityUUID) {
7481
saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size);
@@ -84,6 +91,12 @@ public static void publishUsageEvent(String usageType, long accountId, long zone
8491

8592
}
8693

94+
public static void publishUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId,
95+
Long size, Long virtualSize, String entityType, String entityUUID, Map<String, String> details) {
96+
saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size, virtualSize, details);
97+
publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID);
98+
}
99+
87100
public static void publishUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId,
88101
Long size, Long virtualSize, String entityType, String entityUUID) {
89102
saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size, virtualSize);
@@ -142,11 +155,28 @@ public static void saveUsageEvent(String usageType, long accountId, long zoneId,
142155
s_usageEventDao.persist(new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size));
143156
}
144157

158+
public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId, Long size, Map<String, String> details) {
159+
UsageEventVO usageEventVO = new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size);
160+
s_usageEventDao.persist(usageEventVO);
161+
if (MapUtils.isNotEmpty(details)) {
162+
s_usageEventDao.saveDetails(usageEventVO.getId(), details);
163+
}
164+
}
165+
145166
public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId, Long size,
146167
Long virtualSize) {
147168
s_usageEventDao.persist(new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size, virtualSize));
148169
}
149170

171+
public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId, Long size,
172+
Long virtualSize, Map<String, String> details) {
173+
UsageEventVO usageEventVO = new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size, virtualSize);
174+
s_usageEventDao.persist(usageEventVO);
175+
if (MapUtils.isNotEmpty(details)) {
176+
s_usageEventDao.saveDetails(usageEventVO.getId(), details);
177+
}
178+
}
179+
150180
public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName) {
151181
s_usageEventDao.persist(new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName));
152182
}

engine/schema/src/main/java/com/cloud/event/UsageEventVO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
@Table(name = "usage_event")
3232
public class UsageEventVO implements UsageEvent {
3333
public enum DynamicParameters {
34-
cpuSpeed, cpuNumber, memory
34+
cpuSpeed, cpuNumber, memory, vmSnapshotId
3535
};
3636

3737
@Id

engine/schema/src/main/java/com/cloud/usage/UsageSnapshotOnPrimaryVO.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ public class UsageSnapshotOnPrimaryVO implements InternalIdentity {
6666
@Column(name = "virtualsize")
6767
private Long virtualSize;
6868

69+
@Column(name = "vm_snapshot_id")
70+
private Long vmSnapshotId;
71+
6972
protected UsageSnapshotOnPrimaryVO() {
7073
}
7174

@@ -136,10 +139,18 @@ public long getId() {
136139
return this.id;
137140
}
138141

142+
public Long getVmSnapshotId() {
143+
return vmSnapshotId;
144+
}
145+
146+
public void setVmSnapshotId(Long vmSnapshotId) {
147+
this.vmSnapshotId = vmSnapshotId;
148+
}
149+
139150
@Override
140151
public String toString() {
141152
return "UsageSnapshotOnPrimaryVO [id=" + id + ", zoneId=" + zoneId + ", accountId=" + accountId + ", domainId=" + domainId + ", vmId=" + vmId + ", name=" + name
142-
+ ", snapshotType=" + snapshotType + ", physicalSize=" + physicalSize + ", created=" + created + ", deleted=" + deleted + ", virtualSize=" + virtualSize + "]";
153+
+ ", snapshotType=" + snapshotType + ", physicalSize=" + physicalSize + ", created=" + created + ", deleted=" + deleted + ", virtualSize=" + virtualSize + ", vmSnapshotId=" + vmSnapshotId + "]";
143154
}
144155

145156
}

engine/schema/src/main/java/com/cloud/usage/UsageVMSnapshotVO.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ public class UsageVMSnapshotVO implements InternalIdentity {
6060
@Temporal(value = TemporalType.TIMESTAMP)
6161
private Date processed;
6262

63+
@Column(name = "vm_snapshot_id")
64+
private Long vmSnapshotId;
65+
6366
protected UsageVMSnapshotVO() {
6467
}
6568

@@ -120,10 +123,18 @@ public long getId() {
120123
return this.id;
121124
}
122125

126+
public Long getVmSnapshotId() {
127+
return vmSnapshotId;
128+
}
129+
130+
public void setVmSnapshotId(Long vmSnapshotId) {
131+
this.vmSnapshotId = vmSnapshotId;
132+
}
133+
123134
@Override
124135
public String toString() {
125136
return "UsageVMSnapshotVO [id=" + id + ", zoneId=" + zoneId + ", accountId=" + accountId + ", domainId=" + domainId + ", vmId=" + vmId + ", diskOfferingId="
126-
+ diskOfferingId + ", size=" + size + ", created=" + created + ", processed=" + processed + "]";
137+
+ diskOfferingId + ", size=" + size + ", created=" + created + ", processed=" + processed + ", vmSnapshotId=" + vmSnapshotId + "]";
127138
}
128139

129140
}

engine/schema/src/main/java/com/cloud/usage/dao/UsageVMSnapshotDaoImpl.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.TimeZone;
2626

2727

28+
import org.apache.commons.lang.StringUtils;
2829
import org.apache.log4j.Logger;
2930
import org.springframework.stereotype.Component;
3031

@@ -36,12 +37,12 @@
3637
@Component
3738
public class UsageVMSnapshotDaoImpl extends GenericDaoBase<UsageVMSnapshotVO, Long> implements UsageVMSnapshotDao {
3839
public static final Logger s_logger = Logger.getLogger(UsageVMSnapshotDaoImpl.class.getName());
39-
protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT id, zone_id, account_id, domain_id, vm_id, disk_offering_id, size, created, processed "
40+
protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT id, zone_id, account_id, domain_id, vm_id, disk_offering_id, size, created, processed, vm_snapshot_id "
4041
+ " FROM usage_vmsnapshot" + " WHERE account_id = ? " + " AND ( (created BETWEEN ? AND ?) OR "
4142
+ " (created < ? AND processed is NULL) ) ORDER BY created asc";
4243
protected static final String UPDATE_DELETED = "UPDATE usage_vmsnapshot SET processed = ? WHERE account_id = ? AND id = ? and vm_id = ? and created = ?";
4344

44-
protected static final String PREVIOUS_QUERY = "SELECT id, zone_id, account_id, domain_id, vm_id, disk_offering_id,size, created, processed "
45+
protected static final String PREVIOUS_QUERY = "SELECT id, zone_id, account_id, domain_id, vm_id, disk_offering_id,size, created, processed, vm_snapshot_id "
4546
+ "FROM usage_vmsnapshot " + "WHERE account_id = ? AND id = ? AND vm_id = ? AND created < ? AND processed IS NULL " + "ORDER BY created desc limit 1";
4647

4748
@Override
@@ -99,14 +100,18 @@ public List<UsageVMSnapshotVO> getUsageRecords(Long accountId, Long domainId, Da
99100
Date processDate = null;
100101
String createdTS = rs.getString(8);
101102
String processed = rs.getString(9);
103+
String snapId = rs.getString(10);
104+
Long vmSnapshotId = StringUtils.isNotBlank(snapId) ? Long.valueOf(snapId) : null;
102105

103106
if (createdTS != null) {
104107
createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS);
105108
}
106109
if (processed != null) {
107110
processDate = DateUtil.parseDateString(s_gmtTimeZone, processed);
108111
}
109-
usageRecords.add(new UsageVMSnapshotVO(vId, zoneId, acctId, dId, vmId, doId, size, createdDate, processDate));
112+
UsageVMSnapshotVO usageVMSnapshotVO = new UsageVMSnapshotVO(vId, zoneId, acctId, dId, vmId, doId, size, createdDate, processDate);
113+
usageVMSnapshotVO.setVmSnapshotId(vmSnapshotId);
114+
usageRecords.add(usageVMSnapshotVO);
110115
}
111116
} catch (Exception e) {
112117
txn.rollback();
@@ -150,14 +155,18 @@ public UsageVMSnapshotVO getPreviousUsageRecord(UsageVMSnapshotVO rec) {
150155
Date processDate = null;
151156
String createdTS = rs.getString(8);
152157
String processed = rs.getString(9);
158+
String snapId = rs.getString(10);
159+
Long vmSnapshotId = StringUtils.isNotBlank(snapId) ? Long.valueOf(snapId) : null;
153160

154161
if (createdTS != null) {
155162
createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS);
156163
}
157164
if (processed != null) {
158165
processDate = DateUtil.parseDateString(s_gmtTimeZone, processed);
159166
}
160-
usageRecords.add(new UsageVMSnapshotVO(vId, zoneId, acctId, dId, vmId, doId, size, createdDate, processDate));
167+
UsageVMSnapshotVO usageVMSnapshotVO = new UsageVMSnapshotVO(vId, zoneId, acctId, dId, vmId, doId, size, createdDate, processDate);
168+
usageVMSnapshotVO.setVmSnapshotId(vmSnapshotId);
169+
usageRecords.add(usageVMSnapshotVO);
161170
}
162171
} catch (Exception e) {
163172
txn.rollback();

engine/schema/src/main/java/com/cloud/usage/dao/UsageVMSnapshotOnPrimaryDaoImpl.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.TimeZone;
2626

2727

28+
import org.apache.commons.lang.StringUtils;
2829
import org.apache.log4j.Logger;
2930
import org.springframework.stereotype.Component;
3031

@@ -36,7 +37,7 @@
3637
@Component
3738
public class UsageVMSnapshotOnPrimaryDaoImpl extends GenericDaoBase<UsageSnapshotOnPrimaryVO, Long> implements UsageVMSnapshotOnPrimaryDao {
3839
public static final Logger s_logger = Logger.getLogger(UsageVMSnapshotOnPrimaryDaoImpl.class.getName());
39-
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 "
40+
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, vm_snapshot_id "
4041
+ " FROM usage_snapshot_on_primary" + " WHERE account_id = ? " + " AND ( (created < ? AND deleted is NULL)"
4142
+ " OR ( deleted BETWEEN ? AND ?)) ORDER BY created asc";
4243
protected static final String UPDATE_DELETED = "UPDATE usage_snapshot_on_primary SET deleted = ? WHERE account_id = ? AND id = ? and vm_id = ? and created = ?";
@@ -95,14 +96,18 @@ public List<UsageSnapshotOnPrimaryVO> getUsageRecords(Long accountId, Long domai
9596
Date deleteDate = null;
9697
String createdTS = rs.getString(10);
9798
String deleted = rs.getString(11);
99+
String snapId = rs.getString(12);
100+
Long vmSnapshotId = StringUtils.isNotBlank(snapId) ? Long.valueOf(snapId) : null;
98101

99102
if (createdTS != null) {
100103
createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS);
101104
}
102105
if (deleted != null) {
103106
deleteDate = DateUtil.parseDateString(s_gmtTimeZone, deleted);
104107
}
105-
usageRecords.add(new UsageSnapshotOnPrimaryVO(vId, zoneId, acctId, dId, vmId, name, type, virtaulSize, physicalSize, createdDate, deleteDate));
108+
UsageSnapshotOnPrimaryVO usageSnapshotOnPrimaryVO = new UsageSnapshotOnPrimaryVO(vId, zoneId, acctId, dId, vmId, name, type, virtaulSize, physicalSize, createdDate, deleteDate);
109+
usageSnapshotOnPrimaryVO.setVmSnapshotId(vmSnapshotId);
110+
usageRecords.add(usageSnapshotOnPrimaryVO);
106111
}
107112
} catch (Exception e) {
108113
txn.rollback();

engine/schema/src/main/resources/META-INF/db/schema-41200to41300.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,3 +531,7 @@ CREATE TABLE `cloud`.`template_ovf_properties` (
531531
CONSTRAINT `fk_template_ovf_properties__template_id` FOREIGN KEY (`template_id`) REFERENCES `vm_template`(`id`)
532532
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
533533

534+
-- Add VM snapshot ID on usage helper tables
535+
ALTER TABLE `cloud_usage`.`usage_vmsnapshot` ADD COLUMN `vm_snapshot_id` BIGINT(20) NULL DEFAULT NULL AFTER `processed`;
536+
ALTER TABLE `cloud_usage`.`usage_snapshot_on_primary` ADD COLUMN `vm_snapshot_id` BIGINT(20) NULL DEFAULT NULL AFTER `deleted`;
537+

engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/DefaultVMSnapshotStrategy.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
*/
1919
package org.apache.cloudstack.storage.vmsnapshot;
2020

21+
import java.util.HashMap;
2122
import java.util.List;
2223
import java.util.Map;
2324

2425
import javax.inject.Inject;
2526
import javax.naming.ConfigurationException;
2627

28+
import com.cloud.event.UsageEventVO;
2729
import org.apache.log4j.Logger;
2830

2931
import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
@@ -337,14 +339,22 @@ private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm
337339
offeringId = offering.getId();
338340
}
339341
}
342+
Map<String, String> details = new HashMap<>();
343+
if (vmSnapshot != null) {
344+
details.put(UsageEventVO.DynamicParameters.vmSnapshotId.name(), String.valueOf(vmSnapshot.getId()));
345+
}
340346
UsageEventUtils.publishUsageEvent(type, vmSnapshot.getAccountId(), userVm.getDataCenterId(), userVm.getId(), vmSnapshot.getName(), offeringId, volume.getId(), // save volume's id into templateId field
341-
volumeTo.getSize(), VMSnapshot.class.getName(), vmSnapshot.getUuid());
347+
volumeTo.getSize(), VMSnapshot.class.getName(), vmSnapshot.getUuid(), details);
342348
}
343349

344350
private void publishUsageEvent(String type, VMSnapshot vmSnapshot, UserVm userVm, Long vmSnapSize, Long virtualSize) {
345351
try {
352+
Map<String, String> details = new HashMap<>();
353+
if (vmSnapshot != null) {
354+
details.put(UsageEventVO.DynamicParameters.vmSnapshotId.name(), String.valueOf(vmSnapshot.getId()));
355+
}
346356
UsageEventUtils.publishUsageEvent(type, vmSnapshot.getAccountId(), userVm.getDataCenterId(), userVm.getId(), vmSnapshot.getName(), 0L, 0L, vmSnapSize, virtualSize,
347-
VMSnapshot.class.getName(), vmSnapshot.getUuid());
357+
VMSnapshot.class.getName(), vmSnapshot.getUuid(), details);
348358
} catch (Exception e) {
349359
s_logger.error("Failed to publis usage event " + type, e);
350360
}

server/src/main/java/com/cloud/api/ApiResponseHelper.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
import javax.inject.Inject;
3333

34+
import com.cloud.vm.snapshot.VMSnapshotVO;
35+
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
3436
import org.apache.cloudstack.acl.ControlledEntity;
3537
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
3638
import org.apache.cloudstack.affinity.AffinityGroup;
@@ -372,6 +374,8 @@ public class ApiResponseHelper implements ResponseGenerator {
372374
private IPAddressDao userIpAddressDao;
373375
@Inject
374376
NetworkDetailsDao networkDetailsDao;
377+
@Inject
378+
private VMSnapshotDao vmSnapshotDao;
375379

376380
@Override
377381
public UserResponse createUserResponse(User user) {
@@ -3643,24 +3647,35 @@ public UsageRecordResponse createUsageResponse(Usage usageRecord, Map<String, Se
36433647
usageRecResponse.setDescription(builder.toString());
36443648
}
36453649
} else if (usageRecord.getUsageType() == UsageTypes.VM_SNAPSHOT) {
3646-
resourceType = ResourceObjectType.UserVm;
3647-
if (vmInstance != null) {
3648-
resourceId = vmInstance.getId();
3649-
usageRecResponse.setResourceName(vmInstance.getInstanceName());
3650-
usageRecResponse.setUsageId(vmInstance.getUuid());
3650+
resourceType = ResourceObjectType.VMSnapshot;
3651+
VMSnapshotVO vmSnapshotVO = null;
3652+
if (usageRecord.getUsageId() != null) {
3653+
vmSnapshotVO = vmSnapshotDao.findByIdIncludingRemoved(usageRecord.getUsageId());
3654+
if (vmSnapshotVO != null) {
3655+
resourceId = vmSnapshotVO.getId();
3656+
usageRecResponse.setResourceName(vmSnapshotVO.getDisplayName());
3657+
usageRecResponse.setUsageId(vmSnapshotVO.getUuid());
3658+
}
36513659
}
36523660
usageRecResponse.setSize(usageRecord.getSize());
36533661
if (usageRecord.getOfferingId() != null) {
36543662
usageRecResponse.setOfferingId(usageRecord.getOfferingId().toString());
36553663
}
36563664
if (!oldFormat) {
3657-
VolumeVO volume = _entityMgr.findByIdIncludingRemoved(VolumeVO.class, usageRecord.getUsageId().toString());
3665+
VolumeVO volume = null;
3666+
if (vmSnapshotVO == null && usageRecord.getUsageId() != null) {
3667+
volume = _entityMgr.findByIdIncludingRemoved(VolumeVO.class, usageRecord.getUsageId().toString());
3668+
}
3669+
36583670
DiskOfferingVO diskOff = null;
36593671
if (usageRecord.getOfferingId() != null) {
36603672
diskOff = _entityMgr.findByIdIncludingRemoved(DiskOfferingVO.class, usageRecord.getOfferingId());
36613673
}
36623674
final StringBuilder builder = new StringBuilder();
36633675
builder.append("VMSnapshot usage");
3676+
if (vmSnapshotVO != null) {
3677+
builder.append(" Id: ").append(vmSnapshotVO.getId()).append(" (").append(vmSnapshotVO.getUuid()).append(") ");
3678+
}
36643679
if (vmInstance != null) {
36653680
builder.append(" for VM ").append(vmInstance.getHostName()).append(" (").append(vmInstance.getUuid()).append(")");
36663681
}
@@ -3684,10 +3699,23 @@ public UsageRecordResponse createUsageResponse(Usage usageRecord, Map<String, Se
36843699
usageRecResponse.setDescription(builder.toString());
36853700
}
36863701
} else if (usageRecord.getUsageType() == UsageTypes.VM_SNAPSHOT_ON_PRIMARY) {
3702+
resourceType = ResourceObjectType.VMSnapshot;
3703+
VMSnapshotVO vmSnapshotVO = null;
3704+
if (usageRecord.getUsageId() != null) {
3705+
vmSnapshotVO = vmSnapshotDao.findByIdIncludingRemoved(usageRecord.getUsageId());
3706+
if (vmSnapshotVO != null) {
3707+
resourceId = vmSnapshotVO.getId();
3708+
usageRecResponse.setResourceName(vmSnapshotVO.getDisplayName());
3709+
usageRecResponse.setUsageId(vmSnapshotVO.getUuid());
3710+
}
3711+
}
36873712
usageRecResponse.setSize(usageRecord.getVirtualSize());
36883713
if (!oldFormat) {
36893714
final StringBuilder builder = new StringBuilder();
36903715
builder.append("VMSnapshot on primary storage usage");
3716+
if (vmSnapshotVO != null) {
3717+
builder.append(" Id: ").append(vmSnapshotVO.getId()).append(" (").append(vmSnapshotVO.getUuid()).append(") ");
3718+
}
36913719
if (vmInstance != null) {
36923720
builder.append(" for VM ").append(vmInstance.getHostName()).append(" (").append(vmInstance.getUuid()).append(") ")
36933721
.append("with size ").append(usageRecord.getVirtualSize());

0 commit comments

Comments
 (0)