From bce714c385cc878f86ba27b9e827f1610b5619c7 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Wed, 13 Nov 2024 15:00:59 +0530 Subject: [PATCH 01/10] 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 --- .../java/com/cloud/storage/StorageStats.java | 3 + .../apache/cloudstack/api/ApiConstants.java | 1 + .../api/response/StoragePoolResponse.java | 12 ++ .../agent/api/GetStorageStatsAnswer.java | 36 ++++- debian/control | 2 +- .../api/storage/PrimaryDataStoreDriver.java | 8 + .../upgrade/dao/Upgrade41700to41710.java | 52 ++++-- .../storage/datastore/db/StoragePoolVO.java | 11 ++ .../META-INF/db/schema-42000to42010.sql | 3 + .../db/views/cloud.storage_pool_view.sql | 1 + packaging/el8/cloud.spec | 1 + .../LibvirtGetStorageStatsCommandWrapper.java | 3 +- .../kvm/storage/KVMStoragePool.java | 8 + .../kvm/storage/LibvirtStorageAdaptor.java | 75 +++++++-- .../kvm/storage/LibvirtStoragePool.java | 28 +++- .../storage/LibvirtStorageAdaptorTest.java | 89 +++++++++++ .../agent/manager/MockStorageManagerImpl.java | 8 +- .../cloud/simulator/dao/MockVolumeDao.java | 2 + .../simulator/dao/MockVolumeDaoImpl.java | 12 ++ .../api/query/dao/StoragePoolJoinDaoImpl.java | 9 +- .../cloud/api/query/vo/StoragePoolJoinVO.java | 14 ++ .../java/com/cloud/server/StatsCollector.java | 27 +++- .../com/cloud/storage/StorageManagerImpl.java | 23 ++- .../com/cloud/server/StatsCollectorTest.java | 148 ++++++++++++++---- ui/public/locales/en.json | 1 + .../config/section/infra/primaryStorages.js | 2 +- 26 files changed, 494 insertions(+), 85 deletions(-) diff --git a/api/src/main/java/com/cloud/storage/StorageStats.java b/api/src/main/java/com/cloud/storage/StorageStats.java index a474b23489cd..502e2aaae40a 100644 --- a/api/src/main/java/com/cloud/storage/StorageStats.java +++ b/api/src/main/java/com/cloud/storage/StorageStats.java @@ -26,4 +26,7 @@ public interface StorageStats { * @return bytes capacity of the storage server */ public long getCapacityBytes(); + + Long getCapacityIops(); + Long getUsedIops(); } diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index bf8b79b29d0c..cf03f1d2699b 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -509,6 +509,7 @@ public class ApiConstants { public static final String URL = "url"; public static final String USAGE_INTERFACE = "usageinterface"; public static final String USED_SUBNETS = "usedsubnets"; + public static final String USED_IOPS = "usediops"; public static final String USER_DATA = "userdata"; public static final String USER_DATA_NAME = "userdataname"; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java index 06d5103d7319..676803ea86b6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java @@ -97,6 +97,10 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations { @Param(description = "total min IOPS currently in use by volumes") private Long allocatedIops; + @SerializedName(ApiConstants.USED_IOPS) + @Param(description = "total IOPS currently in use", since = "4.20.1") + private Long usedIops; + @SerializedName(ApiConstants.STORAGE_CUSTOM_STATS) @Param(description = "the storage pool custom stats", since = "4.18.1") private Map customStats; @@ -312,6 +316,14 @@ public void setAllocatedIops(Long allocatedIops) { this.allocatedIops = allocatedIops; } + public Long getUsedIops() { + return usedIops; + } + + public void setUsedIops(Long usedIops) { + this.usedIops = usedIops; + } + public Map getCustomStats() { return customStats; } diff --git a/core/src/main/java/com/cloud/agent/api/GetStorageStatsAnswer.java b/core/src/main/java/com/cloud/agent/api/GetStorageStatsAnswer.java index 26e7b7495869..79753661066e 100644 --- a/core/src/main/java/com/cloud/agent/api/GetStorageStatsAnswer.java +++ b/core/src/main/java/com/cloud/agent/api/GetStorageStatsAnswer.java @@ -27,24 +27,46 @@ public class GetStorageStatsAnswer extends Answer implements StorageStats { protected GetStorageStatsAnswer() { } - protected long used; + protected long usedBytes; - protected long capacity; + protected long capacityBytes; + + protected Long capacityIops; + + protected Long usedIops; @Override public long getByteUsed() { - return used; + return usedBytes; } @Override public long getCapacityBytes() { - return capacity; + return capacityBytes; + } + + @Override + public Long getCapacityIops() { + return capacityIops; + } + + @Override + public Long getUsedIops() { + return usedIops; + } + + public GetStorageStatsAnswer(GetStorageStatsCommand cmd, long capacityBytes, long usedBytes) { + super(cmd, true, null); + this.capacityBytes = capacityBytes; + this.usedBytes = usedBytes; } - public GetStorageStatsAnswer(GetStorageStatsCommand cmd, long capacity, long used) { + public GetStorageStatsAnswer(GetStorageStatsCommand cmd, long capacityBytes, long usedBytes, Long capacityIops, Long usedIops) { super(cmd, true, null); - this.capacity = capacity; - this.used = used; + this.capacityBytes = capacityBytes; + this.usedBytes = usedBytes; + this.capacityIops = capacityIops; + this.usedIops = usedIops; } public GetStorageStatsAnswer(GetStorageStatsCommand cmd, String details) { diff --git a/debian/control b/debian/control index c0cb95af0352..a773844c27cf 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Description: CloudStack server library Package: cloudstack-agent Architecture: all -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 +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 Recommends: init-system-helpers Conflicts: cloud-agent, cloud-agent-libs, cloud-agent-deps, cloud-agent-scripts Description: CloudStack agent diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java index 2011b1f08fbf..c8d9015af902 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java @@ -111,6 +111,14 @@ default Map getCustomStorageStats(StoragePool pool) { */ Pair getStorageStats(StoragePool storagePool); + /** + * Intended for managed storage + * returns the capacity and used IOPS or null if not supported + */ + default Pair getStorageIopsStats(StoragePool storagePool) { + return null; + } + /** * intended for managed storage * returns true if the storage can provide the volume stats (physical and virtual size) diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java index e3eb2bf514df..f94d215c954d 100644 --- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java +++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java @@ -23,12 +23,16 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.commons.collections.CollectionUtils; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeDaoImpl; import com.cloud.upgrade.SystemVmTemplateRegistration; +import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.exception.CloudRuntimeException; public class Upgrade41700to41710 extends DbUpgradeAbstractImpl implements DbUpgradeSystemVmTemplate { @@ -95,24 +99,46 @@ public void updateSystemVmTemplates(Connection conn) { } } + /* + GenericDao.customSearch using GenericSearchBuilder and GenericDao.update using + GenericDao.createSearchBuilder used here to prevent any future issues when new fields + are added to StoragePoolVO or VolumeVO and this upgrade path starts to fail. + */ private void updateStorPoolStorageType() { storageDao = new PrimaryDataStoreDaoImpl(); - List storPoolPools = storageDao.findPoolsByProvider("StorPool"); - for (StoragePoolVO storagePoolVO : storPoolPools) { - if (StoragePoolType.SharedMountPoint == storagePoolVO.getPoolType()) { - storagePoolVO.setPoolType(StoragePoolType.StorPool); - storageDao.update(storagePoolVO.getId(), storagePoolVO); - } - updateStorageTypeForStorPoolVolumes(storagePoolVO.getId()); + StoragePoolVO pool = storageDao.createForUpdate(); + pool.setPoolType(StoragePoolType.StorPool); + SearchBuilder sb = storageDao.createSearchBuilder(); + sb.and("provider", sb.entity().getStorageProviderName(), SearchCriteria.Op.EQ); + sb.and("type", sb.entity().getPoolType(), SearchCriteria.Op.EQ); + sb.done(); + SearchCriteria sc = sb.create(); + sc.setParameters("provider", StoragePoolType.StorPool.name()); + sc.setParameters("type", StoragePoolType.SharedMountPoint.name()); + storageDao.update(pool, sc); + + GenericSearchBuilder gSb = storageDao.createSearchBuilder(Long.class); + gSb.selectFields(gSb.entity().getId()); + gSb.and("provider", gSb.entity().getStorageProviderName(), SearchCriteria.Op.EQ); + gSb.done(); + SearchCriteria gSc = gSb.create(); + gSc.setParameters("provider", StoragePoolType.StorPool.name()); + List poolIds = storageDao.customSearch(gSc, null); + if (CollectionUtils.isEmpty(poolIds)) { + return; } + updateStorageTypeForStorPoolVolumes(poolIds); } - private void updateStorageTypeForStorPoolVolumes(long storagePoolId) { + private void updateStorageTypeForStorPoolVolumes(List storagePoolIds) { volumeDao = new VolumeDaoImpl(); - List volumes = volumeDao.findByPoolId(storagePoolId, null); - for (VolumeVO volumeVO : volumes) { - volumeVO.setPoolType(StoragePoolType.StorPool); - volumeDao.update(volumeVO.getId(), volumeVO); - } + VolumeVO volume = volumeDao.createForUpdate(); + volume.setPoolType(StoragePoolType.StorPool); + SearchBuilder sb = volumeDao.createSearchBuilder(); + sb.and("poolId", sb.entity().getPoolId(), SearchCriteria.Op.IN); + sb.done(); + SearchCriteria sc = sb.create(); + sc.setParameters("poolId", storagePoolIds.toArray()); + volumeDao.update(volume, sc); } } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java index 707091adb873..71e526ab0b7d 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java @@ -118,6 +118,9 @@ public class StoragePoolVO implements StoragePool { @Column(name = "capacity_iops", updatable = true, nullable = true) private Long capacityIops; + @Column(name = "used_iops", updatable = true, nullable = true) + private Long usedIops; + @Column(name = "hypervisor") @Convert(converter = HypervisorTypeConverter.class) private HypervisorType hypervisor; @@ -255,6 +258,14 @@ public Long getCapacityIops() { return capacityIops; } + public Long getUsedIops() { + return usedIops; + } + + public void setUsedIops(Long usedIops) { + this.usedIops = usedIops; + } + @Override public Long getClusterId() { return clusterId; diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql b/engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql index 570627a8da55..8498c0073802 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql @@ -29,3 +29,6 @@ CALL `cloud`.`IDEMPOTENT_DROP_FOREIGN_KEY`('cloud.mshost_peer','fk_mshost_peer__ CALL `cloud`.`IDEMPOTENT_DROP_INDEX`('i_mshost_peer__owner_peer_runid','mshost_peer'); CALL `cloud`.`IDEMPOTENT_ADD_UNIQUE_KEY`('cloud.mshost_peer', 'i_mshost_peer__owner_peer', '(owner_mshost, peer_mshost)'); CALL `cloud`.`IDEMPOTENT_ADD_FOREIGN_KEY`('cloud.mshost_peer', 'fk_mshost_peer__owner_mshost', '(owner_mshost)', '`mshost`(`id`)'); + +-- Add used_iops column to support IOPS data in storage stats +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.storage_pool', 'used_iops', 'bigint(20) unsigned DEFAULT NULL COMMENT "IOPS currently in use for this storage pool" '); diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.storage_pool_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.storage_pool_view.sql index e6cc94582088..0d1c533ec1c1 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.storage_pool_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.storage_pool_view.sql @@ -32,6 +32,7 @@ SELECT `storage_pool`.`removed` AS `removed`, `storage_pool`.`capacity_bytes` AS `capacity_bytes`, `storage_pool`.`capacity_iops` AS `capacity_iops`, + `storage_pool`.`used_iops` AS `used_iops`, `storage_pool`.`scope` AS `scope`, `storage_pool`.`hypervisor` AS `hypervisor`, `storage_pool`.`storage_provider_name` AS `storage_provider_name`, diff --git a/packaging/el8/cloud.spec b/packaging/el8/cloud.spec index f9d6fd1ce873..598e6667f3b3 100644 --- a/packaging/el8/cloud.spec +++ b/packaging/el8/cloud.spec @@ -118,6 +118,7 @@ Requires: cryptsetup Requires: rng-tools Requires: (libgcrypt > 1.8.3 or libgcrypt20) Requires: (selinux-tools if qemu-tools) +Requires: sysstat Provides: cloud-agent Group: System Environment/Libraries %description agent diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetStorageStatsCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetStorageStatsCommandWrapper.java index d00f5b540e20..419b54492583 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetStorageStatsCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetStorageStatsCommandWrapper.java @@ -40,7 +40,8 @@ public Answer execute(final GetStorageStatsCommand command, final LibvirtComputi if (sp == null) { return new GetStorageStatsAnswer(command, "no storage pool to get statistics from"); } - return new GetStorageStatsAnswer(command, sp.getCapacity(), sp.getUsed()); + return new GetStorageStatsAnswer(command, sp.getCapacity(), sp.getUsed(), sp.getCapacityIops(), + sp.getUsedIops()); } catch (final CloudRuntimeException e) { return new GetStorageStatsAnswer(command, e.toString()); } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java index 674799c0bbe3..d7791310ff79 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java @@ -62,6 +62,14 @@ public default KVMPhysicalDisk createPhysicalDisk(String volumeUuid, PhysicalDis public long getUsed(); + default Long getCapacityIops() { + return null; + } + + default Long getUsedIops() { + return null; + } + public long getAvailable(); public boolean refresh(); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index 1ce901d857f1..0222a02b1e1d 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -16,14 +16,21 @@ // under the License. package com.cloud.hypervisor.kvm.storage; +import static com.cloud.utils.NumbersUtil.toHumanReadableSize; + import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.utils.cryptsetup.KeyFile; @@ -33,9 +40,10 @@ import org.apache.cloudstack.utils.qemu.QemuImgFile; import org.apache.cloudstack.utils.qemu.QemuObject; import org.apache.commons.codec.binary.Base64; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.libvirt.Connect; import org.libvirt.LibvirtException; import org.libvirt.Secret; @@ -69,14 +77,6 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; -import static com.cloud.utils.NumbersUtil.toHumanReadableSize; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - - public class LibvirtStorageAdaptor implements StorageAdaptor { protected Logger logger = LogManager.getLogger(getClass()); private StorageLayer _storageLayer; @@ -521,6 +521,60 @@ public KVMStoragePool getStoragePool(String uuid) { return this.getStoragePool(uuid, false); } + protected void updateLocalPoolIops(LibvirtStoragePool pool) { + if (!StoragePoolType.Filesystem.equals(pool.getType()) || StringUtils.isBlank(pool.getLocalPath())) { + return; + } + if (logger.isTraceEnabled()) { + logger.trace(String.format("Updating used IOPS for pool: %s", pool.getName())); + } + + // Run script to get data + List commands = new ArrayList<>(); + commands.add(new String[]{ + Script.getExecutableAbsolutePath("bash"), + "-c", + String.format( + "%s %s | %s 'NR==2 {print $1}'", + Script.getExecutableAbsolutePath("df"), + pool.getLocalPath(), + Script.getExecutableAbsolutePath("awk") + ) + }); + String result = Script.executePipedCommands(commands, 1000).second(); + if (StringUtils.isBlank(result)) { + return; + } + result = result.trim(); + commands.add(new String[]{ + Script.getExecutableAbsolutePath("bash"), + "-c", + String.format( + "%s -z %s 1 2 | %s 'NR==7 {read=$4; write=$5; total=read+write; print total}'", + Script.getExecutableAbsolutePath("iostat"), + result, + Script.getExecutableAbsolutePath("awk") + ) + }); + result = Script.executePipedCommands(commands, 10000).second(); + if (logger.isTraceEnabled()) { + logger.trace(String.format("Pool used IOPS result: %s", result)); + } + if (StringUtils.isBlank(result)) { + return; + } + try { + double doubleValue = Double.parseDouble(result); + pool.setUsedIops((long) doubleValue); + if (logger.isDebugEnabled()) { + logger.debug(String.format("Updated used IOPS: %s for pool: %s", pool.getUsedIops(), pool.getName())); + } + } catch (NumberFormatException e) { + logger.warn(String.format("Unable to parse retrieved used IOPS: %s for pool: %s", result, + pool.getName())); + } + } + @Override public KVMStoragePool getStoragePool(String uuid, boolean refreshInfo) { logger.info("Trying to fetch storage pool " + uuid + " from libvirt"); @@ -591,6 +645,7 @@ public KVMStoragePool getStoragePool(String uuid, boolean refreshInfo) { } pool.setCapacity(storage.getInfo().capacity); pool.setUsed(storage.getInfo().allocation); + updateLocalPoolIops(pool); pool.setAvailable(storage.getInfo().available); logger.debug("Successfully refreshed pool " + uuid + diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java index 52adc59cbe7b..5bbb3b26ce27 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java @@ -44,6 +44,8 @@ public class LibvirtStoragePool implements KVMStoragePool { protected String uuid; protected long capacity; protected long used; + protected Long capacityIops; + protected Long usedIops; protected long available; protected String name; protected String localPath; @@ -82,20 +84,38 @@ public void setUsed(long used) { this.used = used; } - public void setAvailable(long available) { - this.available = available; - } - @Override public long getUsed() { return this.used; } + @Override + public Long getCapacityIops() { + return capacityIops; + } + + public void setCapacityIops(Long capacityIops) { + this.capacityIops = capacityIops; + } + + @Override + public Long getUsedIops() { + return usedIops; + } + + public void setUsedIops(Long usedIops) { + this.usedIops = usedIops; + } + @Override public long getAvailable() { return this.available; } + public void setAvailable(long available) { + this.available = available; + } + public StoragePoolType getStoragePoolType() { return this.type; } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptorTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptorTest.java index c2bbff7efb0c..7e31e879f8dd 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptorTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptorTest.java @@ -17,10 +17,16 @@ package com.cloud.hypervisor.kvm.storage; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; + import java.util.HashMap; import java.util.Map; import java.util.UUID; +import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import org.junit.After; import org.junit.Before; @@ -29,6 +35,7 @@ import org.libvirt.Connect; import org.libvirt.StoragePool; import org.libvirt.StoragePoolInfo; +import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; @@ -38,6 +45,7 @@ import com.cloud.hypervisor.kvm.resource.LibvirtConnection; import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef; import com.cloud.storage.Storage; +import com.cloud.utils.script.Script; @RunWith(MockitoJUnitRunner.class) public class LibvirtStorageAdaptorTest { @@ -46,6 +54,11 @@ public class LibvirtStorageAdaptorTest { private AutoCloseable closeable; + @Mock + LibvirtStoragePool mockPool; + + MockedStatic