Skip to content

Commit bce714c

Browse files
committed
server, plugin: enhance storage stats for IOPS
Adds framework layer change to allow retrieving and storing IOPS stats for storage pools. Custom `PrimaryStoreDriver` can implement method - `getStorageIopsStats` for returning IOPS stats. Existing method `getUsedIops` can also be overridden by such plugins when only used IOPS is returned. For testing purpose, implementation has been added for simulator hypervisor plugin to return capacity and used IOPS for a pool. For local storage pool, implementation has been added using iostat to return currently used IOPS. StoragePoolResponse class has been updated to return IOPS values which allows showing IOPS values in UI for different storage pool related views and APIs. Signed-off-by: Abhishek Kumar <[email protected]>
1 parent b3dc402 commit bce714c

File tree

26 files changed

+494
-85
lines changed

26 files changed

+494
-85
lines changed

api/src/main/java/com/cloud/storage/StorageStats.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,7 @@ public interface StorageStats {
2626
* @return bytes capacity of the storage server
2727
*/
2828
public long getCapacityBytes();
29+
30+
Long getCapacityIops();
31+
Long getUsedIops();
2932
}

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ public class ApiConstants {
509509
public static final String URL = "url";
510510
public static final String USAGE_INTERFACE = "usageinterface";
511511
public static final String USED_SUBNETS = "usedsubnets";
512+
public static final String USED_IOPS = "usediops";
512513
public static final String USER_DATA = "userdata";
513514

514515
public static final String USER_DATA_NAME = "userdataname";

api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations {
9797
@Param(description = "total min IOPS currently in use by volumes")
9898
private Long allocatedIops;
9999

100+
@SerializedName(ApiConstants.USED_IOPS)
101+
@Param(description = "total IOPS currently in use", since = "4.20.1")
102+
private Long usedIops;
103+
100104
@SerializedName(ApiConstants.STORAGE_CUSTOM_STATS)
101105
@Param(description = "the storage pool custom stats", since = "4.18.1")
102106
private Map<String, String> customStats;
@@ -312,6 +316,14 @@ public void setAllocatedIops(Long allocatedIops) {
312316
this.allocatedIops = allocatedIops;
313317
}
314318

319+
public Long getUsedIops() {
320+
return usedIops;
321+
}
322+
323+
public void setUsedIops(Long usedIops) {
324+
this.usedIops = usedIops;
325+
}
326+
315327
public Map<String, String> getCustomStats() {
316328
return customStats;
317329
}

core/src/main/java/com/cloud/agent/api/GetStorageStatsAnswer.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,46 @@ public class GetStorageStatsAnswer extends Answer implements StorageStats {
2727
protected GetStorageStatsAnswer() {
2828
}
2929

30-
protected long used;
30+
protected long usedBytes;
3131

32-
protected long capacity;
32+
protected long capacityBytes;
33+
34+
protected Long capacityIops;
35+
36+
protected Long usedIops;
3337

3438
@Override
3539
public long getByteUsed() {
36-
return used;
40+
return usedBytes;
3741
}
3842

3943
@Override
4044
public long getCapacityBytes() {
41-
return capacity;
45+
return capacityBytes;
46+
}
47+
48+
@Override
49+
public Long getCapacityIops() {
50+
return capacityIops;
51+
}
52+
53+
@Override
54+
public Long getUsedIops() {
55+
return usedIops;
56+
}
57+
58+
public GetStorageStatsAnswer(GetStorageStatsCommand cmd, long capacityBytes, long usedBytes) {
59+
super(cmd, true, null);
60+
this.capacityBytes = capacityBytes;
61+
this.usedBytes = usedBytes;
4262
}
4363

44-
public GetStorageStatsAnswer(GetStorageStatsCommand cmd, long capacity, long used) {
64+
public GetStorageStatsAnswer(GetStorageStatsCommand cmd, long capacityBytes, long usedBytes, Long capacityIops, Long usedIops) {
4565
super(cmd, true, null);
46-
this.capacity = capacity;
47-
this.used = used;
66+
this.capacityBytes = capacityBytes;
67+
this.usedBytes = usedBytes;
68+
this.capacityIops = capacityIops;
69+
this.usedIops = usedIops;
4870
}
4971

5072
public GetStorageStatsAnswer(GetStorageStatsCommand cmd, String details) {

debian/control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Description: CloudStack server library
2424

2525
Package: cloudstack-agent
2626
Architecture: all
27-
Depends: ${python:Depends}, ${python3:Depends}, openjdk-17-jre-headless | java17-runtime-headless | java17-runtime | zulu-17, cloudstack-common (= ${source:Version}), lsb-base (>= 9), openssh-client, qemu-kvm (>= 2.5) | qemu-system-x86 (>= 5.2), libvirt-bin (>= 1.3) | libvirt-daemon-system (>= 3.0), iproute2, ebtables, vlan, ipset, python3-libvirt, ethtool, iptables, cryptsetup, rng-tools, rsync, lsb-release, ufw, apparmor, cpu-checker, libvirt-daemon-driver-storage-rbd
27+
Depends: ${python:Depends}, ${python3:Depends}, openjdk-17-jre-headless | java17-runtime-headless | java17-runtime | zulu-17, cloudstack-common (= ${source:Version}), lsb-base (>= 9), openssh-client, qemu-kvm (>= 2.5) | qemu-system-x86 (>= 5.2), libvirt-bin (>= 1.3) | libvirt-daemon-system (>= 3.0), iproute2, ebtables, vlan, ipset, python3-libvirt, ethtool, iptables, cryptsetup, rng-tools, rsync, lsb-release, ufw, apparmor, cpu-checker, libvirt-daemon-driver-storage-rbd, sysstat
2828
Recommends: init-system-helpers
2929
Conflicts: cloud-agent, cloud-agent-libs, cloud-agent-deps, cloud-agent-scripts
3030
Description: CloudStack agent

engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ default Map<String, String> getCustomStorageStats(StoragePool pool) {
111111
*/
112112
Pair<Long, Long> getStorageStats(StoragePool storagePool);
113113

114+
/**
115+
* Intended for managed storage
116+
* returns the capacity and used IOPS or null if not supported
117+
*/
118+
default Pair<Long, Long> getStorageIopsStats(StoragePool storagePool) {
119+
return null;
120+
}
121+
114122
/**
115123
* intended for managed storage
116124
* returns true if the storage can provide the volume stats (physical and virtual size)

engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@
2323
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
2424
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl;
2525
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
26+
import org.apache.commons.collections.CollectionUtils;
2627

2728
import com.cloud.storage.Storage.StoragePoolType;
2829
import com.cloud.storage.VolumeVO;
2930
import com.cloud.storage.dao.VolumeDao;
3031
import com.cloud.storage.dao.VolumeDaoImpl;
3132
import com.cloud.upgrade.SystemVmTemplateRegistration;
33+
import com.cloud.utils.db.GenericSearchBuilder;
34+
import com.cloud.utils.db.SearchBuilder;
35+
import com.cloud.utils.db.SearchCriteria;
3236
import com.cloud.utils.exception.CloudRuntimeException;
3337

3438
public class Upgrade41700to41710 extends DbUpgradeAbstractImpl implements DbUpgradeSystemVmTemplate {
@@ -95,24 +99,46 @@ public void updateSystemVmTemplates(Connection conn) {
9599
}
96100
}
97101

102+
/*
103+
GenericDao.customSearch using GenericSearchBuilder and GenericDao.update using
104+
GenericDao.createSearchBuilder used here to prevent any future issues when new fields
105+
are added to StoragePoolVO or VolumeVO and this upgrade path starts to fail.
106+
*/
98107
private void updateStorPoolStorageType() {
99108
storageDao = new PrimaryDataStoreDaoImpl();
100-
List<StoragePoolVO> storPoolPools = storageDao.findPoolsByProvider("StorPool");
101-
for (StoragePoolVO storagePoolVO : storPoolPools) {
102-
if (StoragePoolType.SharedMountPoint == storagePoolVO.getPoolType()) {
103-
storagePoolVO.setPoolType(StoragePoolType.StorPool);
104-
storageDao.update(storagePoolVO.getId(), storagePoolVO);
105-
}
106-
updateStorageTypeForStorPoolVolumes(storagePoolVO.getId());
109+
StoragePoolVO pool = storageDao.createForUpdate();
110+
pool.setPoolType(StoragePoolType.StorPool);
111+
SearchBuilder<StoragePoolVO> sb = storageDao.createSearchBuilder();
112+
sb.and("provider", sb.entity().getStorageProviderName(), SearchCriteria.Op.EQ);
113+
sb.and("type", sb.entity().getPoolType(), SearchCriteria.Op.EQ);
114+
sb.done();
115+
SearchCriteria<StoragePoolVO> sc = sb.create();
116+
sc.setParameters("provider", StoragePoolType.StorPool.name());
117+
sc.setParameters("type", StoragePoolType.SharedMountPoint.name());
118+
storageDao.update(pool, sc);
119+
120+
GenericSearchBuilder<StoragePoolVO, Long> gSb = storageDao.createSearchBuilder(Long.class);
121+
gSb.selectFields(gSb.entity().getId());
122+
gSb.and("provider", gSb.entity().getStorageProviderName(), SearchCriteria.Op.EQ);
123+
gSb.done();
124+
SearchCriteria<Long> gSc = gSb.create();
125+
gSc.setParameters("provider", StoragePoolType.StorPool.name());
126+
List<Long> poolIds = storageDao.customSearch(gSc, null);
127+
if (CollectionUtils.isEmpty(poolIds)) {
128+
return;
107129
}
130+
updateStorageTypeForStorPoolVolumes(poolIds);
108131
}
109132

110-
private void updateStorageTypeForStorPoolVolumes(long storagePoolId) {
133+
private void updateStorageTypeForStorPoolVolumes(List<Long> storagePoolIds) {
111134
volumeDao = new VolumeDaoImpl();
112-
List<VolumeVO> volumes = volumeDao.findByPoolId(storagePoolId, null);
113-
for (VolumeVO volumeVO : volumes) {
114-
volumeVO.setPoolType(StoragePoolType.StorPool);
115-
volumeDao.update(volumeVO.getId(), volumeVO);
116-
}
135+
VolumeVO volume = volumeDao.createForUpdate();
136+
volume.setPoolType(StoragePoolType.StorPool);
137+
SearchBuilder<VolumeVO> sb = volumeDao.createSearchBuilder();
138+
sb.and("poolId", sb.entity().getPoolId(), SearchCriteria.Op.IN);
139+
sb.done();
140+
SearchCriteria<VolumeVO> sc = sb.create();
141+
sc.setParameters("poolId", storagePoolIds.toArray());
142+
volumeDao.update(volume, sc);
117143
}
118144
}

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ public class StoragePoolVO implements StoragePool {
118118
@Column(name = "capacity_iops", updatable = true, nullable = true)
119119
private Long capacityIops;
120120

121+
@Column(name = "used_iops", updatable = true, nullable = true)
122+
private Long usedIops;
123+
121124
@Column(name = "hypervisor")
122125
@Convert(converter = HypervisorTypeConverter.class)
123126
private HypervisorType hypervisor;
@@ -255,6 +258,14 @@ public Long getCapacityIops() {
255258
return capacityIops;
256259
}
257260

261+
public Long getUsedIops() {
262+
return usedIops;
263+
}
264+
265+
public void setUsedIops(Long usedIops) {
266+
this.usedIops = usedIops;
267+
}
268+
258269
@Override
259270
public Long getClusterId() {
260271
return clusterId;

engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,6 @@ CALL `cloud`.`IDEMPOTENT_DROP_FOREIGN_KEY`('cloud.mshost_peer','fk_mshost_peer__
2929
CALL `cloud`.`IDEMPOTENT_DROP_INDEX`('i_mshost_peer__owner_peer_runid','mshost_peer');
3030
CALL `cloud`.`IDEMPOTENT_ADD_UNIQUE_KEY`('cloud.mshost_peer', 'i_mshost_peer__owner_peer', '(owner_mshost, peer_mshost)');
3131
CALL `cloud`.`IDEMPOTENT_ADD_FOREIGN_KEY`('cloud.mshost_peer', 'fk_mshost_peer__owner_mshost', '(owner_mshost)', '`mshost`(`id`)');
32+
33+
-- Add used_iops column to support IOPS data in storage stats
34+
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.storage_pool', 'used_iops', 'bigint(20) unsigned DEFAULT NULL COMMENT "IOPS currently in use for this storage pool" ');

engine/schema/src/main/resources/META-INF/db/views/cloud.storage_pool_view.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ SELECT
3232
`storage_pool`.`removed` AS `removed`,
3333
`storage_pool`.`capacity_bytes` AS `capacity_bytes`,
3434
`storage_pool`.`capacity_iops` AS `capacity_iops`,
35+
`storage_pool`.`used_iops` AS `used_iops`,
3536
`storage_pool`.`scope` AS `scope`,
3637
`storage_pool`.`hypervisor` AS `hypervisor`,
3738
`storage_pool`.`storage_provider_name` AS `storage_provider_name`,

0 commit comments

Comments
 (0)