Roy Golan has uploaded a new change for review.

Change subject: core: VURTI - fix handle expection in GetVmStats
......................................................................

core: VURTI - fix handle expection in GetVmStats

after getting all vms with List command, VURTI loops through them
to update internal structure data. BUT if the call fails, VURTI removes
the VM from the internal running map - this leads to a split-brains
for VURTI assumes the Vm is DOWN and if it HA, its runs it.

the fix is to exclude this Vm from the list of the vms that have changed
this is similar to a case where Vm didn't changed its status

UNIT TEST
added a unit test to make sure the VM is kept in the map
although the call to GetVmStats didn't made it

Bug-Url: https://bugzilla.redhat.com/1072282
Change-Id: I415804d9fa1f1288423241b8547f4cab5540914a
Signed-off-by: Roy Golan <rgo...@redhat.com>
---
M 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/ResourceManager.java
M 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsManager.java
M 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfo.java
M 
backend/manager/modules/vdsbroker/src/test/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfoTest.java
4 files changed, 164 insertions(+), 36 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/99/25599/1

diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/ResourceManager.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/ResourceManager.java
index 802f99a..a925334 100644
--- 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/ResourceManager.java
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/ResourceManager.java
@@ -51,7 +51,6 @@
             new ConcurrentHashMap<Guid, Boolean>();
 
     private static final String VDSCommandPrefix = "VDSCommand";
-
     private static Log log = LogFactory.getLog(ResourceManager.class);
 
     private ResourceManager() {
diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsManager.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsManager.java
index bbb2639..7b0b7f4 100644
--- 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsManager.java
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsManager.java
@@ -65,7 +65,7 @@
         return (_refreshIteration == _numberRefreshesBeforeSave);
     }
 
-    private static final int VDS_REFRESH_RATE = Config.<Integer> 
getValue(ConfigValues.VdsRefreshRate) * 1000;
+    private int VDS_REFRESH_RATE = Config.<Integer> 
getValue(ConfigValues.VdsRefreshRate) * 1000;
 
     private String onTimerJobId;
 
@@ -97,7 +97,7 @@
     private final AtomicInteger mUnrespondedAttempts;
     private final AtomicBoolean sshSoftFencingExecuted;
 
-    private static final int VDS_DURING_FAILURE_TIMEOUT_IN_MINUTES = Config
+    private  int VDS_DURING_FAILURE_TIMEOUT_IN_MINUTES = Config
             .<Integer> 
getValue(ConfigValues.TimeToReduceFailedRunOnVdsInMinutes);
     private String duringFailureJobId;
     private boolean privateInitialized;
diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfo.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfo.java
index b1be8a9..ebe742a 100644
--- 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfo.java
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfo.java
@@ -902,20 +902,12 @@
         auditLog(logable, AuditLogType.VDS_DETECTED);
     }
 
