Skip to content

Commit 2811252

Browse files
committed
Leave system VM and router volumes out of all-volumes resource alert rules
1 parent 91bb2c5 commit 2811252

5 files changed

Lines changed: 67 additions & 17 deletions

File tree

‎engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.S
3434

3535
List<VolumeVO> findByAccount(long accountId);
3636

37-
List<Long> listIdsByAccountOrDomainsAndState(Long accountId, List<Long> domainIds, Volume.State state);
37+
/**
38+
* Lists IDs of volumes that are detached or attached to user VMs, leaving out system VM and router volumes.
39+
*/
40+
List<Long> listUserVolumeIdsByAccountOrDomainsAndState(Long accountId, List<Long> domainIds, Volume.State state);
3841

3942
List<VolumeVO> findIncludingRemovedByAccount(long accountId);
4043

‎engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java‎

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
7575
private final SearchBuilder<VolumeVO> storeAndInstallPathSearch;
7676
private final SearchBuilder<VolumeVO> volumeIdSearch;
7777
protected GenericSearchBuilder<VolumeVO, Long> CountByAccount;
78-
protected final GenericSearchBuilder<VolumeVO, Long> IdsByAccountOrDomainsAndStateSearch;
7978
protected final SearchBuilder<VolumeVO> ExternalUuidSearch;
8079
protected GenericSearchBuilder<VolumeVO, SumCount> primaryStorageSearch;
8180
protected GenericSearchBuilder<VolumeVO, SumCount> primaryStorageSearch2;
@@ -100,6 +99,9 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
10099

101100
private static final String ORDER_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT_PART1 = "SELECT pool.id, SUM(IF(vol.state='Ready' AND vol.account_id = ?, 1, 0)) FROM `cloud`.`storage_pool` pool LEFT JOIN `cloud`.`volumes` vol ON pool.id = vol.pool_id WHERE pool.data_center_id = ? ";
102101
private static final String ORDER_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT_PART2 = " GROUP BY pool.id ORDER BY 2 ASC ";
102+
private static final String LIST_USER_VOLUME_IDS = "SELECT vol.id FROM `cloud`.`volumes` vol "
103+
+ "LEFT JOIN `cloud`.`vm_instance` vm ON vm.id = vol.instance_id "
104+
+ "WHERE vol.removed IS NULL AND (vol.instance_id IS NULL OR vm.type = 'User')";
103105

104106
private static final String ORDER_ZONE_WIDE_POOLS_NUMBER_OF_VOLUMES_FOR_ACCOUNT = "SELECT pool.id, SUM(IF(vol.state='Ready' AND vol.account_id = ?, 1, 0)) FROM `cloud`.`storage_pool` pool LEFT JOIN `cloud`.`volumes` vol ON pool.id = vol.pool_id WHERE pool.data_center_id = ? "
105107
+ " AND pool.scope = 'ZONE' AND pool.status='Up' " + " GROUP BY pool.id ORDER BY 2 ASC ";
@@ -120,18 +122,44 @@ public List<VolumeVO> findByAccount(long accountId) {
120122
}
121123

122124
@Override
123-
public List<Long> listIdsByAccountOrDomainsAndState(Long accountId, List<Long> domainIds, Volume.State state) {
124-
SearchCriteria<Long> sc = IdsByAccountOrDomainsAndStateSearch.create();
125+
public List<Long> listUserVolumeIdsByAccountOrDomainsAndState(Long accountId, List<Long> domainIds, Volume.State state) {
126+
if (domainIds != null && domainIds.isEmpty()) {
127+
return new ArrayList<>();
128+
}
129+
StringBuilder sql = new StringBuilder(LIST_USER_VOLUME_IDS);
125130
if (accountId != null) {
126-
sc.setParameters("accountId", accountId);
131+
sql.append(" AND vol.account_id = ?");
127132
}
128133
if (domainIds != null) {
129-
sc.setParameters("domainIds", domainIds.toArray());
134+
sql.append(" AND vol.domain_id IN (").append(String.join(",", Collections.nCopies(domainIds.size(), "?"))).append(")");
130135
}
131136
if (state != null) {
132-
sc.setParameters("state", state);
137+
sql.append(" AND vol.state = ?");
133138
}
134-
return customSearch(sc, null);
139+
List<Long> ids = new ArrayList<>();
140+
TransactionLegacy txn = TransactionLegacy.currentTxn();
141+
try (PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql.toString())) {
142+
int i = 1;
143+
if (accountId != null) {
144+
pstmt.setLong(i++, accountId);
145+
}
146+
if (domainIds != null) {
147+
for (Long domainId : domainIds) {
148+
pstmt.setLong(i++, domainId);
149+
}
150+
}
151+
if (state != null) {
152+
pstmt.setString(i, state.name());
153+
}
154+
try (ResultSet rs = pstmt.executeQuery()) {
155+
while (rs.next()) {
156+
ids.add(rs.getLong(1));
157+
}
158+
}
159+
} catch (SQLException e) {
160+
throw new CloudRuntimeException("Unable to list user volume IDs", e);
161+
}
162+
return ids;
135163
}
136164

