Skip to content

Commit cb91a76

Browse files
Fix npe when migrating vm with volume (#4698) (#4775)
Cherry-pick commit 59fba49 and fix conflict. Co-authored-by: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com>
1 parent 6048afb commit cb91a76

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed

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
@@ -212,8 +212,10 @@ protected void copyTemplateToTargetFilesystemStorageIfNeeded(VolumeInfo srcVolum
212212
if (copyCommandAnswer != null && copyCommandAnswer.getResult()) {
213213
updateTemplateReferenceIfSuccessfulCopy(srcVolumeInfo, srcStoragePool, destTemplateInfo, destDataStore);
214214
}
215+
return;
215216
}
216217
}
218+
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()));
217219
}
218220

219221
/**

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

Lines changed: 22 additions & 4 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);
@@ -1790,7 +1791,12 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
17901791
continue;
17911792
}
17921793

1793-
copyTemplateToTargetFilesystemStorageIfNeeded(srcVolumeInfo, sourceStoragePool, destDataStore, destStoragePool, destHost);
1794+
if (srcVolumeInfo.getTemplateId() != null) {
1795+
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()));
1796+
copyTemplateToTargetFilesystemStorageIfNeeded(srcVolumeInfo, sourceStoragePool, destDataStore, destStoragePool, destHost);
1797+
} else {
1798+
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()));
1799+
}
17941800

17951801
VolumeVO destVolume = duplicateVolumeOnAnotherStorage(srcVolume, destStoragePool);
17961802
VolumeInfo destVolumeInfo = _volumeDataFactory.getVolume(destVolume.getId(), destDataStore);
@@ -1894,9 +1900,11 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
18941900

18951901
throw new CloudRuntimeException(errMsg);
18961902
}
1897-
}
1898-
catch (Exception ex) {
1899-
errMsg = "Copy operation failed in 'StorageSystemDataMotionStrategy.copyAsync': " + ex.getMessage();
1903+
} catch (AgentUnavailableException | OperationTimedoutException | CloudRuntimeException ex) {
1904+
String volumesAndStorages = volumeDataStoreMap.entrySet().stream().map(entry -> formatEntryOfVolumesAndStoragesAsJsonToDisplayOnLog(entry)).collect(Collectors.joining(","));
1905+
1906+
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());
1907+
LOGGER.error(errMsg, ex);
19001908

19011909
throw new CloudRuntimeException(errMsg);
19021910
}
@@ -1911,6 +1919,16 @@ public void copyAsync(Map<VolumeInfo, DataStore> volumeDataStoreMap, VirtualMach
19111919
}
19121920
}
19131921

1922+
protected String formatMigrationElementsAsJsonToDisplayOnLog(String objectName, Object object, Object from, Object to){
1923+
return String.format("{%s: \"%s\", from: \"%s\", to:\"%s\"}", objectName, object, from, to);
1924+
}
1925+
1926+
protected String formatEntryOfVolumesAndStoragesAsJsonToDisplayOnLog(Map.Entry<VolumeInfo, DataStore> entry ){
1927+
VolumeInfo srcVolumeInfo = entry.getKey();
1928+
DataStore destDataStore = entry.getValue();
1929+
return formatMigrationElementsAsJsonToDisplayOnLog("volume", srcVolumeInfo.getId(), srcVolumeInfo.getPoolId(), destDataStore.getId());
1930+
}
1931+
19141932
/**
19151933
* Returns true if at least one of the entries on the map 'volumeDataStoreMap' has both source and destination storage pools of Network Filesystem (NFS).
19161934
*/

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)