Skip to content

Commit 59fba49

Browse files
GutoVeroneziDaniel Augusto Veronezi Salvador
andauthored
Fix npe when migrating vm with volume (#4698)
Co-authored-by: Daniel Augusto Veronezi Salvador <daniel@scclouds.com.br>
1 parent a1be9b0 commit 59fba49

3 files changed

Lines changed: 46 additions & 3 deletions

File tree

engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,10 @@ protected void copyTemplateToTargetFilesystemStorageIfNeeded(VolumeInfo srcVolum
217217
if (copyCommandAnswer != null && copyCommandAnswer.getResult()) {
218218
updateTemplateReferenceIfSuccessfulCopy(srcVolumeInfo, srcStoragePool, destTemplateInfo, destDataStore);
219219
}
220+
return;
220221
}
221222
}
223+
LOGGER.debug(String.format("Skipping 'copy template to target filesystem storage before migration' due to the template [%s] already exist on the storage pool [%s].", srcVolumeInfo.getTemplateId(), destStoragePool.getId()));
222224
}
223225

224226
/**

engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
import com.cloud.vm.VirtualMachineManager;
135135
import com.cloud.vm.dao.VMInstanceDao;
136136
import com.google.common.base.Preconditions;
137+
import java.util.stream.Collectors;
137138

138139
public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
139140
private static final Logger LOGGER = Logger.getLogger(StorageSystemDataMotionStrategy.class);
@@ -1816,7 +1817,12 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
18161817
continue;
18171818
}
18181819

1819-
copyTemplateToTargetFilesystemStorageIfNeeded(srcVolumeInfo, sourceStoragePool, destDataStore, destStoragePool, destHost);
1820+
if (srcVolumeInfo.getTemplateId() != null) {
1821+
LOGGER.debug(String.format("Copying template [%s] of volume [%s] from source storage pool [%s] to target storage pool [%s].", srcVolumeInfo.getTemplateId(), srcVolumeInfo.getId(), sourceStoragePool.getId(), destStoragePool.getId()));
1822+
copyTemplateToTargetFilesystemStorageIfNeeded(srcVolumeInfo, sourceStoragePool, destDataStore, destStoragePool, destHost);
1823+
} else {
1824+
LOGGER.debug(String.format("Skipping copy template from source storage pool [%s] to target storage pool [%s] before migration due to volume [%s] does not have a template.", sourceStoragePool.getId(), destStoragePool.getId(), srcVolumeInfo.getId()));
1825+
}
18201826

18211827
VolumeVO destVolume = duplicateVolumeOnAnotherStorage(srcVolume, destStoragePool);
18221828
VolumeInfo destVolumeInfo = _volumeDataFactory.getVolume(destVolume.getId(), destDataStore);
@@ -1920,9 +1926,12 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
19201926

19211927
throw new CloudRuntimeException(errMsg);
19221928
}
1923-
} catch (Exception ex) {
1924-
errMsg = "Copy operation failed in 'StorageSystemDataMotionStrategy.copyAsync': " + ex.getMessage();
1929+
} catch (AgentUnavailableException | OperationTimedoutException | CloudRuntimeException ex) {
1930+
String volumesAndStorages = volumeDataStoreMap.entrySet().stream().map(entry -> formatEntryOfVolumesAndStoragesAsJsonToDisplayOnLog(entry)).collect(Collectors.joining(","));
1931+
1932+
errMsg = String.format("Copy volume(s) to storage(s) [%s] and VM to host [%s] failed in StorageSystemDataMotionStrategy.copyAsync. Error message: [%s].", volumesAndStorages, formatMigrationElementsAsJsonToDisplayOnLog("vm", vmTO.getId(), srcHost.getId(), destHost.getId()), ex.getMessage());
19251933
LOGGER.error(errMsg, ex);
1934+
19261935
throw new CloudRuntimeException(errMsg);
19271936
} finally {
19281937
CopyCmdAnswer copyCmdAnswer = new CopyCmdAnswer(errMsg);
@@ -1935,6 +1944,16 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
19351944
}
19361945
}
19371946

1947+
protected String formatMigrationElementsAsJsonToDisplayOnLog(String objectName, Object object, Object from, Object to){
1948+
return String.format("{%s: \"%s\", from: \"%s\", to:\"%s\"}", objectName, object, from, to);
1949+
}
1950+
1951+
protected String formatEntryOfVolumesAndStoragesAsJsonToDisplayOnLog(Map.Entry<VolumeInfo, DataStore> entry ){
1952+
VolumeInfo srcVolumeInfo = entry.getKey();
1953+
DataStore destDataStore = entry.getValue();
1954+
return formatMigrationElementsAsJsonToDisplayOnLog("volume", srcVolumeInfo.getId(), srcVolumeInfo.getPoolId(), destDataStore.getId());
1955+
}
1956+
19381957
/**
19391958
* Returns true if at least one of the entries on the map 'volumeDataStoreMap' has both source and destination storage pools of Network Filesystem (NFS).
19401959
*/

engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategyTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import com.cloud.storage.Storage.StoragePoolType;
5656
import com.cloud.storage.Volume;
5757
import com.cloud.storage.VolumeVO;
58+
import java.util.AbstractMap;
5859

5960
@RunWith(MockitoJUnitRunner.class)
6061
public class StorageSystemDataMotionStrategyTest {
@@ -266,4 +267,25 @@ private void configureAndVerifyIsSourceAndDestinationPoolTypeOfNfs(StoragePoolTy
266267
Assert.assertEquals(expected, result);
267268
}
268269

270+
@Test
271+
public void formatMigrationElementsAsJsonToDisplayOnLogValidateFormat(){
272+
String objectName = "test";
273+
Long object = 1L, from = 2L, to = 3L;
274+
275+
Assert.assertEquals(String.format("{%s: \"%s\", from: \"%s\", to:\"%s\"}", objectName, object, from, to), strategy.formatMigrationElementsAsJsonToDisplayOnLog(objectName,
276+
object, from, to));
277+
}
278+
279+
@Test
280+
public void formatEntryOfVolumesAndStoragesAsJsonToDisplayOnLogValidateFormat(){
281+
Long volume = 1L, from = 2L, to = 3L;
282+
VolumeInfo volumeInfo = Mockito.mock(VolumeInfo.class);
283+
DataStore dataStore = Mockito.mock(DataStore.class);
284+
285+
Mockito.when(volumeInfo.getId()).thenReturn(volume);
286+
Mockito.when(volumeInfo.getPoolId()).thenReturn(from);
287+
Mockito.when(dataStore.getId()).thenReturn(to);
288+
289+
Assert.assertEquals(String.format("{volume: \"%s\", from: \"%s\", to:\"%s\"}", volume, from, to), strategy.formatEntryOfVolumesAndStoragesAsJsonToDisplayOnLog(new AbstractMap.SimpleEntry<>(volumeInfo, dataStore)));
290+
}
269291
}

0 commit comments

Comments
 (0)