Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 09a4a25

Browse files
committed
Merge remote-tracking branch 'apache/4.18' into HEAD
2 parents 071a071 + 40cc10a commit 09a4a25

26 files changed

Lines changed: 1972 additions & 109 deletions

File tree

api/src/main/java/org/apache/cloudstack/api/command/user/vm/StartVMCmd.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ public class StartVMCmd extends BaseAsyncCmd implements UserCmd {
8686
type = CommandType.BOOLEAN,
8787
description = "True by default, CloudStack will firstly try to start the VM on the last host where it run on before stopping, if destination host is not specified. " +
8888
"If false, CloudStack will not consider the last host and start the VM by normal process.",
89-
since = "4.18.0")
89+
since = "4.18.0",
90+
authorized = {RoleType.Admin})
9091
private Boolean considerLastHost;
9192

9293
@Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "Deployment planner to use for vm allocation. Available to ROOT admin only", since = "4.4", authorized = { RoleType.Admin })

engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ static String getHypervisorHostname(String name) {
264264

265265
Pair<Long, Long> findClusterAndHostIdForVm(long vmId);
266266

267+
Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm, boolean skipCurrentHostForStartingVm);
268+
267269
/**
268270
* Obtains statistics for a list of VMs; CPU and network utilization
269271
* @param hostId ID of the host

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@
212212
import com.cloud.storage.DiskOfferingVO;
213213
import com.cloud.storage.ScopeType;
214214
import com.cloud.storage.Storage.ImageFormat;
215+
import com.cloud.storage.Storage;
215216
import com.cloud.storage.StorageManager;
216217
import com.cloud.storage.StoragePool;
217218
import com.cloud.storage.VMTemplateVO;
@@ -1054,6 +1055,26 @@ protected void checkIfTemplateNeededForCreatingVmVolumes(VMInstanceVO vm) {
10541055
}
10551056
}
10561057

1058+
protected void checkAndAttemptMigrateVmAcrossCluster(final VMInstanceVO vm, final Long destinationClusterId, final Map<Volume, StoragePool> volumePoolMap) {
1059+
if (!HypervisorType.VMware.equals(vm.getHypervisorType()) || vm.getLastHostId() == null) {
1060+
return;
1061+
}
1062+
Host lastHost = _hostDao.findById(vm.getLastHostId());
1063+
if (destinationClusterId.equals(lastHost.getClusterId())) {
1064+
return;
1065+
}
1066+
if (volumePoolMap.values().stream().noneMatch(s -> destinationClusterId.equals(s.getClusterId()))) {
1067+
return;
1068+
}
1069+
Answer[] answer = attemptHypervisorMigration(vm, volumePoolMap, lastHost.getId());
1070+
if (answer == null) {
1071+
s_logger.warn("Hypervisor inter-cluster migration during VM start failed");
1072+
return;
1073+
}
1074+
// Other network related updates will be done using caller
1075+
markVolumesInPool(vm, answer);
1076+
}
1077+
10571078
@Override
10581079
public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner)
10591080
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
@@ -1227,6 +1248,7 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
12271248
resetVmNicsDeviceId(vm.getId());
12281249
_networkMgr.prepare(vmProfile, dest, ctx);
12291250
if (vm.getHypervisorType() != HypervisorType.BareMetal) {
1251+
checkAndAttemptMigrateVmAcrossCluster(vm, cluster_id, dest.getStorageForDisks());
12301252
volumeMgr.prepare(vmProfile, dest);
12311253
}
12321254

@@ -2355,7 +2377,7 @@ private Answer[] attemptHypervisorMigration(VMInstanceVO vm, Map<Volume, Storage
23552377
try {
23562378
return _agentMgr.send(hostId, commandsContainer);
23572379
} catch (AgentUnavailableException | OperationTimedoutException e) {
2358-
throw new CloudRuntimeException(String.format("Failed to migrate VM: %s", vm.getUuid()),e);
2380+
s_logger.warn(String.format("Hypervisor migration failed for the VM: %s", vm), e);
23592381
}
23602382
}
23612383
return null;
@@ -2904,7 +2926,7 @@ protected Map<Volume, StoragePool> buildMapUsingUserInformation(VirtualMachinePr
29042926
* </ul>
29052927
*/
29062928
protected void executeManagedStorageChecksWhenTargetStoragePoolProvided(StoragePoolVO currentPool, VolumeVO volume, StoragePoolVO targetPool) {
2907-
if (!currentPool.isManaged()) {
2929+
if (!currentPool.isManaged() || currentPool.getPoolType().equals(Storage.StoragePoolType.PowerFlex)) {
29082930
return;
29092931
}
29102932
if (currentPool.getId() == targetPool.getId()) {
@@ -5712,8 +5734,12 @@ private Pair<Long, Long> findClusterAndHostIdForVmFromVolumes(long vmId) {
57125734
return new Pair<>(clusterId, hostId);
57135735
}
57145736

5715-
private Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm) {
5716-
Long hostId = vm.getHostId();
5737+
@Override
5738+
public Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm, boolean skipCurrentHostForStartingVm) {
5739+
Long hostId = null;
5740+
if (!skipCurrentHostForStartingVm || !State.Starting.equals(vm.getState())) {
5741+
hostId = vm.getHostId();
5742+
}
57175743
Long clusterId = null;
57185744
if(hostId == null) {
57195745
hostId = vm.getLastHostId();
@@ -5731,6 +5757,10 @@ private Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm) {
57315757
return new Pair<>(clusterId, hostId);
57325758
}
57335759

5760+
private Pair<Long, Long> findClusterAndHostIdForVm(VirtualMachine vm) {
5761+
return findClusterAndHostIdForVm(vm, false);
5762+
}
5763+
57345764
@Override
57355765
public Pair<Long, Long> findClusterAndHostIdForVm(long vmId) {
57365766
VMInstanceVO vm = _vmDao.findById(vmId);

engine/orchestration/src/test/java/com/cloud/vm/VirtualMachineManagerImplTest.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import java.util.HashMap;
3333
import java.util.List;
3434
import java.util.Map;
35+
import java.util.Random;
36+
import java.util.stream.Collectors;
3537

3638
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
3739
import org.apache.cloudstack.framework.config.ConfigKey;
@@ -46,6 +48,7 @@
4648
import org.mockito.Mock;
4749
import org.mockito.Mockito;
4850
import org.mockito.Spy;
51+
import org.mockito.stubbing.Answer;
4952
import org.mockito.runners.MockitoJUnitRunner;
5053

5154
import com.cloud.agent.AgentManager;
@@ -68,6 +71,7 @@
6871
import com.cloud.service.dao.ServiceOfferingDao;
6972
import com.cloud.storage.DiskOfferingVO;
7073
import com.cloud.storage.ScopeType;
74+
import com.cloud.storage.Storage;
7175
import com.cloud.storage.StorageManager;
7276
import com.cloud.storage.StoragePool;
7377
import com.cloud.storage.StoragePoolHostVO;
@@ -373,9 +377,26 @@ public void executeManagedStorageChecksWhenTargetStoragePoolProvidedTestCurrentS
373377
Mockito.verify(storagePoolVoMock, Mockito.times(0)).getId();
374378
}
375379

380+
@Test
381+
public void allowVolumeMigrationsForPowerFlexStorage() {
382+
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
383+
Mockito.doReturn(Storage.StoragePoolType.PowerFlex).when(storagePoolVoMock).getPoolType();
384+
385+
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolProvided(storagePoolVoMock, volumeVoMock, Mockito.mock(StoragePoolVO.class));
386+
387+
Mockito.verify(storagePoolVoMock).isManaged();
388+
Mockito.verify(storagePoolVoMock, Mockito.times(0)).getId();
389+
}
390+
376391
@Test
377392
public void executeManagedStorageChecksWhenTargetStoragePoolProvidedTestCurrentStoragePoolEqualsTargetPool() {
378393
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
394+
// return any storage type except powerflex/scaleio
395+
List<Storage.StoragePoolType> values = Arrays.asList(Storage.StoragePoolType.values());
396+
when(storagePoolVoMock.getPoolType()).thenAnswer((Answer<Storage.StoragePoolType>) invocation -> {
397+
List<Storage.StoragePoolType> filteredValues = values.stream().filter(v -> v != Storage.StoragePoolType.PowerFlex).collect(Collectors.toList());
398+
int randomIndex = new Random().nextInt(filteredValues.size());
399+
return filteredValues.get(randomIndex); });
379400

380401
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolProvided(storagePoolVoMock, volumeVoMock, storagePoolVoMock);
381402

@@ -386,6 +407,12 @@ public void executeManagedStorageChecksWhenTargetStoragePoolProvidedTestCurrentS
386407
@Test(expected = CloudRuntimeException.class)
387408
public void executeManagedStorageChecksWhenTargetStoragePoolProvidedTestCurrentStoragePoolNotEqualsTargetPool() {
388409
Mockito.doReturn(true).when(storagePoolVoMock).isManaged();
410+
// return any storage type except powerflex/scaleio
411+
List<Storage.StoragePoolType> values = Arrays.asList(Storage.StoragePoolType.values());
412+
when(storagePoolVoMock.getPoolType()).thenAnswer((Answer<Storage.StoragePoolType>) invocation -> {
413+
List<Storage.StoragePoolType> filteredValues = values.stream().filter(v -> v != Storage.StoragePoolType.PowerFlex).collect(Collectors.toList());
414+
int randomIndex = new Random().nextInt(filteredValues.size());
415+
return filteredValues.get(randomIndex); });
389416

390417
virtualMachineManagerImpl.executeManagedStorageChecksWhenTargetStoragePoolProvided(storagePoolVoMock, volumeVoMock, Mockito.mock(StoragePoolVO.class));
391418
}
@@ -838,4 +865,34 @@ public void checkIfTemplateNeededForCreatingVmVolumesTemplateAvailable() {
838865
Mockito.when(templateZoneDao.findByZoneTemplate(dcId, templateId)).thenReturn(Mockito.mock(VMTemplateZoneVO.class));
839866
virtualMachineManagerImpl.checkIfTemplateNeededForCreatingVmVolumes(vm);
840867
}
868+
869+
@Test
870+
public void checkAndAttemptMigrateVmAcrossClusterNonValid() {
871+
// Below scenarios shouldn't result in VM migration
872+
873+
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
874+
Mockito.when(vm.getHypervisorType()).thenReturn(HypervisorType.KVM);
875+
virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, 1L, new HashMap<>());
876+
877+
Mockito.when(vm.getHypervisorType()).thenReturn(HypervisorType.VMware);
878+
Mockito.when(vm.getLastHostId()).thenReturn(null);
879+
virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, 1L, new HashMap<>());
880+
881+
Long destinationClusterId = 10L;
882+
Mockito.when(vm.getLastHostId()).thenReturn(1L);
883+
HostVO hostVO = Mockito.mock(HostVO.class);
884+
Mockito.when(hostVO.getClusterId()).thenReturn(destinationClusterId);
885+
Mockito.when(hostDaoMock.findById(1L)).thenReturn(hostVO);
886+
virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, destinationClusterId, new HashMap<>());
887+
888+
destinationClusterId = 20L;
889+
Map<Volume, StoragePool> map = new HashMap<>();
890+
StoragePool pool1 = Mockito.mock(StoragePool.class);
891+
Mockito.when(pool1.getClusterId()).thenReturn(10L);
892+
map.put(Mockito.mock(Volume.class), pool1);
893+
StoragePool pool2 = Mockito.mock(StoragePool.class);
894+
Mockito.when(pool2.getClusterId()).thenReturn(null);
895+
map.put(Mockito.mock(Volume.class), pool2);
896+
virtualMachineManagerImpl.checkAndAttemptMigrateVmAcrossCluster(vm, destinationClusterId, map);
897+
}
841898
}

