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 <vishes...@gmail.com>
AuthorDate: Mon Feb 19 18:26:21 2024 +0530

    Fixup vm powerstate update (#8545)
    
    Co-authored-by: Suresh Kumar Anaparti <suresh.anapa...@shapeblue.com>
---
 .../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);
+    }
 }

Reply via email to