Skip to content

Commit 57b0945

Browse files
committed
fix NPE in volumes statistics
If volume is migrated between storage pools and "volume.stats.interval" is set to more frequent interval for exmaple 30 sec. NullPointerException is thrown, because the hypervisor is looking for volume on storage pool from which the volume was migrated. The statistics did not work right - before this fix only one cluster is lists if we have more clusters from the same type (eg. KVM), and only one host will return volume stats. Also all volumes are sent to that host, but they could be on another host. And the logic does not work correctly. Also the response was not working correctly for QCOW2 images, because it's looking for volume's uuid, but in the statistics CS keeps the path (because of the migrated volumes which UUIDs are changed)
1 parent 0f3f2a0 commit 57b0945

File tree

3 files changed

+13
-21
lines changed

3 files changed

+13
-21
lines changed

engine/schema/src/main/java/com/cloud/dc/dao/ClusterDaoImpl.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ public ClusterDaoImpl() {
8181

8282
ZoneSearch = createSearchBuilder();
8383
ZoneSearch.and("dataCenterId", ZoneSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
84-
ZoneSearch.groupBy(ZoneSearch.entity().getHypervisorType());
8584
ZoneSearch.done();
8685

8786
AvailHyperSearch = createSearchBuilder();

server/src/main/java/com/cloud/api/query/ViewResponseHelper.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,7 @@ public static List<VolumeResponse> createVolumeResponse(ResponseView view, Volum
287287
vrDataList.put(vr.getId(), vrData);
288288

289289
VolumeStats vs = null;
290-
if (vr.getFormat() == ImageFormat.QCOW2) {
291-
vs = ApiDBUtils.getVolumeStatistics(vrData.getId());
292-
}
293-
else if (vr.getFormat() == ImageFormat.VHD){
290+
if (vr.getFormat() == ImageFormat.VHD || vr.getFormat() == ImageFormat.QCOW2){
294291
vs = ApiDBUtils.getVolumeStatistics(vrData.getPath());
295292
}
296293
else if (vr.getFormat() == ImageFormat.OVA){

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// under the License.
1717
package com.cloud.vm;
1818

19+
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
20+
1921
import java.io.IOException;
2022
import java.io.StringReader;
2123
import java.io.UnsupportedEncodingException;
@@ -29,6 +31,7 @@
2931
import java.util.List;
3032
import java.util.Map;
3133
import java.util.Map.Entry;
34+
import java.util.Objects;
3235
import java.util.Set;
3336
import java.util.UUID;
3437
import java.util.concurrent.ConcurrentHashMap;
@@ -47,8 +50,6 @@
4750
import javax.xml.parsers.DocumentBuilderFactory;
4851
import javax.xml.parsers.ParserConfigurationException;
4952

50-
import com.cloud.exception.UnsupportedServiceException;
51-
import com.cloud.hypervisor.Hypervisor;
5253
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
5354
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
5455
import org.apache.cloudstack.affinity.AffinityGroupService;
@@ -188,13 +189,15 @@
188189
import com.cloud.exception.ResourceAllocationException;
189190
import com.cloud.exception.ResourceUnavailableException;
190191
import com.cloud.exception.StorageUnavailableException;
192+
import com.cloud.exception.UnsupportedServiceException;
191193
import com.cloud.exception.VirtualMachineMigrationException;
192194
import com.cloud.gpu.GPU;
193195
import com.cloud.ha.HighAvailabilityManager;
194196
import com.cloud.host.Host;
195197
import com.cloud.host.HostVO;
196198
import com.cloud.host.Status;
197199
import com.cloud.host.dao.HostDao;
200+
import com.cloud.hypervisor.Hypervisor;
198201
import com.cloud.hypervisor.Hypervisor.HypervisorType;
199202
import com.cloud.hypervisor.HypervisorCapabilitiesVO;
200203
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
@@ -328,8 +331,6 @@
328331
import com.cloud.vm.snapshot.VMSnapshotVO;
329332
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
330333

331-
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
332-
333334
public class UserVmManagerImpl extends ManagerBase implements UserVmManager, VirtualMachineGuru, UserVmService, Configurable {
334335
private static final Logger s_logger = Logger.getLogger(UserVmManagerImpl.class);
335336

@@ -1930,18 +1931,13 @@ public HashMap<Long, VmStatsEntry> getVirtualMachineStatistics(long hostId, Stri
19301931
public HashMap<String, VolumeStatsEntry> getVolumeStatistics(long clusterId, String poolUuid, StoragePoolType poolType, List<String> volumeLocators, int timeout) {
19311932
List<HostVO> neighbors = _resourceMgr.listHostsInClusterByStatus(clusterId, Status.Up);
19321933
StoragePoolVO storagePool = _storagePoolDao.findPoolByUUID(poolUuid);
1933-
for (HostVO neighbor : neighbors) {
1934-
// apply filters:
1935-
// - managed storage
1936-
// - local storage
1937-
if (storagePool.isManaged() || storagePool.isLocal()) {
1938-
1939-
volumeLocators = getVolumesByHost(neighbor, storagePool);
1934+
HashMap<String, VolumeStatsEntry> volumeStatsByUuid = new HashMap<>();
19401935

1941-
}
1936+
for (HostVO neighbor : neighbors) {
1937+
volumeLocators = getVolumesByHost(neighbor, storagePool);
19421938

19431939
// - zone wide storage for specific hypervisortypes
1944-
if (ScopeType.ZONE.equals(storagePool.getScope()) && storagePool.getHypervisor() != neighbor.getHypervisorType()) {
1940+
if ((ScopeType.ZONE.equals(storagePool.getScope()) && storagePool.getHypervisor() != neighbor.getHypervisorType()) || (volumeLocators == null || volumeLocators.size() == 0)) {
19451941
// skip this neighbour if their hypervisor type is not the same as that of the store
19461942
continue;
19471943
}
@@ -1956,16 +1952,16 @@ public HashMap<String, VolumeStatsEntry> getVolumeStatistics(long clusterId, Str
19561952

19571953
if (answer instanceof GetVolumeStatsAnswer){
19581954
GetVolumeStatsAnswer volstats = (GetVolumeStatsAnswer)answer;
1959-
return volstats.getVolumeStats();
1955+
volumeStatsByUuid.putAll(volstats.getVolumeStats());
19601956
}
19611957
}
1962-
return null;
1958+
return volumeStatsByUuid.size() > 0 ? volumeStatsByUuid : null;
19631959
}
19641960

19651961
private List<String> getVolumesByHost(HostVO host, StoragePool pool){
19661962
List<UserVmVO> vmsPerHost = _vmDao.listByHostId(host.getId());
19671963
return vmsPerHost.stream()
1968-
.flatMap(vm -> _volsDao.findByInstanceIdAndPoolId(vm.getId(),pool.getId()).stream().map(vol -> vol.getPath()))
1964+
.flatMap(vm -> _volsDao.findByInstanceIdAndPoolId(vm.getId(),pool.getId()).stream().map(vol -> vol.getState() == Volume.State.Ready ? vol.getPath() : null).filter(Objects::nonNull))
19691965
.collect(Collectors.toList());
19701966
}
19711967

0 commit comments

Comments
 (0)