137165
@Override
@@ -436,13 +464,6 @@ public VolumeDaoImpl() {
436464
AllFieldsSearch.and("kmsWrappedKeyId", AllFieldsSearch.entity().getKmsWrappedKeyId(), Op.EQ);
437465
AllFieldsSearch.done();
438466

439-
IdsByAccountOrDomainsAndStateSearch = createSearchBuilder(Long.class);
440-
IdsByAccountOrDomainsAndStateSearch.selectFields(IdsByAccountOrDomainsAndStateSearch.entity().getId());
441-
IdsByAccountOrDomainsAndStateSearch.and("accountId", IdsByAccountOrDomainsAndStateSearch.entity().getAccountId(), Op.EQ);
442-
IdsByAccountOrDomainsAndStateSearch.and("domainIds", IdsByAccountOrDomainsAndStateSearch.entity().getDomainId(), Op.IN);
443-
IdsByAccountOrDomainsAndStateSearch.and("state", IdsByAccountOrDomainsAndStateSearch.entity().getState(), Op.EQ);
444-
IdsByAccountOrDomainsAndStateSearch.done();
445-
446467
RootDiskStateSearch = createSearchBuilder();
447468
RootDiskStateSearch.and("state", RootDiskStateSearch.entity().getState(), Op.IN);
448469
RootDiskStateSearch.and("vType", RootDiskStateSearch.entity().getVolumeType(), Op.EQ);

‎engine/schema/src/test/java/com/cloud/storage/dao/VolumeDaoImplTest.java‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,32 @@ public void testListPoolIdsByVolumeCount_without_cluster_details() throws SQLExc
114114
verify(preparedStatementMock, times(1)).executeQuery();
115115
}
116116

117+
@Test
118+
public void listUserVolumeIdsByAccountOrDomainsAndStateSkipsSystemVmVolumes() throws SQLException {
119+
final String expectedSql = "SELECT vol.id FROM `cloud`.`volumes` vol "
120+
+ "LEFT JOIN `cloud`.`vm_instance` vm ON vm.id = vol.instance_id "
121+
+ "WHERE vol.removed IS NULL AND (vol.instance_id IS NULL OR vm.type = 'User')"
122+
+ " AND vol.domain_id IN (?,?) AND vol.state = ?";
123+
when(TransactionLegacy.currentTxn()).thenReturn(transactionMock);
124+
when(transactionMock.prepareAutoCloseStatement(expectedSql)).thenReturn(preparedStatementMock);
125+
ResultSet rs = Mockito.mock(ResultSet.class);
126+
when(rs.next()).thenReturn(true, false);
127+
when(rs.getLong(1)).thenReturn(7L);
128+
when(preparedStatementMock.executeQuery()).thenReturn(rs);
129+
130+
List<Long> ids = volumeDao.listUserVolumeIdsByAccountOrDomainsAndState(null, List.of(1L, 2L), Volume.State.Ready);
131+
132+
Assert.assertEquals(List.of(7L), ids);
133+
verify(preparedStatementMock).setLong(1, 1L);
134+
verify(preparedStatementMock).setLong(2, 2L);
135+
verify(preparedStatementMock).setString(3, "Ready");
136+
}
137+
138+
@Test
139+
public void listUserVolumeIdsByAccountOrDomainsAndStateWithNoDomains() {
140+
Assert.assertTrue(volumeDao.listUserVolumeIdsByAccountOrDomainsAndState(null, List.of(), Volume.State.Ready).isEmpty());
141+
}
142+
117143
@Test
118144
public void findByInstanceAndNotState_queriesWithInstanceIdAndExcludedStates() {
119145
SearchBuilder<VolumeVO> sb = Mockito.mock(SearchBuilder.class);

‎plugins/resource-alerts/src/main/java/org/apache/cloudstack/resourcealert/ResourceAlertManagerImpl.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ private List<Long> getResourceIds(ResourceAlertRuleVO rule) {
396396
}
397397
case Volume: {
398398
Pair<Long, List<Long>> scope = getGenericRuleScope(rule);
399-
return scope == null ? Collections.emptyList() : volumeDao.listIdsByAccountOrDomainsAndState(
399+
return scope == null ? Collections.emptyList() : volumeDao.listUserVolumeIdsByAccountOrDomainsAndState(
400400
scope.first(), scope.second(), Volume.State.Ready);
401401
}
402402
case Host:

‎plugins/resource-alerts/src/test/java/org/apache/cloudstack/resourcealert/ResourceAlertManagerImplTest.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,7 @@ public void testGenericVolumeRuleForRootAdminListsReadyVolumesCloudWide() {
875875

876876
manager.evaluateRules();
877877

878-
verify(volumeDao).listIdsByAccountOrDomainsAndState(null, null, Volume.State.Ready);
878+
verify(volumeDao).listUserVolumeIdsByAccountOrDomainsAndState(null, null, Volume.State.Ready);
879879
}
880880

881881
@Test

0 commit comments

Comments
 (0)