Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/src/main/java/com/cloud/storage/StorageStats.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ public interface StorageStats {
* @return bytes capacity of the storage server
*/
public long getCapacityBytes();

Long getCapacityIops();
Long getUsedIops();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
@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<String, String> customStats;
Expand Down Expand Up @@ -312,6 +316,14 @@
this.allocatedIops = allocatedIops;
}

public Long getUsedIops() {
return usedIops;
}

Check warning on line 321 in api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java#L319-L321

Added lines #L319 - L321 were not covered by tests

public void setUsedIops(Long usedIops) {
this.usedIops = usedIops;
}

Check warning on line 325 in api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java

View check run for this annotation

Codecov / codecov/patch

api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java#L323-L325

Added lines #L323 - L325 were not covered by tests

public Map<String, String> getCustomStats() {
return customStats;
}
Expand Down
36 changes: 29 additions & 7 deletions core/src/main/java/com/cloud/agent/api/GetStorageStatsAnswer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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 org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class GetStorageStatsAnswerTest {

@Test
public void testDefaultConstructor() {
GetStorageStatsAnswer answer = new GetStorageStatsAnswer();

Assert.assertEquals(0, answer.getByteUsed());
Assert.assertEquals(0, answer.getCapacityBytes());
Assert.assertNull(answer.getCapacityIops());
Assert.assertNull(answer.getUsedIops());
}

@Test
public void testConstructorWithCapacityAndUsedBytes() {
GetStorageStatsCommand mockCmd = new GetStorageStatsCommand();
long capacityBytes = 1024L;
long usedBytes = 512L;

GetStorageStatsAnswer answer = new GetStorageStatsAnswer(mockCmd, capacityBytes, usedBytes);

Assert.assertEquals(capacityBytes, answer.getCapacityBytes());
Assert.assertEquals(usedBytes, answer.getByteUsed());
Assert.assertNull(answer.getCapacityIops());
Assert.assertNull(answer.getUsedIops());
}

@Test
public void testConstructorWithIops() {
GetStorageStatsCommand mockCmd = new GetStorageStatsCommand();
long capacityBytes = 2048L;
long usedBytes = 1024L;
Long capacityIops = 1000L;
Long usedIops = 500L;

GetStorageStatsAnswer answer = new GetStorageStatsAnswer(mockCmd, capacityBytes, usedBytes, capacityIops, usedIops);

Assert.assertEquals(capacityBytes, answer.getCapacityBytes());
Assert.assertEquals(usedBytes, answer.getByteUsed());
Assert.assertEquals(capacityIops, answer.getCapacityIops());
Assert.assertEquals(usedIops, answer.getUsedIops());
}

@Test
public void testErrorConstructor() {
GetStorageStatsCommand mockCmd = new GetStorageStatsCommand();
String errorDetails = "An error occurred";

GetStorageStatsAnswer answer = new GetStorageStatsAnswer(mockCmd, errorDetails);

Assert.assertFalse(answer.getResult());
Assert.assertEquals(errorDetails, answer.getDetails());
Assert.assertEquals(0, answer.getCapacityBytes());
Assert.assertEquals(0, answer.getByteUsed());
Assert.assertNull(answer.getCapacityIops());
Assert.assertNull(answer.getUsedIops());
}
}
2 changes: 1 addition & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@
*/
Pair<Long, Long> getStorageStats(StoragePool storagePool);

/**
* Intended for managed storage
* returns the capacity and used IOPS or null if not supported
*/
default Pair<Long, Long> getStorageIopsStats(StoragePool storagePool) {
return null;
}

Check warning on line 120 in engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java

View check run for this annotation

Codecov / codecov/patch

engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreDriver.java#L118-L120

Added lines #L118 - L120 were not covered by tests