engine/storage/volume/src/main/java/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,10 @@ protected VolumeVO duplicateVolumeOnAnotherStorage(Volume volume, StoragePool po
16481648
newVol.setPoolType(pool.getPoolType());
16491649
newVol.setLastPoolId(lastPoolId);
16501650
newVol.setPodId(pool.getPodId());
1651+
if (volume.getPassphraseId() != null) {
1652+
newVol.setPassphraseId(volume.getPassphraseId());
1653+
newVol.setEncryptFormat(volume.getEncryptFormat());
1654+
}
16511655
return volDao.persist(newVol);
16521656
}
16531657

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtConnection.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.apache.log4j.Logger;
2323
import org.libvirt.Connect;
24+
import org.libvirt.Library;
2425
import org.libvirt.LibvirtException;
2526

2627
import com.cloud.hypervisor.Hypervisor;
@@ -44,6 +45,7 @@ static public Connect getConnection(String hypervisorURI) throws LibvirtExceptio
4445
if (conn == null) {
4546
s_logger.info("No existing libvirtd connection found. Opening a new one");
4647
conn = new Connect(hypervisorURI, false);
48+
Library.initEventLoop();
4749
s_logger.debug("Successfully connected to libvirt at: " + hypervisorURI);
4850
s_connections.put(hypervisorURI, conn);
4951
} else {

0 commit comments

Comments
 (0)