Liron Aravot has uploaded a new change for review.

Change subject: core: add locks to VmTemplate commands (#761515)
......................................................................

core: add locks to VmTemplate commands (#761515)

https://bugzilla.redhat.com/761515

Currently the different VmTemplate commands make use of DB lock only,
which causes to different race conditions (as the lock is check and only
then acquired - non atomic operation). This patch adds to the different
VmTemplate commands the use of in-memory lock and canDoAction() checks
in order to prevent those race conditions and possible corruption.

Change-Id: I2d5b6518bbf19077ae5822b9359a6147c87d0f46
Signed-off-by: Liron Aravot <lara...@redhat.com>
---
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromTemplateCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ExportVmTemplateCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ImportVmTemplateCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/MoveOrCopyTemplateCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateFromImportExportCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateHandler.java
M 
backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/AddVmCommandTest.java
10 files changed, 111 insertions(+), 26 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/13/8013/1

diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmCommand.java
index eb81bc6..dd113f5 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmCommand.java
@@ -279,6 +279,10 @@
         addCanDoActionMessage(VdcBllMessages.VAR__TYPE__VM);
     }
 
+    protected boolean verifyVmTemplateStatusForUse(Guid templateId, Boolean 
checkIfBlankTemplate) {
+        return VmTemplateHandler.verifyVmTemplateStatusForUse(templateId, 
checkIfBlankTemplate);
+    }
+
     @Override
     protected boolean canDoAction() {
         boolean returnValue = true;
@@ -286,6 +290,12 @@
             
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
             return false;
         }
+
+        if (!verifyVmTemplateStatusForUse(getVmTemplateId(), Boolean.TRUE)) {
+            getReturnValue().getCanDoActionMessages()
+                    
.add(VdcBllMessages.VM_TEMPLATE_IMAGE_IS_LOCKED.toString());
+        }
+
         returnValue = buildAndCheckDestStorageDomains();
         if (returnValue) {
             storageToDisksMap =
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromTemplateCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromTemplateCommand.java
index 4faa6ea..b08d5a0 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromTemplateCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmFromTemplateCommand.java
@@ -1,6 +1,8 @@
 package org.ovirt.engine.core.bll;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.ovirt.engine.core.bll.job.ExecutionHandler;
 import org.ovirt.engine.core.common.action.AddVmFromTemplateParameters;
@@ -12,6 +14,7 @@
 import org.ovirt.engine.core.common.businessentities.VMStatus;
 import org.ovirt.engine.core.common.errors.VdcBLLException;
 import org.ovirt.engine.core.common.errors.VdcBllErrors;
+import org.ovirt.engine.core.common.locks.LockingGroup;
 import org.ovirt.engine.core.compat.Guid;
 import org.ovirt.engine.core.dal.dbbroker.DbFacade;
 
@@ -33,6 +36,14 @@
     }
 
     @Override
+    protected Map<String, String> getExclusiveLocks() {
+        Map<String, String> locks = new HashMap<String, String>();
+        locks.putAll(super.getExclusiveLocks());
+        locks.put(getVmTemplateId().toString(), LockingGroup.TEMPLATE.name());
+        return locks;
+    }
+
+    @Override
     protected void ExecuteVmCommand() {
         super.ExecuteVmCommand();
         // override template id to blank
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ExportVmTemplateCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ExportVmTemplateCommand.java
index ede9c86..d94dc2f 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ExportVmTemplateCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ExportVmTemplateCommand.java
@@ -1,6 +1,7 @@
 package org.ovirt.engine.core.bll;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Map;
 
 import org.ovirt.engine.core.bll.job.ExecutionHandler;
@@ -15,11 +16,13 @@
 import org.ovirt.engine.core.common.businessentities.DiskImage;
 import org.ovirt.engine.core.common.businessentities.StorageDomainType;
 import org.ovirt.engine.core.common.errors.VdcBLLException;
+import org.ovirt.engine.core.common.locks.LockingGroup;
 import org.ovirt.engine.core.compat.Guid;
 import org.ovirt.engine.core.dal.VdcBllMessages;
 import org.ovirt.engine.core.utils.transaction.TransactionMethod;
 import org.ovirt.engine.core.utils.transaction.TransactionSupport;
 
+@LockIdNameAttribute
 public class ExportVmTemplateCommand<T extends MoveOrCopyParameters> extends 
MoveOrCopyTemplateCommand<T> {
 
     public ExportVmTemplateCommand(T parameters) {
@@ -73,10 +76,21 @@
     }
 
     @Override
+    protected Map<String, String> getExclusiveLocks() {
+        return Collections.singletonMap(getVmTemplateId().toString(), 
LockingGroup.TEMPLATE.name());
+    }
+
+    @Override
     protected boolean canDoAction() {
         if (getVmTemplate() != null) {
             setDescription(getVmTemplateName());
         }
+
+        if (!VmTemplateHandler.verifyVmTemplateStatusForUse(getVmTemplateId(), 
false)) {
+            getReturnValue().getCanDoActionMessages()
+            .add(VdcBllMessages.VM_TEMPLATE_IMAGE_IS_LOCKED.toString());
+        }
+
         StorageDomainValidator storageDomainValidator = new 
StorageDomainValidator(getStorageDomain());
         boolean retVal = 
storageDomainValidator.isDomainExistAndActive(getReturnValue().getCanDoActionMessages());
 
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ImportVmTemplateCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ImportVmTemplateCommand.java
index 05eed07..043dad2 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ImportVmTemplateCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/ImportVmTemplateCommand.java
@@ -2,6 +2,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -42,6 +43,7 @@
 import org.ovirt.engine.core.common.businessentities.storage_domains;
 import org.ovirt.engine.core.common.errors.VdcBLLException;
 import org.ovirt.engine.core.common.errors.VdcBllErrors;
+import org.ovirt.engine.core.common.locks.LockingGroup;
 import org.ovirt.engine.core.common.queries.DiskImageList;
 import 
org.ovirt.engine.core.common.queries.GetAllFromExportDomainQueryParameters;
 import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
@@ -77,6 +79,11 @@
     }
 
     @Override
+    protected Map<String, String> getExclusiveLocks() {
+        return Collections.singletonMap(getVmTemplateId().toString(), 
LockingGroup.TEMPLATE.name());
+    }
+
+    @Override
     protected boolean canDoAction() {
         boolean retVal = true;
         if (getVmTemplate() == null) {
@@ -84,6 +91,11 @@
         } else {
             setDescription(getVmTemplateName());
         }
+
+        if (retVal && 
!VmTemplateHandler.verifyVmTemplateStatusForUse(getVmTemplateId(), false)) {
+            getReturnValue().getCanDoActionMessages()
+                    
.add(VdcBllMessages.VM_TEMPLATE_IMAGE_IS_LOCKED.toString());
+        }
         // check that the storage pool is valid
         retVal = retVal && checkStoragePool();
 
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/MoveOrCopyTemplateCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/MoveOrCopyTemplateCommand.java
index 5be693f..7ac4cd6 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/MoveOrCopyTemplateCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/MoveOrCopyTemplateCommand.java
@@ -156,15 +156,13 @@
 
     @Override
     protected void executeCommand() {
-        if (VmTemplateHandler.isTemplateStatusIsNotLocked(getVmTemplateId())) {
-            VmTemplateHandler.lockVmTemplateInTransaction(getVmTemplateId(), 
getCompensationContext());
-            if (!getTemplateDisks().isEmpty()) {
-                MoveOrCopyAllImageGroups();
-            } else {
-                endVmTemplateRelatedOps();
-            }
-            setSucceeded(true);
+        VmTemplateHandler.lockVmTemplateInTransaction(getVmTemplateId(), 
getCompensationContext());
+        if (!getTemplateDisks().isEmpty()) {
+            MoveOrCopyAllImageGroups();
+        } else {
+            endVmTemplateRelatedOps();
         }
+        setSucceeded(true);
     }
 
     protected void MoveOrCopyAllImageGroups() {
@@ -219,6 +217,10 @@
         }
     }
 
+    protected boolean verifyVmTemplateStatusForUse(Guid templateId, boolean 
checkIfBlankTemplate) {
+        return VmTemplateHandler.verifyVmTemplateStatusForUse(templateId, 
checkIfBlankTemplate);
+    }
+
     protected boolean checkIfDisksExist(Iterable<DiskImage> disksList) {
         for (DiskImage disk : disksList) {
             VDSReturnValue runVdsCommand = getBackend()
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateCommand.java
index 02ff06e..57f0c70 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateCommand.java
@@ -1,6 +1,7 @@
 package org.ovirt.engine.core.bll;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -19,6 +20,7 @@
 import org.ovirt.engine.core.common.businessentities.VM;
 import org.ovirt.engine.core.common.businessentities.VmTemplate;
 import org.ovirt.engine.core.common.businessentities.storage_domain_static;
+import org.ovirt.engine.core.common.locks.LockingGroup;
 import org.ovirt.engine.core.common.vdscommands.IrsBaseVDSCommandParameters;
 import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
 import org.ovirt.engine.core.compat.Guid;
@@ -29,6 +31,7 @@
 import org.ovirt.engine.core.utils.transaction.TransactionSupport;
 
 @NonTransactiveCommandAttribute(forceCompensation = true)
+@LockIdNameAttribute
 public class RemoveVmTemplateCommand<T extends VmTemplateParametersBase> 
extends VmTemplateCommand<T>
         implements Quotable {
 
@@ -66,6 +69,11 @@
         if (VmTemplateHandler.BlankVmTemplateId.equals(vmTemplateId)) {
             
addCanDoActionMessage(VdcBllMessages.VMT_CANNOT_REMOVE_BLANK_TEMPLATE);
             return false;
+        }
+
+        if (!VmTemplateHandler.verifyVmTemplateStatusForUse(getVmTemplateId(), 
false)) {
+            getReturnValue().getCanDoActionMessages()
+                    
.add(VdcBllMessages.VM_TEMPLATE_IMAGE_IS_LOCKED.toString());
         }
 
         // check storage pool valid
@@ -176,28 +184,32 @@
 
     @Override
     protected void executeCommand() {
-        if (VmTemplateHandler.isTemplateStatusIsNotLocked(getVmTemplateId())) {
-            // Set VM to lock status immediately, for reducing race condition.
-            VmTemplateHandler.lockVmTemplateInTransaction(getVmTemplateId(), 
getCompensationContext());
-            // if for some reason template doesn't have images, remove it now 
and not in end action
-            final boolean hasImages = imageTemplates.size() > 0;
-            if 
(RemoveTemplateInSpm(getVmTemplate().getstorage_pool_id().getValue(), 
getVmTemplateId())) {
-                if (hasImages) {
-                    TransactionSupport.executeInNewTransaction(new 
TransactionMethod<Void>() {
+        // Set VM to lock status immediately, for reducing race condition.
+        VmTemplateHandler.lockVmTemplateInTransaction(getVmTemplateId(), 
getCompensationContext());
+        // if for some reason template doesn't have images, remove it now and 
not in end action
+        final boolean hasImages = imageTemplates.size() > 0;
+        if 
(RemoveTemplateInSpm(getVmTemplate().getstorage_pool_id().getValue(), 
getVmTemplateId())) {
+            if (hasImages) {
+                TransactionSupport.executeInNewTransaction(new 
TransactionMethod<Void>() {
 
-                        @Override
-                        public Void runInTransaction() {
-                            if (RemoveVmTemplateImages()) {
-                                setSucceeded(true);
-                            }
-                            return null;
+                    @Override
+                    public Void runInTransaction() {
+                        if (RemoveVmTemplateImages()) {
+                            setSucceeded(true);
                         }
-                    });
-                } else {
-                    HandleEndAction();
-                }
+                        return null;
+                    }
+                });
+            } else {
+                HandleEndAction();
             }
         }
+
+    }
+
+    @Override
+    protected Map<String, String> getExclusiveLocks() {
+        return Collections.singletonMap(getVmTemplateId().toString(), 
LockingGroup.TEMPLATE.name());
     }
 
     private void RemoveTemplateFromDb() {
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateFromImportExportCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateFromImportExportCommand.java
index 95be26f..63139be 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateFromImportExportCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmTemplateFromImportExportCommand.java
@@ -31,6 +31,7 @@
 import org.ovirt.engine.core.utils.linq.Predicate;
 
 @NonTransactiveCommandAttribute
+@LockIdNameAttribute
 public class RemoveVmTemplateFromImportExportCommand<T extends 
VmTemplateImportExportParameters> extends
         RemoveVmTemplateCommand<T> {
 
@@ -50,6 +51,13 @@
             retVal = false;
             
addCanDoActionMessage(VdcBllMessages.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
         }
+
+        if (retVal && 
!VmTemplateHandler.verifyVmTemplateStatusForUse(getVmTemplateId(), false)) {
+            getReturnValue().getCanDoActionMessages()
+                    
.add(VdcBllMessages.VM_TEMPLATE_IMAGE_IS_LOCKED.toString());
+            retVal = false;
+        }
+
         if (retVal) {
             DiskImageList images = 
templatesFromExport.get(LinqUtils.firstOrNull(templatesFromExport.keySet(),
                         new Predicate<VmTemplate>() {
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateCommand.java
index ad78350..99ccd75 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateCommand.java
@@ -178,6 +178,10 @@
         return getVmTemplateName();
     }
 
+    protected boolean verifyVmTemplateStatusForUse(Guid templateId, boolean 
checkIfBlankTemplate) {
+        return VmTemplateHandler.verifyVmTemplateStatusForUse(templateId, 
checkIfBlankTemplate);
+    }
+
     /**
      * This method create OVF for each template in list and call updateVm in 
SPM
      *
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateHandler.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateHandler.java
index 4e0f1c0..4876b74 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateHandler.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmTemplateHandler.java
@@ -123,5 +123,16 @@
         }
     }
 
+    /**
+     * Returns boolean indicating if the template with the given templateId is 
free for use.
+     * @param templateId
+     * @param checkIfBlankTemplate
+     * @return
+     */
+    public static boolean verifyVmTemplateStatusForUse(Guid templateId, 
boolean checkIfBlankTemplate) {
+        return !((checkIfBlankTemplate || 
!VmTemplateHandler.BlankVmTemplateId.equals(templateId))
+                && !VmTemplateHandler.isTemplateStatusIsNotLocked(templateId));
+    }
+
     private static Log log = LogFactory.getLog(VmTemplateHandler.class);
 }
diff --git 
a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/AddVmCommandTest.java
 
b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/AddVmCommandTest.java
index 7be5659..e28ab00 100644
--- 
a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/AddVmCommandTest.java
+++ 
b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/AddVmCommandTest.java
@@ -469,6 +469,7 @@
 
     private static void mockVerifyAddVM(AddVmCommand<?> cmd) {
         doReturn(true).when(cmd).verifyAddVM(anyListOf(String.class), 
any(Guid.class), anyInt());
+        doReturn(true).when(cmd).verifyVmTemplateStatusForUse(any(Guid.class), 
any(Boolean.class));
     }
 
     private void mockConfig() {


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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I2d5b6518bbf19077ae5822b9359a6147c87d0f46
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Liron Aravot <lara...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to