/**
* intended for managed storage
* returns true if the storage can provide the volume stats (physical and virtual size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -95,24 +99,58 @@ public void updateSystemVmTemplates(Connection conn) {
}
}

private void updateStorPoolStorageType() {
storageDao = new PrimaryDataStoreDaoImpl();
List<StoragePoolVO> 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());
protected PrimaryDataStoreDao getStorageDao() {
if (storageDao == null) {
storageDao = new PrimaryDataStoreDaoImpl();
}
return storageDao;
}

private void updateStorageTypeForStorPoolVolumes(long storagePoolId) {
volumeDao = new VolumeDaoImpl();
List<VolumeVO> volumes = volumeDao.findByPoolId(storagePoolId, null);
for (VolumeVO volumeVO : volumes) {
volumeVO.setPoolType(StoragePoolType.StorPool);
volumeDao.update(volumeVO.getId(), volumeVO);
protected VolumeDao getVolumeDao() {
if (volumeDao == null) {
volumeDao = new VolumeDaoImpl();
}
return volumeDao;
}

/*
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.
*/
protected void updateStorPoolStorageType() {
StoragePoolVO pool = getStorageDao().createForUpdate();
pool.setPoolType(StoragePoolType.StorPool);
SearchBuilder<StoragePoolVO> sb = getStorageDao().createSearchBuilder();
sb.and("provider", sb.entity().getStorageProviderName(), SearchCriteria.Op.EQ);
sb.and("type", sb.entity().getPoolType(), SearchCriteria.Op.EQ);
sb.done();
SearchCriteria<StoragePoolVO> sc = sb.create();
sc.setParameters("provider", StoragePoolType.StorPool.name());
sc.setParameters("type", StoragePoolType.SharedMountPoint.name());
getStorageDao().update(pool, sc);

GenericSearchBuilder<StoragePoolVO, Long> gSb = getStorageDao().createSearchBuilder(Long.class);
gSb.selectFields(gSb.entity().getId());
gSb.and("provider", gSb.entity().getStorageProviderName(), SearchCriteria.Op.EQ);
gSb.done();
SearchCriteria<Long> gSc = gSb.create();
gSc.setParameters("provider", StoragePoolType.StorPool.name());
List<Long> poolIds = getStorageDao().customSearch(gSc, null);
updateStorageTypeForStorPoolVolumes(poolIds);
}

protected void updateStorageTypeForStorPoolVolumes(List<Long> storagePoolIds) {
if (CollectionUtils.isEmpty(storagePoolIds)) {
return;
}
VolumeVO volume = getVolumeDao().createForUpdate();
volume.setPoolType(StoragePoolType.StorPool);
SearchBuilder<VolumeVO> sb = getVolumeDao().createSearchBuilder();
sb.and("poolId", sb.entity().getPoolId(), SearchCriteria.Op.IN);
sb.done();
SearchCriteria<VolumeVO> sc = sb.create();
sc.setParameters("poolId", storagePoolIds.toArray());
getVolumeDao().update(volume, sc);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@
@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;
Expand Down Expand Up @@ -255,6 +258,14 @@
return capacityIops;
}

public Long getUsedIops() {
return usedIops;
}

Check warning on line 263 in engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java

View check run for this annotation

Codecov / codecov/patch

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java#L261-L263

Added lines #L261 - L263 were not covered by tests

public void setUsedIops(Long usedIops) {
this.usedIops = usedIops;
}

Check warning on line 267 in engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java

View check run for this annotation

Codecov / codecov/patch

engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java#L265-L267

Added lines #L265 - L267 were not covered by tests

@Override
public Long getClusterId() {
return clusterId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ CALL `cloud`.`IDEMPOTENT_ADD_FOREIGN_KEY`('cloud.mshost_peer', 'fk_mshost_peer__

-- Add last_id to the volumes table
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.volumes', 'last_id', 'bigint(20) unsigned DEFAULT NULL');

-- Add used_iops column to support IOPS data in storage stats
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.storage_pool', 'used_iops', 'bigint unsigned DEFAULT NULL COMMENT "IOPS currently in use for this storage pool" ');
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ SELECT
`storage_pool`.`created` AS `created`,
`storage_pool`.`removed` AS `removed`,
`storage_pool`.`capacity_bytes` AS `capacity_bytes`,
`storage_pool`.`used_bytes` AS `used_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`,
Expand Down
Loading
Loading