-    private void refreshVmStats() {
+    protected void refreshVmStats() {
         if (Config.<Boolean> getValue(ConfigValues.DebugTimerLogging)) {
             log.debug("vds::refreshVmList entered");
         }
-        VDSReturnValue vdsReturnValue;
-        VDSCommandType commandType =
-                _vdsManager.getRefreshStatistics()
-                        ? VDSCommandType.GetAllVmStats
-                        : VDSCommandType.List;
-        vdsReturnValue = getResourceManager().runVdsCommand(commandType, new 
VdsIdAndVdsVDSCommandParametersBase(_vds));
 
-        _runningVms = (Map<Guid, VmInternalData>) 
vdsReturnValue.getReturnValue();
-
-        if (vdsReturnValue.getSucceeded()) {
+        if (fetchRunningVms()) {
             List<VM> running = checkVmsStatusChanged();
 
             proceedWatchdogEvents();
@@ -945,8 +937,23 @@
             prepareGuestAgentNetworkDevicesForUpdate();
 
             updateLunDisks();
+        }
+    }
 
-        } else {
+    /**
+     * fetch running VMs and populate the internal structure. if we fail, 
handle the error
+     * @return true if we could get vms otherwise false
+     */
+    protected boolean fetchRunningVms() {
+        VDSCommandType commandType =
+                _vdsManager.getRefreshStatistics()
+                        ? VDSCommandType.GetAllVmStats
+                        : VDSCommandType.List;
+        VDSReturnValue vdsReturnValue =
+                getResourceManager().runVdsCommand(commandType, new 
VdsIdAndVdsVDSCommandParametersBase(_vds));
+        _runningVms = (Map<Guid, VmInternalData>) 
vdsReturnValue.getReturnValue();
+
+        if (!vdsReturnValue.getSucceeded()) {
             RuntimeException callException = 
vdsReturnValue.getExceptionObject();
             if (callException != null) {
                 if (callException instanceof VDSErrorException) {
@@ -963,6 +970,8 @@
                 log.errorFormat("{0} failed with no exception!", 
commandType.name());
             }
         }
+
+        return vdsReturnValue.getSucceeded();
     }
 
     /**
@@ -1257,7 +1266,7 @@
     }
 
     // if not statistics check if status changed and add to running list
-    private List<VM> checkVmsStatusChanged() {
+    protected List<VM> checkVmsStatusChanged() {
         List<VM> running = new ArrayList<VM>();
         if (!_vdsManager.getRefreshStatistics()) {
             List<VmDynamic> tempRunningList = new ArrayList<VmDynamic>();
@@ -1267,18 +1276,25 @@
             for (VmDynamic runningVm : tempRunningList) {
                 VM vmToUpdate = _vmDict.get(runningVm.getId());
 
+                boolean statusNotChanged = false;
                 if (vmToUpdate == null
                         || (vmToUpdate.getStatus() != runningVm.getStatus() &&
-                        !(vmToUpdate.getStatus() == 
VMStatus.PreparingForHibernate && runningVm.getStatus() == VMStatus.Up))) {
-                    VDSReturnValue vdsReturnValue = 
getResourceManager().runVdsCommand(
-                            VDSCommandType.GetVmStats,
-                            new GetVmStatsVDSCommandParameters(_vds, 
runningVm.getId()));
-                    if (vdsReturnValue.getSucceeded()) {
-                        _runningVms.put(runningVm.getId(), (VmInternalData) 
vdsReturnValue.getReturnValue());
+                        !(vmToUpdate.getStatus() == 
VMStatus.PreparingForHibernate && runningVm.getStatus() == VMStatus.Up)) ) {
+                    VDSReturnValue vmStats =
+                            getResourceManager().runVdsCommand(
+                                    VDSCommandType.GetVmStats,
+                                    new GetVmStatsVDSCommandParameters(_vds, 
runningVm.getId()));
+                    if (vmStats.getSucceeded()) {
+                        _runningVms.put(runningVm.getId(), (VmInternalData) 
vmStats.getReturnValue());
                     } else {
-                        _runningVms.remove(runningVm.getId());
+                        log.error("failed to fetch vm stats. status remain 
unchanged");
+                        statusNotChanged = true;
                     }
                 } else {
+                    statusNotChanged = true;
+                }
+
+                if (statusNotChanged) {
                     // status not changed move to next vm
                     running.add(vmToUpdate);
                     _runningVms.remove(vmToUpdate.getId());
@@ -1573,7 +1589,7 @@
         }
     }
 
-    private void processExternallyManagedVms() {
+    protected void processExternallyManagedVms() {
         List<String> vmsToQuery = new ArrayList<String>();
         // Searching for External VMs that run on the host
         for (VmInternalData vmInternalData : _runningVms.values()) {
diff --git 
a/backend/manager/modules/vdsbroker/src/test/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfoTest.java
 
b/backend/manager/modules/vdsbroker/src/test/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfoTest.java
index a4b0f4e..c97677a 100644
--- 
a/backend/manager/modules/vdsbroker/src/test/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfoTest.java
+++ 
b/backend/manager/modules/vdsbroker/src/test/java/org/ovirt/engine/core/vdsbroker/VdsUpdateRunTimeInfoTest.java
@@ -12,11 +12,14 @@
 import java.util.List;
 import java.util.Map;
 
+import junit.framework.Assert;
+
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.ovirt.engine.core.common.AuditLogType;
 import org.ovirt.engine.core.common.businessentities.AuditLog;
@@ -26,10 +29,16 @@
 import org.ovirt.engine.core.common.businessentities.VDS;
 import org.ovirt.engine.core.common.businessentities.VDSGroup;
 import org.ovirt.engine.core.common.businessentities.VM;
+import org.ovirt.engine.core.common.businessentities.VMStatus;
 import org.ovirt.engine.core.common.businessentities.VmDevice;
-import org.ovirt.engine.core.common.businessentities.VmDynamic;
 import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType;
+import org.ovirt.engine.core.common.businessentities.VmDynamic;
+import org.ovirt.engine.core.common.config.ConfigValues;
+import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
+import org.ovirt.engine.core.common.vdscommands.VDSParametersBase;
+import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
 import org.ovirt.engine.core.compat.Guid;
+import org.ovirt.engine.core.compat.Version;
 import org.ovirt.engine.core.dal.dbbroker.DbFacade;
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase;
 import org.ovirt.engine.core.dao.AuditLogDAO;
@@ -37,6 +46,8 @@
 import org.ovirt.engine.core.dao.VdsGroupDAO;
 import org.ovirt.engine.core.dao.VmDAO;
 import org.ovirt.engine.core.dao.VmDeviceDAO;
+import org.ovirt.engine.core.dao.VmDynamicDAO;
+import org.ovirt.engine.core.utils.MockConfigRule;
 import org.ovirt.engine.core.utils.MockEJBStrategyRule;
 import org.ovirt.engine.core.vdsbroker.vdsbroker.VdsProperties;
 import org.ovirt.engine.core.vdsbroker.vdsbroker.entities.VmInternalData;
@@ -44,13 +55,27 @@
 @RunWith(MockitoJUnitRunner.class)
 public class VdsUpdateRunTimeInfoTest {
 
+    private static final Guid VM_1 = 
Guid.createGuidFromString("7eeabc50-325f-49bb-acb6-15e786599423");
+
     @ClassRule
     public static MockEJBStrategyRule mockEjbRule = new MockEJBStrategyRule();
+
+    @ClassRule
+    public static MockConfigRule mcr = new MockConfigRule(
+            MockConfigRule.mockConfig(
+                    ConfigValues.DebugTimerLogging,
+                    true),
+            MockConfigRule.mockConfig(
+                    ConfigValues.VdsRefreshRate,
+                    3),
+            MockConfigRule.mockConfig(
+                    ConfigValues.TimeToReduceFailedRunOnVdsInMinutes,
+                    3)
+    );
 
     private VDS vds;
     HashMap[] vmInfo;
     List<VmDynamic> poweringUpVms;
-    Map<Guid, VmInternalData> runningVms;
 
     VdsUpdateRunTimeInfo updater;
 
@@ -72,13 +97,28 @@
     @Mock
     VmDeviceDAO vmDeviceDAO;
 
+    @Mock
+    VmDynamicDAO vmDynamicDao;
+
     AuditLogDAO mockAuditLogDao = new AuditLogDaoMocker();
+
+    VM vm_1_db;
+    VM vm_1_vdsm;
+
+    @Mock
+    ResourceManager resourceManager;
+
+    @Mock
+    private VdsManager vdsManager;
+
 
     @Before
     public void setup() {
         initVds();
         initConditions();
-        updater = new VdsUpdateRunTimeInfo(null, vds, 
mock(MonitoringStrategy.class)) {
+        when(vdsManager.getRefreshStatistics()).thenReturn(false);
+        updater = Mockito.spy(
+                    new VdsUpdateRunTimeInfo(vdsManager, vds, 
mock(MonitoringStrategy.class)) {
 
             @Override
             public DbFacade getDbFacade() {
@@ -101,13 +141,7 @@
             protected List<VmDynamic> getPoweringUpVms() {
                 return poweringUpVms;
             }
-
-            @Override
-            protected Map<Guid, VmInternalData> getRunningVms() {
-                return runningVms;
-            }
-
-        };
+        });
     }
 
     @Test
@@ -183,9 +217,8 @@
         VmInternalData vmInternalData = new VmInternalData(vmDynamic, null, 
null, lunsMapFromVmStats);
 
         when(diskDAO.getAllForVm(any(Guid.class), 
any(Boolean.class))).thenReturn(vmLunDisksFromDb);
-
+        
when(updater.getRunningVms()).thenReturn(Collections.singletonMap(vmId, 
vmInternalData));
         poweringUpVms = Collections.singletonList(vmDynamic);
-        runningVms = Collections.singletonMap(vmId, vmInternalData);
 
         updater.updateLunDisks();
     }
@@ -195,15 +228,18 @@
         when(dbFacade.getVmDao()).thenReturn(vmDAO);
         when(dbFacade.getAuditLogDao()).thenReturn(mockAuditLogDao);
         when(dbFacade.getVmDeviceDao()).thenReturn(vmDeviceDAO);
+        when(dbFacade.getVmDynamicDao()).thenReturn(vmDynamicDao);
         when(dbFacade.getDiskDao()).thenReturn(diskDAO);
         when(groupDAO.get((Guid) any())).thenReturn(cluster);
         Map<Guid, VM> emptyMap = Collections.emptyMap();
-        when(vmDAO.getAllRunningByVds(vds.getId())).thenReturn(emptyMap);
+        initVm();
+        
when(vmDAO.getAllRunningByVds(vds.getId())).thenReturn(Collections.singletonMap(VM_1,
 vm_1_db));
     }
 
     private void initVds() {
         vds = new VDS();
         vds.setId(new Guid("00000000-0000-0000-0000-000000000012"));
+        vds.setVdsGroupCompatibilityVersion(Version.v3_4);
     }
 
     @Test
@@ -221,4 +257,81 @@
         dynamic.setLastWatchdogEvent(null);
         assertFalse(VdsUpdateRunTimeInfo.isNewWatchdogEvent(dynamic, vm));
     }
+
+    /**
+     * Test that when we succeed in retriving a VM stats, we insert it into 
the internal runningVms structure
+     */
+    @Test
+    public void verifyListOfRunningVmsIsSameWithSuccessFromVdsmResponse() {
+        prepareForRefreshVmStatsCall();
+        mockGetVmStatsCommand(true);
+        // start refreshing vm data... VURTI now fetches Vms list from 
ResourceManager and loop through it
+        updater.fetchRunningVms();
+        List<VM> runningAndUnchanged = updater.checkVmsStatusChanged();
+
+        Assert.assertTrue(updater.getRunningVms().containsKey(VM_1));
+        Assert.assertFalse(runningAndUnchanged.contains(VM_1));
+    }
+
+    /**
+     * Test that when we fail in getting a response for GetVmStats we still 
insert the VM to the runningVms structure,<br>
+     * but not the internal runningVmStructure which is the same handling as 
if vm status didn't change
+     */
+    @Test
+    public void verifyListOfRunningVmsIsSameWithFailureOnGetVmStats() {
+        prepareForRefreshVmStatsCall();
+        mockGetVmStatsCommand(false);
+        // start refreshing vm data... VURTI now fetches Vms list from 
ResourceManager and loop through it
+        updater.fetchRunningVms();
+        List<VM> runningAndUnchanged = updater.checkVmsStatusChanged();
+
+        Assert.assertFalse(updater.getRunningVms().containsKey(VM_1));
+        Assert.assertTrue(runningAndUnchanged.contains(vm_1_db));
+    }
+
+    private void prepareForRefreshVmStatsCall() {
+        initVm();
+        mockUpdater();
+        mockListCommand();
+    }
+
+    private void mockUpdater() {
+        when(updater.getResourceManager()).thenReturn(resourceManager);
+    }
+
+    private void initVm() {
+        vm_1_vdsm = new VM();
+        vm_1_db = new VM();
+        vm_1_db.setId(VM_1);
+        vm_1_vdsm.setId(VM_1);
+        vm_1_db.setStatus(VMStatus.WaitForLaunch);
+        vm_1_vdsm.setStatus(VMStatus.Up);
+        vm_1_db.setName("vm-prod-mailserver");
+        vm_1_vdsm.setName("vm-prod-mailserver");
+        when(vmDynamicDao.get(VM_1)).thenReturn(vm_1_db.getDynamicData());
+    }
+
+    private void mockGetVmStatsCommand(boolean mockSuccess) {
+        VDSReturnValue vdsReturnValue = new VDSReturnValue();
+        if (mockSuccess) {
+            vdsReturnValue.setSucceeded(true);
+            vdsReturnValue.setReturnValue(createRunningVms().get(VM_1));
+        }
+        
when(resourceManager.runVdsCommand(Mockito.eq(VDSCommandType.GetVmStats), 
(VDSParametersBase) Mockito.anyObject())).thenReturn(vdsReturnValue);
+    }
+
+    private void mockListCommand() {
+        VDSReturnValue vdsReturnValue = new VDSReturnValue();
+        vdsReturnValue.setSucceeded(true);
+        vdsReturnValue.setReturnValue(createRunningVms());
+        when(resourceManager.runVdsCommand(Mockito.eq(VDSCommandType.List), 
(VDSParametersBase) Mockito.anyObject())).thenReturn(vdsReturnValue);
+        
when(resourceManager.runVdsCommand(Mockito.eq(VDSCommandType.GetVmStats), 
(VDSParametersBase) Mockito.anyObject())).thenReturn(vdsReturnValue);
+        when(updater.getResourceManager()).thenReturn(resourceManager);
+    }
+
+    private Map<Guid, VmInternalData> createRunningVms() {
+        HashMap<Guid, VmInternalData> vms = new HashMap<>();
+        vms.put(VM_1, new VmInternalData(vm_1_vdsm.getDynamicData(), null, 
null, null));
+        return vms;
+    }
 }


-- 
To view, visit http://gerrit.ovirt.org/25599
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I415804d9fa1f1288423241b8547f4cab5540914a
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.4
Gerrit-Owner: Roy Golan <rgo...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to