This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch 4.19
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.19 by this push:
new 1a1131154ef Fixup vm powerstate update (#8545)
1a1131154ef is described below
commit 1a1131154ef27e0f5491ceb249eded7fd810c021
Author: Vishesh <[email protected]>
AuthorDate: Mon Feb 19 18:26:21 2024 +0530
Fixup vm powerstate update (#8545)
Co-authored-by: Suresh Kumar Anaparti <[email protected]>
---
.../com/cloud/vm/VirtualMachineManagerImpl.java | 7 +-
.../java/com/cloud/vm/dao/VMInstanceDaoImpl.java | 23 +++-
.../com/cloud/vm/dao/VMInstanceDaoImplTest.java | 152 +++++++++++++++++++--
3 files changed, 161 insertions(+), 21 deletions(-)
diff --git
a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
index 29c60698398..59d129bc065 100755
---
a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++
b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -213,8 +213,8 @@ import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.ScopeType;
-import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage;
+import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateVO;
@@ -2208,9 +2208,11 @@ public class VirtualMachineManagerImpl extends
ManagerBase implements VirtualMac
boolean result = stateTransitTo(vm, Event.OperationSucceeded,
null);
if (result) {
+ vm.setPowerState(PowerState.PowerOff);
+ _vmDao.update(vm.getId(), vm);
if (VirtualMachine.Type.User.equals(vm.type) &&
ResourceCountRunningVMsonly.value()) {
ServiceOfferingVO offering =
_offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
- resourceCountDecrement(vm.getAccountId(),new
Long(offering.getCpu()), new Long(offering.getRamSize()));
+ resourceCountDecrement(vm.getAccountId(),
offering.getCpu().longValue(), offering.getRamSize().longValue());
}
} else {
throw new CloudRuntimeException("unable to stop " + vm);
@@ -2761,6 +2763,7 @@ public class VirtualMachineManagerImpl extends
ManagerBase implements VirtualMac
}
vm.setLastHostId(srcHostId);
+ _vmDao.resetVmPowerStateTracking(vm.getId());
try {
if (vm.getHostId() == null || vm.getHostId() != srcHostId ||
!changeState(vm, Event.MigrationRequested, dstHostId, work, Step.Migrating)) {
_networkMgr.rollbackNicForMigration(vmSrc, profile);
diff --git
a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
index 916687baeb4..322895f0ec5 100755
--- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
@@ -66,7 +66,7 @@ import com.cloud.vm.VirtualMachine.Type;
public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long>
implements VMInstanceDao {
public static final Logger s_logger =
Logger.getLogger(VMInstanceDaoImpl.class);
- private static final int MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT = 3;
+ static final int MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT = 3;
protected SearchBuilder<VMInstanceVO> VMClusterSearch;
protected SearchBuilder<VMInstanceVO> LHVMClusterSearch;
@@ -897,17 +897,19 @@ public class VMInstanceDaoImpl extends
GenericDaoBase<VMInstanceVO, Long> implem
@Override
public boolean updatePowerState(final long instanceId, final long
powerHostId, final VirtualMachine.PowerState powerState, Date wisdomEra) {
- return Transaction.execute(new TransactionCallback<Boolean>() {
+ return Transaction.execute(new TransactionCallback<>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
boolean needToUpdate = false;
VMInstanceVO instance = findById(instanceId);
if (instance != null
- && (null == instance.getPowerStateUpdateTime()
+ && (null == instance.getPowerStateUpdateTime()
||
instance.getPowerStateUpdateTime().before(wisdomEra))) {
Long savedPowerHostId = instance.getPowerHostId();
- if (instance.getPowerState() != powerState ||
savedPowerHostId == null
- || savedPowerHostId.longValue() != powerHostId) {
+ if (instance.getPowerState() != powerState
+ || savedPowerHostId == null
+ || savedPowerHostId != powerHostId
+ ||
!isPowerStateInSyncWithInstanceState(powerState, powerHostId, instance)) {
instance.setPowerState(powerState);
instance.setPowerHostId(powerHostId);
instance.setPowerStateUpdateCount(1);
@@ -929,6 +931,17 @@ public class VMInstanceDaoImpl extends
GenericDaoBase<VMInstanceVO, Long> implem
});
}
+ private boolean isPowerStateInSyncWithInstanceState(final
VirtualMachine.PowerState powerState, final long powerHostId, final
VMInstanceVO instance) {
+ State instanceState = instance.getState();
+ if ((powerState == VirtualMachine.PowerState.PowerOff && instanceState
== State.Running)
+ || (powerState == VirtualMachine.PowerState.PowerOn &&
instanceState == State.Stopped)) {
+ s_logger.debug(String.format("VM id: %d on host id: %d and power
host id: %d is in %s state, but power state is %s",
+ instance.getId(), instance.getHostId(), powerHostId,
instanceState, powerState));
+ return false;
+ }
+ return true;
+ }
+
@Override
public boolean isPowerStateUpToDate(final long instanceId) {
VMInstanceVO instance = findById(instanceId);
diff --git
a/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDaoImplTest.java
b/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDaoImplTest.java
index 767b41420b7..9dc773cd7d6 100644
--- a/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDaoImplTest.java
+++ b/engine/schema/src/test/java/com/cloud/vm/dao/VMInstanceDaoImplTest.java
@@ -17,22 +17,32 @@
package com.cloud.vm.dao;
-import com.cloud.utils.Pair;
-import com.cloud.vm.VirtualMachine;
+import static com.cloud.vm.VirtualMachine.State.Running;
+import static com.cloud.vm.VirtualMachine.State.Stopped;
+import static
com.cloud.vm.dao.VMInstanceDaoImpl.MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
-import org.junit.Assert;
import org.mockito.Mock;
-
-import static com.cloud.vm.VirtualMachine.State.Running;
-import static com.cloud.vm.VirtualMachine.State.Stopped;
-
-import static org.mockito.Mockito.when;
-import com.cloud.vm.VMInstanceVO;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import com.cloud.utils.Pair;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+
/**
* Created by sudharma_jain on 3/2/17.
*/
@@ -55,16 +65,130 @@ public class VMInstanceDaoImplTest {
}
@Test
- public void testUpdateState() throws Exception {
+ public void testUpdateState() {
Long destHostId = null;
- Pair<Long, Long> opaqueMock = new Pair<Long, Long>(new Long(1),
destHostId);
+ Pair<Long, Long> opaqueMock = new Pair<>(1L, destHostId);
vmInstanceDao.updateState(Stopped,
VirtualMachine.Event.FollowAgentPowerOffReport, Stopped, vm , opaqueMock);
}
@Test
- public void testIfStateAndHostUnchanged() throws Exception {
- Assert.assertEquals(vmInstanceDao.ifStateUnchanged(Stopped, Stopped,
null, null), true);
- Assert.assertEquals(vmInstanceDao.ifStateUnchanged(Stopped, Running,
null, null), false);
+ public void testIfStateAndHostUnchanged() {
+ assertTrue(vmInstanceDao.ifStateUnchanged(Stopped, Stopped, null,
null));
+ assertFalse(vmInstanceDao.ifStateUnchanged(Stopped, Running, null,
null));
+ }
+
+ @Test
+ public void testUpdatePowerStateDifferentPowerState() {
+ when(vm.getPowerStateUpdateTime()).thenReturn(null);
+ when(vm.getPowerHostId()).thenReturn(1L);
+ when(vm.getPowerState()).thenReturn(VirtualMachine.PowerState.PowerOn);
+ doReturn(vm).when(vmInstanceDao).findById(anyLong());
+ doReturn(true).when(vmInstanceDao).update(anyLong(), any());
+
+ boolean result = vmInstanceDao.updatePowerState(1L, 1L,
VirtualMachine.PowerState.PowerOff, new Date());
+
+ verify(vm, times(1)).setPowerState(VirtualMachine.PowerState.PowerOff);
+ verify(vm, times(1)).setPowerHostId(1L);
+ verify(vm, times(1)).setPowerStateUpdateCount(1);
+ verify(vm, times(1)).setPowerStateUpdateTime(any(Date.class));
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void testUpdatePowerStateVmNotFound() {
+ when(vm.getPowerStateUpdateTime()).thenReturn(null);
+ when(vm.getPowerHostId()).thenReturn(1L);
+ when(vm.getPowerState()).thenReturn(VirtualMachine.PowerState.PowerOn);
+ doReturn(null).when(vmInstanceDao).findById(anyLong());
+
+ boolean result = vmInstanceDao.updatePowerState(1L, 1L,
VirtualMachine.PowerState.PowerOff, new Date());
+
+ verify(vm, never()).setPowerState(any());
+ verify(vm, never()).setPowerHostId(anyLong());
+ verify(vm, never()).setPowerStateUpdateCount(any(Integer.class));
+ verify(vm, never()).setPowerStateUpdateTime(any(Date.class));
+
+ assertFalse(result);
+ }
+
+ @Test
+ public void testUpdatePowerStateNoChangeFirstUpdate() {
+ when(vm.getPowerStateUpdateTime()).thenReturn(null);
+ when(vm.getPowerHostId()).thenReturn(1L);
+ when(vm.getPowerState()).thenReturn(VirtualMachine.PowerState.PowerOn);
+ when(vm.getState()).thenReturn(Running);
+ when(vm.getPowerStateUpdateCount()).thenReturn(1);
+ doReturn(vm).when(vmInstanceDao).findById(anyLong());
+ doReturn(true).when(vmInstanceDao).update(anyLong(), any());
+
+ boolean result = vmInstanceDao.updatePowerState(1L, 1L,
VirtualMachine.PowerState.PowerOn, new Date());
+
+ verify(vm, never()).setPowerState(any());
+ verify(vm, never()).setPowerHostId(anyLong());
+ verify(vm, times(1)).setPowerStateUpdateCount(2);
+ verify(vm, times(1)).setPowerStateUpdateTime(any(Date.class));
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void testUpdatePowerStateNoChangeMaxUpdatesValidState() {
+ when(vm.getPowerStateUpdateTime()).thenReturn(null);
+ when(vm.getPowerHostId()).thenReturn(1L);
+ when(vm.getPowerState()).thenReturn(VirtualMachine.PowerState.PowerOn);
+
when(vm.getPowerStateUpdateCount()).thenReturn(MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT);
+ when(vm.getState()).thenReturn(Running);
+ doReturn(vm).when(vmInstanceDao).findById(anyLong());
+ doReturn(true).when(vmInstanceDao).update(anyLong(), any());
+
+ boolean result = vmInstanceDao.updatePowerState(1L, 1L,
VirtualMachine.PowerState.PowerOn, new Date());
+
+ verify(vm, never()).setPowerState(any());
+ verify(vm, never()).setPowerHostId(anyLong());
+ verify(vm, never()).setPowerStateUpdateCount(any(Integer.class));
+ verify(vm, never()).setPowerStateUpdateTime(any(Date.class));
+
+ assertFalse(result);
}
+ @Test
+ public void testUpdatePowerStateNoChangeMaxUpdatesInvalidStateVmStopped() {
+ when(vm.getPowerStateUpdateTime()).thenReturn(null);
+ when(vm.getPowerHostId()).thenReturn(1L);
+ when(vm.getPowerState()).thenReturn(VirtualMachine.PowerState.PowerOn);
+
when(vm.getPowerStateUpdateCount()).thenReturn(MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT);
+ when(vm.getState()).thenReturn(Stopped);
+ doReturn(vm).when(vmInstanceDao).findById(anyLong());
+ doReturn(true).when(vmInstanceDao).update(anyLong(), any());
+
+ boolean result = vmInstanceDao.updatePowerState(1L, 1L,
VirtualMachine.PowerState.PowerOn, new Date());
+
+ verify(vm, times(1)).setPowerState(any());
+ verify(vm, times(1)).setPowerHostId(anyLong());
+ verify(vm, times(1)).setPowerStateUpdateCount(1);
+ verify(vm, times(1)).setPowerStateUpdateTime(any(Date.class));
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void testUpdatePowerStateNoChangeMaxUpdatesInvalidStateVmRunning() {
+ when(vm.getPowerStateUpdateTime()).thenReturn(null);
+ when(vm.getPowerHostId()).thenReturn(1L);
+
when(vm.getPowerState()).thenReturn(VirtualMachine.PowerState.PowerOff);
+
when(vm.getPowerStateUpdateCount()).thenReturn(MAX_CONSECUTIVE_SAME_STATE_UPDATE_COUNT);
+ when(vm.getState()).thenReturn(Running);
+ doReturn(vm).when(vmInstanceDao).findById(anyLong());
+ doReturn(true).when(vmInstanceDao).update(anyLong(), any());
+
+ boolean result = vmInstanceDao.updatePowerState(1L, 1L,
VirtualMachine.PowerState.PowerOff, new Date());
+
+ verify(vm, times(1)).setPowerState(any());
+ verify(vm, times(1)).setPowerHostId(anyLong());
+ verify(vm, times(1)).setPowerStateUpdateCount(1);
+ verify(vm, times(1)).setPowerStateUpdateTime(any(Date.class));
+
+ assertTrue(result);
+ }
}