Omer Frenkel has uploaded a new change for review.

Change subject: core: automatically update vms on new version
......................................................................

core: automatically update vms on new version

When new version of a template is available,
or when stateless(\pool) vm goes to down,
we update the vm to the new version.

Change-Id: I5449eee954bd6096b6f2e423a75a8cac3e5bcc3b
Signed-off-by: Omer Frenkel <ofren...@redhat.com>
---
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndAttachToPoolCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmTemplateCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmCommand.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/RestoreStatelessVmCommand.java
A 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmVersionCommand.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmCommand.java
M 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/RemoveVmParameters.java
A 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/UpdateVmVersionParameters.java
M 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java
A 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/CopyOnNewVersion.java
M 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmBase.java
M 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java
M backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAO.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAODbFacadeImpl.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAO.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAODbFacadeImpl.java
M backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties
M 
backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDAOTest.java
M 
backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmStaticDAOTest.java
M backend/manager/modules/dal/src/test/resources/fixtures.xml
M 
frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
M 
frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
M 
frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
M packaging/dbscripts/vms_sp.sql
25 files changed, 537 insertions(+), 31 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/10/23610/1

diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndAttachToPoolCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndAttachToPoolCommand.java
index ae9dc04..a3ee980 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndAttachToPoolCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmAndAttachToPoolCommand.java
@@ -2,6 +2,7 @@
 
 import java.util.Map;
 
+import org.apache.commons.lang.StringUtils;
 import org.ovirt.engine.core.bll.job.ExecutionHandler;
 import org.ovirt.engine.core.common.action.AddVmAndAttachToPoolParameters;
 import org.ovirt.engine.core.common.action.AddVmFromScratchParameters;
@@ -57,7 +58,11 @@
 
     private VdcReturnValueBase addVm(VmStatic vmStatic) {
         VmManagementParametersBase parameters = new 
VmManagementParametersBase(vmStatic);
-        parameters.setSessionId(getParameters().getSessionId());
+        if (StringUtils.isEmpty(getParameters().getSessionId())) {
+            parameters.setParametersCurrentUser(getCurrentUser());
+        } else {
+            parameters.setSessionId(getParameters().getSessionId());
+        }
         parameters.setDontAttachToDefaultTag(true);
         parameters.setDiskInfoDestinationMap(diskInfoDestinationMap);
         
parameters.setSoundDeviceEnabled(getParameters().isSoundDeviceEnabled());
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmTemplateCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmTemplateCommand.java
index 6501804..1d3e885 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmTemplateCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/AddVmTemplateCommand.java
@@ -8,6 +8,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.lang.StringUtils;
 import org.ovirt.engine.core.bll.quota.QuotaConsumptionParameter;
@@ -28,6 +30,7 @@
 import org.ovirt.engine.core.common.VdcObjectType;
 import org.ovirt.engine.core.common.action.AddVmTemplateParameters;
 import org.ovirt.engine.core.common.action.CreateImageTemplateParameters;
+import org.ovirt.engine.core.common.action.UpdateVmVersionParameters;
 import org.ovirt.engine.core.common.action.VdcActionParametersBase;
 import org.ovirt.engine.core.common.action.VdcActionType;
 import org.ovirt.engine.core.common.action.VdcReturnValueBase;
@@ -56,11 +59,14 @@
 import org.ovirt.engine.core.common.utils.Pair;
 import org.ovirt.engine.core.common.validation.group.CreateEntity;
 import org.ovirt.engine.core.compat.Guid;
+import org.ovirt.engine.core.compat.TransactionScopeOption;
 import org.ovirt.engine.core.dal.dbbroker.DbFacade;
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector;
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase;
 import org.ovirt.engine.core.dao.PermissionDAO;
 import org.ovirt.engine.core.utils.collections.MultiValueMapUtils;
+import org.ovirt.engine.core.utils.timer.OnTimerMethodAnnotation;
+import org.ovirt.engine.core.utils.timer.SchedulerUtilQuartzImpl;
 import org.ovirt.engine.core.utils.transaction.TransactionMethod;
 import org.ovirt.engine.core.utils.transaction.TransactionSupport;
 
@@ -77,6 +83,7 @@
     private boolean isVmInDb;
 
     private static final String BASE_TEMPLATE_VERSION_NAME = "base version";
+    private static Map<Guid, String> updateVmsJobIdMap = new 
ConcurrentHashMap<Guid, String>();
 
     /**
      * Constructor for command creation when compensation is applied on startup
@@ -203,6 +210,16 @@
             getParameters().setBaseTemplateId(getVmTemplateId());
             if (StringUtils.isEmpty(getParameters().getTemplateVersionName())) 
{
                 
getParameters().setTemplateVersionName(BASE_TEMPLATE_VERSION_NAME);
+            }
+        } else {
+            String jobId = 
updateVmsJobIdMap.remove(getParameters().getBaseTemplateId());
+            if (jobId != null) {
+                log.infoFormat("Cancelling current running update for vms for 
base template id {0}", getParameters().getBaseTemplateId());
+                try {
+                    SchedulerUtilQuartzImpl.getInstance().deleteJob(jobId);
+                } catch (Exception e) {
+                    log.warnFormat("Failed deleting job {0} at 
cancelRecoveryJob", jobId);
+                }
             }
         }
 
@@ -569,6 +586,29 @@
 
     private void endDefaultOperations() {
         endUnlockOps();
+
+        // in case of new version of a template, update vms marked to use 
latest
+        if (getParameters().getBaseTemplateId() != null) {
+            String jobId = 
SchedulerUtilQuartzImpl.getInstance().scheduleAOneTimeJob(this, 
"onTimerHandleVdsRecovering", new Class[0],
+                    new Object[0], 0, TimeUnit.SECONDS);
+            updateVmsJobIdMap.put(getParameters().getBaseTemplateId(), jobId);
+        }
+    }
+
+    @OnTimerMethodAnnotation("onTimerHandleVdsRecovering")
+    public void onTimerHandleVdsRecovering() {
+        for (Guid vmId : 
getVmDAO().getVmIdsForVersionUpdate(getParameters().getBaseTemplateId())) {
+            // if the job was removed, stop executing, we probably have new 
version creation going on
+            if 
(!updateVmsJobIdMap.containsKey(getParameters().getBaseTemplateId())) {
+                break;
+            }
+            UpdateVmVersionParameters params = new 
UpdateVmVersionParameters(vmId);
+            params.setSessionId(getParameters().getSessionId());
+            // execute in new transaction, as failure here should not fail 
template creation
+            
params.setTransactionScopeOption(TransactionScopeOption.RequiresNew);
+            getBackend().runInternalAction(VdcActionType.UpdateVmVersion, 
params);
+        }
+        updateVmsJobIdMap.remove(getParameters().getBaseTemplateId());
     }
 
     private void endUnlockOps() {
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmCommand.java
index c0ccd32..9cc7654 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RemoveVmCommand.java
@@ -261,9 +261,16 @@
 
     private RemoveAllVmImagesParameters 
buildRemoveAllVmImagesParameters(List<DiskImage> images) {
         RemoveAllVmImagesParameters params = new 
RemoveAllVmImagesParameters(getVmId(), images);
-        params.setParentCommand(getActionType());
-        params.setEntityInfo(getParameters().getEntityInfo());
-        params.setParentParameters(getParameters());
+        if (getParameters().getParentCommand() == VdcActionType.Unknown) {
+            params.setParentCommand(getActionType());
+            params.setEntityInfo(getParameters().getEntityInfo());
+            params.setParentParameters(getParameters());
+        } else {
+            params.setParentCommand(getParameters().getParentCommand());
+            
params.setEntityInfo(getParameters().getParentParameters().getEntityInfo());
+            params.setParentParameters(getParameters().getParentParameters());
+        }
+
         return params;
     }
 
@@ -283,7 +290,7 @@
         removeVmUsers();
         removeVmNetwork();
         memoryStates = removeVmSnapshots();
-        removeVmStatic();
+        removeVmStatic(getParameters().isRemovePermissions());
     }
 
     /**
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 4c71bfe..3f721af 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
@@ -154,7 +154,7 @@
         }
 
         // for base templates, make sure it has no versions that need to be 
removed first
-        if (vmTemplateId.equals(template.getBaseTemplateId())) {
+        if (getParameters().isRemoveTemplateFromDb() && 
vmTemplateId.equals(template.getBaseTemplateId())) {
             List<VmTemplate> templateVersions = 
getVmTemplateDAO().getTemplateVersionsForBaseTemplate(vmTemplateId);
             if (!templateVersions.isEmpty()) {
                 List<String> templateVersionsNames = new ArrayList<>();
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RestoreStatelessVmCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RestoreStatelessVmCommand.java
index 70b3037..1123cd7 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RestoreStatelessVmCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/RestoreStatelessVmCommand.java
@@ -4,6 +4,7 @@
 
 import org.ovirt.engine.core.bll.job.ExecutionHandler;
 import org.ovirt.engine.core.common.action.RestoreAllSnapshotsParameters;
+import org.ovirt.engine.core.common.action.UpdateVmVersionParameters;
 import org.ovirt.engine.core.common.action.VdcActionType;
 import org.ovirt.engine.core.common.action.VdcReturnValueBase;
 import org.ovirt.engine.core.common.action.VmOperationParameterBase;
@@ -30,27 +31,44 @@
 
     @Override
     protected void executeCommand() {
-        boolean returnVal = true;
-        Guid snapshotId = 
DbFacade.getInstance().getSnapshotDao().getId(getVmId(), 
SnapshotType.STATELESS);
-        List<DiskImage> imagesList = null;
+        VdcReturnValueBase result =
+                getBackend().runInternalAction(VdcActionType.UpdateVmVersion,
+                        new UpdateVmVersionParameters(getVmId()),
+                        
ExecutionHandler.createDefaultContexForTasks(getExecutionContext(), getLock()));
 
-        if (snapshotId != null) {
-            imagesList = 
DbFacade.getInstance().getDiskImageDao().getAllSnapshotsForVmSnapshot(snapshotId);
-        }
+        // if it fail because of canDoAction, its safe to restore the snapshot
+        // and the vm will still be usable with previous version
+        if (!result.getSucceeded() && !result.getCanDoAction()) {
+            log.warnFormat("Couldn't update VM {0} ({1}) version from it's 
template, continue with restoring stateless snapshot.",
+                    getVm().getName(),
+                    getVmId());
 
-        if (imagesList != null && imagesList.size() > 0) {
-            /**
-             * restore all snapshots
-             */
-            RestoreAllSnapshotsParameters tempVar = new 
RestoreAllSnapshotsParameters(getVm().getId(), snapshotId);
-            tempVar.setShouldBeLogged(false);
-            tempVar.setImages(imagesList);
-            VdcReturnValueBase vdcReturn =
-                    
Backend.getInstance().runInternalAction(VdcActionType.RestoreAllSnapshots,
-                            tempVar,
-                            
ExecutionHandler.createDefaultContexForTasks(getExecutionContext(), getLock()));
-            returnVal = vdcReturn.getSucceeded();
+            boolean returnVal = true;
+            Guid snapshotId = 
DbFacade.getInstance().getSnapshotDao().getId(getVmId(), 
SnapshotType.STATELESS);
+            List<DiskImage> imagesList = null;
+
+            if (snapshotId != null) {
+                imagesList = 
DbFacade.getInstance().getDiskImageDao().getAllSnapshotsForVmSnapshot(snapshotId);
+            }
+
+            if (imagesList != null && imagesList.size() > 0) {
+                /**
+                 * restore all snapshots
+                 */
+                RestoreAllSnapshotsParameters tempVar = new 
RestoreAllSnapshotsParameters(getVm().getId(), snapshotId);
+                tempVar.setShouldBeLogged(false);
+                tempVar.setImages(imagesList);
+                VdcReturnValueBase vdcReturn =
+                        
Backend.getInstance().runInternalAction(VdcActionType.RestoreAllSnapshots,
+                                tempVar,
+                                
ExecutionHandler.createDefaultContexForTasks(getExecutionContext(), getLock()));
+                returnVal = vdcReturn.getSucceeded();
+            }
+            setSucceeded(returnVal);
         }
-        setSucceeded(returnVal);
+    }
+
+    private void overrideVmComfig() {
+
     }
 }
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmVersionCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmVersionCommand.java
new file mode 100644
index 0000000..def4672
--- /dev/null
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/UpdateVmVersionCommand.java
@@ -0,0 +1,252 @@
+package org.ovirt.engine.core.bll;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.ovirt.engine.core.bll.job.ExecutionHandler;
+import org.ovirt.engine.core.common.VdcObjectType;
+import org.ovirt.engine.core.common.action.AddVmAndAttachToPoolParameters;
+import org.ovirt.engine.core.common.action.RemoveVmFromPoolParameters;
+import org.ovirt.engine.core.common.action.RemoveVmParameters;
+import org.ovirt.engine.core.common.action.UpdateVmVersionParameters;
+import org.ovirt.engine.core.common.action.VdcActionType;
+import org.ovirt.engine.core.common.action.VdcReturnValueBase;
+import org.ovirt.engine.core.common.action.VmManagementParametersBase;
+import org.ovirt.engine.core.common.asynctasks.EntityInfo;
+import org.ovirt.engine.core.common.businessentities.CopyOnNewVersion;
+import org.ovirt.engine.core.common.businessentities.DiskImage;
+import org.ovirt.engine.core.common.businessentities.VMStatus;
+import org.ovirt.engine.core.common.businessentities.VmBase;
+import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType;
+import org.ovirt.engine.core.common.businessentities.VmPayload;
+import org.ovirt.engine.core.common.businessentities.VmTemplate;
+import org.ovirt.engine.core.common.businessentities.VmWatchdog;
+import org.ovirt.engine.core.common.errors.VdcBllMessages;
+import org.ovirt.engine.core.common.locks.LockingGroup;
+import org.ovirt.engine.core.common.queries.IdQueryParameters;
+import org.ovirt.engine.core.common.queries.VdcQueryType;
+import org.ovirt.engine.core.common.utils.Pair;
+import org.ovirt.engine.core.common.utils.VmDeviceType;
+import org.ovirt.engine.core.compat.Guid;
+import org.ovirt.engine.core.compat.TransactionScopeOption;
+import org.ovirt.engine.core.utils.log.Log;
+import org.ovirt.engine.core.utils.log.LogFactory;
+
+/**
+ * This class updates VM to the latest template version for stateless vms that 
has newer template version
+ */
+@InternalCommandAttribute
+@LockIdNameAttribute
+public class UpdateVmVersionCommand<T extends UpdateVmVersionParameters> 
extends VmCommand<T> {
+
+    private static final Log log = 
LogFactory.getLog(UpdateVmVersionCommand.class);
+    /**
+     * Constructor for command creation when compensation is applied on startup
+     *
+     * @param commandId
+     */
+    protected UpdateVmVersionCommand(Guid commandId) {
+        super(commandId);
+    }
+
+    public UpdateVmVersionCommand(T parameters) {
+        super(parameters);
+        parameters.setEntityInfo(new EntityInfo(VdcObjectType.VM, 
parameters.getVmId()));
+
+        // vm should be filled in end action
+        if (parameters.getVm() != null) {
+            setVmTemplateId(parameters.getVm().getVmtGuid());
+        }
+    }
+
+    @Override
+    protected boolean canDoAction() {
+        if (getVm() == null) {
+            return 
failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_VM_NOT_FOUND);
+        }
+
+        if (getVm().getStatus() != VMStatus.Down) {
+            return 
failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_VM_IS_NOT_DOWN);
+        }
+
+        if (!getVm().isUseLatestVersion()) {
+            return 
failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_VM_NOT_SET_FOR_LATEST);
+        }
+
+        if (getVmTemplate() == null) {
+            return 
failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
+        }
+
+        if (getVm().getVmtGuid().equals(getVmTemplate().getId())) {
+            return 
failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_VM_ALREADY_IN_LATEST_VERSION);
+        }
+
+        getVm().setVmtGuid(getVmTemplate().getId());
+
+        return true;
+    }
+
+    @Override
+    protected void setActionMessageParameters() {
+        addCanDoActionMessage(VdcBllMessages.VAR__ACTION__UPDATE_VM_VERSION);
+        addCanDoActionMessage(VdcBllMessages.VAR__TYPE__VM);
+    }
+
+    @Override
+    protected void executeVmCommand() {
+        if (!copyData(getVmTemplate(), getVm().getStaticData())) {
+            return;
+        }
+        getParameters().setVmStaticData(getVm().getStaticData());
+
+        if (getVm().getVmPoolId() != null) {
+            getParameters().setVmPoolId(getVm().getVmPoolId());
+            RemoveVmFromPoolParameters removeVmFromPoolParas = new 
RemoveVmFromPoolParameters(getVmId(), false);
+            
removeVmFromPoolParas.setTransactionScopeOption(TransactionScopeOption.RequiresNew);
+            VdcReturnValueBase result = 
getBackend().runInternalAction(VdcActionType.RemoveVmFromPool,
+                    removeVmFromPoolParas,
+                    
ExecutionHandler.createDefaultContexForTasks(getExecutionContext(), getLock()));
+            if (!result.getSucceeded()) {
+                log.errorFormat("Could not detach vm {0} ({1}) from vm-pool 
{2}.",
+                        getVm().getName(),
+                        getVmId(),
+                        getVm().getVmPoolName());
+                return;
+            }
+        }
+
+        RemoveVmParameters removeParams = new RemoveVmParameters(getVmId(), 
false);
+        removeParams.setParentCommand(getActionType());
+        removeParams.setParentParameters(getParameters());
+        removeParams.setEntityInfo(getParameters().getEntityInfo());
+        VdcReturnValueBase result = 
getBackend().runInternalAction(VdcActionType.RemoveVm, removeParams,
+                
ExecutionHandler.createDefaultContexForTasks(getExecutionContext(), getLock()));
+
+        if (result.getSucceeded()) {
+            if (result.getHasAsyncTasks()) {
+                
getReturnValue().getVdsmTaskIdList().addAll(result.getInternalVdsmTaskIdList());
+            } else {
+                endVmCommand();
+            }
+            setSucceeded(true);
+        }
+    }
+
+    private void addUpdatedVm() {
+        VmManagementParametersBase addVmParams;
+        VdcActionType action;
+        if (getParameters().getVmPoolId() != null) {
+            addVmParams =
+                    new 
AddVmAndAttachToPoolParameters(getParameters().getVmStaticData(),
+                            getParameters().getVmPoolId(),
+                            getParameters().getVmStaticData().getName(),
+                            new HashMap<Guid, DiskImage>());
+            action = VdcActionType.AddVmAndAttachToPool;
+        } else {
+            addVmParams = new 
VmManagementParametersBase(getParameters().getVmStaticData());
+            action = VdcActionType.AddVm;
+        }
+
+        addVmParams.setDiskInfoDestinationMap(new HashMap<Guid, DiskImage>());
+        
addVmParams.setConsoleEnabled(deviceExists(VmDeviceGeneralType.CONSOLE, 
VmDeviceType.CONSOLE));
+        
addVmParams.setBalloonEnabled(deviceExists(VmDeviceGeneralType.BALLOON, 
VmDeviceType.BALLOON));
+        
addVmParams.setSoundDeviceEnabled(deviceExists(VmDeviceGeneralType.SOUND, 
VmDeviceType.SOUND));
+        
addVmParams.setVirtioScsiEnabled(deviceExists(VmDeviceGeneralType.CONTROLLER, 
VmDeviceType.VIRTIOSCSI));
+
+        List<VmWatchdog> watchdogs = 
getBackend().runInternalQuery(VdcQueryType.GetWatchdog,
+                new IdQueryParameters(getVmTemplateId())).getReturnValue();
+        if (!watchdogs.isEmpty()) {
+            addVmParams.setWatchdog(watchdogs.get(0));
+        }
+
+        if (!StringUtils.isEmpty(getParameters().getSessionId())) {
+            VmPayload payload = 
getBackend().runInternalQuery(VdcQueryType.GetVmPayload,
+                    new IdQueryParameters(getVmTemplateId())).getReturnValue();
+
+            if (payload != null) {
+                addVmParams.setVmPayload(payload);
+            }
+        }
+
+        // when this initiated from down vm event (restore stateless vm)
+        // then there is no session, so using the current user.
+        if (StringUtils.isEmpty(getParameters().getSessionId())) {
+            addVmParams.setParametersCurrentUser(getCurrentUser());
+        } else {
+            addVmParams.setSessionId(getParameters().getSessionId());
+        }
+        getBackend().runInternalAction(action, addVmParams,
+                
ExecutionHandler.createDefaultContexForTasks(getExecutionContext(), getLock()));
+    }
+
+    /**
+     * Copy fields that annotated with {@link CopyOnNewVersion} from the new 
template version to the vm
+     *
+     * @param source
+     *            - template to copy data from
+     * @param dest
+     *            - vm to copy data to
+     */
+    private boolean copyData(VmBase source, VmBase dest) {
+        for (Field srcFld : VmBase.class.getDeclaredFields()) {
+            try {
+                if (srcFld.getAnnotation(CopyOnNewVersion.class) != null) {
+                    srcFld.setAccessible(true);
+
+                    Field dstFld = 
VmBase.class.getDeclaredField(srcFld.getName());
+                    dstFld.setAccessible(true);
+                    dstFld.set(dest, srcFld.get(source));
+                }
+            } catch (Exception exp) {
+                log.errorFormat("Failed to copy field {0} of new version to VM 
{1} ({2}), error: {3}",
+                        srcFld.getName(),
+                        source.getName(),
+                        source.getId(),
+                        exp.getMessage());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean deviceExists(VmDeviceGeneralType generalType, VmDeviceType 
deviceType) {
+        return !getVmDeviceDao().getVmDeviceByVmIdTypeAndDevice(
+                getVmTemplateId(), generalType, 
deviceType.getName()).isEmpty();
+    }
+
+    @Override
+    protected Map<String, Pair<String, String>> getExclusiveLocks() {
+        return Collections.singletonMap(getVmId().toString(),
+                LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM, 
VdcBllMessages.ACTION_TYPE_FAILED_OBJECT_LOCKED));
+    }
+
+    @Override
+    protected Map<String, Pair<String, String>> getSharedLocks() {
+        // take shared lock on latest template, since we will add vm from it
+        if (getVm() != null) {
+            VmTemplate latest = 
getVmTemplateDAO().getTemplateWithLatestVersionInChain(getVm().getVmtGuid());
+            if (latest != null) {
+                setVmTemplateId(latest.getId());
+                setVmTemplate(latest);
+                return Collections.singletonMap(latest.getId().toString(),
+                        
LockMessagesMatchUtil.makeLockingPair(LockingGroup.TEMPLATE, 
VdcBllMessages.ACTION_TYPE_FAILED_OBJECT_LOCKED));
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void endVmCommand() {
+        addUpdatedVm();
+        setSucceeded(true);
+    }
+
+    @Override
+    protected void endWithFailure() {
+        // nothing to do
+    }
+}
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmCommand.java
index 5b2a615..f81e42a 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/VmCommand.java
@@ -210,7 +210,11 @@
     }
 
     protected void removeVmStatic() {
-        getVmStaticDAO().remove(getVmId());
+        removeVmStatic(true);
+    }
+
+    protected void removeVmStatic(boolean removePermissions) {
+        getVmStaticDAO().remove(getVmId(), removePermissions);
     }
 
     protected List<VmNic> getInterfaces() {
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/RemoveVmParameters.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/RemoveVmParameters.java
index aacebb9..6cd3e9d 100644
--- 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/RemoveVmParameters.java
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/RemoveVmParameters.java
@@ -7,6 +7,7 @@
     private static final long serialVersionUID = 4931085923357689965L;
     private boolean force;
     private boolean removeDisks;
+    private boolean removePermissions;
 
     public boolean getForce() {
         return force;
@@ -24,10 +25,19 @@
         this.removeDisks = removeDisks;
     }
 
+    public boolean isRemovePermissions() {
+        return removePermissions;
+    }
+
+    public void setRemovePermissions(boolean removePermissions) {
+        this.removePermissions = removePermissions;
+    }
+
     public RemoveVmParameters(Guid vmId, boolean force) {
         super(vmId);
         setForce(force);
         removeDisks = true;
+        removePermissions = true;
     }
 
     public RemoveVmParameters(Guid vmId, boolean force, boolean removeDisks) {
@@ -37,5 +47,6 @@
 
     public RemoveVmParameters() {
         removeDisks = true;
+        removePermissions = true;
     }
 }
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/UpdateVmVersionParameters.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/UpdateVmVersionParameters.java
new file mode 100644
index 0000000..73edc51
--- /dev/null
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/UpdateVmVersionParameters.java
@@ -0,0 +1,24 @@
+package org.ovirt.engine.core.common.action;
+
+import org.ovirt.engine.core.compat.Guid;
+
+public class UpdateVmVersionParameters extends VmManagementParametersBase {
+
+    private Guid vmPoolId;
+
+    public UpdateVmVersionParameters() {
+    }
+
+    public UpdateVmVersionParameters(Guid vmId) {
+        super();
+        setVmId(vmId);
+    }
+
+    public Guid getVmPoolId() {
+        return vmPoolId;
+    }
+
+    public void setVmPoolId(Guid vmPoolId) {
+        this.vmPoolId = vmPoolId;
+    }
+}
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java
index e567fd2..59ca73d 100644
--- 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java
@@ -51,6 +51,7 @@
     ActivateDeactivateVmNic(42, QuotaDependency.NONE),
     AddVmFromSnapshot(52, ActionGroup.CREATE_VM, QuotaDependency.BOTH),
     ImportVmFromConfiguration(43, ActionGroup.IMPORT_EXPORT_VM, 
QuotaDependency.NONE),
+    UpdateVmVersion(44, QuotaDependency.NONE),
     // VdsCommands
     AddVds(101, ActionGroup.CREATE_HOST, QuotaDependency.NONE),
     UpdateVds(102, ActionGroup.EDIT_HOST_CONFIGURATION, false, 
QuotaDependency.NONE),
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/CopyOnNewVersion.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/CopyOnNewVersion.java
new file mode 100644
index 0000000..b0e8645
--- /dev/null
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/CopyOnNewVersion.java
@@ -0,0 +1,16 @@
+package org.ovirt.engine.core.common.businessentities;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used to mark a field
+ * that need to be copied to vm, from a new template version
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CopyOnNewVersion {
+
+}
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmBase.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmBase.java
index b56f729..0f30c32 100644
--- 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmBase.java
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmBase.java
@@ -49,6 +49,7 @@
     @EditableOnTemplate
     private Guid vdsGroupId;
 
+    @CopyOnNewVersion
     @EditableField
     private int osId;
 
@@ -63,28 +64,34 @@
     @EditableField
     private String comment;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     private int memSizeMb;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     private int numOfSockets;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     private int cpuPerSocket;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     @IntegerContainedInConfigValueList(configValue = 
ConfigValues.ValidNumOfMonitors,
             message = "VALIDATION.VM.NUM_OF_MONITORS.EXCEEDED")
     private int numOfMonitors;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     private boolean singleQxlPci;
 
+    @CopyOnNewVersion
     @EditableField
     @Size(max = BusinessEntitiesDefinitions.GENERAL_DOMAIN_SIZE)
     private String domain;
@@ -94,28 +101,36 @@
     @Size(max = BusinessEntitiesDefinitions.GENERAL_TIME_ZONE_SIZE)
     private String timeZone;
 
+    @CopyOnNewVersion
     @EditableField
     private VmType vmType;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     private UsbPolicy usbPolicy;
 
+    @CopyOnNewVersion
     private boolean failBack;
 
+    @CopyOnNewVersion
     @EditableField
     private BootSequence defaultBootSequence;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     private int niceLevel;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     private int cpuShares;
 
+    @CopyOnNewVersion
     @EditableField
     private int priority;
 
+    @CopyOnNewVersion
     @EditableField
     private boolean autoStartup;
 
@@ -123,9 +138,11 @@
     @EditableOnTemplate
     private boolean stateless;
 
+    @CopyOnNewVersion
     @EditableField
     private boolean deleteProtected;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     private SsoMethod ssoMethod;
@@ -133,15 +150,18 @@
     @EditableField
     private long dbGeneration;
 
+    @CopyOnNewVersion
     @EditableField
     private boolean smartcardEnabled;
 
+    @CopyOnNewVersion
     @EditableField
     @Size(max = BusinessEntitiesDefinitions.GENERAL_MAX_SIZE)
     private String isoPath;
 
     private OriginType origin;
 
+    @CopyOnNewVersion
     @EditableField
     @Size(max = BusinessEntitiesDefinitions.GENERAL_MAX_SIZE)
     @Pattern(regexp = ValidationUtils.NO_TRIMMING_WHITE_SPACES_PATTERN,
@@ -149,6 +169,7 @@
                     UpdateEntity.class })
     private String kernelUrl;
 
+    @CopyOnNewVersion
     @EditableField
     @Size(max = BusinessEntitiesDefinitions.GENERAL_MAX_SIZE)
     @Pattern(regexp = ValidationUtils.NO_TRIMMING_WHITE_SPACES_PATTERN,
@@ -156,6 +177,7 @@
                     UpdateEntity.class })
     private String kernelParams;
 
+    @CopyOnNewVersion
     @EditableField
     @Size(max = BusinessEntitiesDefinitions.GENERAL_MAX_SIZE)
     @Pattern(regexp = ValidationUtils.NO_TRIMMING_WHITE_SPACES_PATTERN,
@@ -163,12 +185,14 @@
                     UpdateEntity.class })
     private String initrdUrl;
 
+    @CopyOnNewVersion
     @EditableField
     private boolean allowConsoleReconnect;
 
     /**
      * if this field is null then value should be taken from cluster
      */
+    @CopyOnNewVersion
     @EditableField
     private Boolean tunnelMigration;
 
@@ -229,11 +253,13 @@
     @EditableField
     private QuotaEnforcementTypeEnum quotaEnforcementType;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     @OvfExportOnlyField(valueToIgnore = "MIGRATABLE", exportOption = 
ExportOption.EXPORT_NON_IGNORED_VALUES)
     private MigrationSupport migrationSupport;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     private Guid dedicatedVmForVds;
@@ -242,6 +268,7 @@
     @EditableOnTemplate
     private DisplayType defaultDisplayType;
 
+    @CopyOnNewVersion
     @EditableOnVmStatusField
     @EditableOnTemplate
     @NullOrStringContainedInConfigValueList(configValue = 
ConfigValues.VncKeyboardLayoutValidValues,
@@ -249,9 +276,11 @@
         message = "VALIDATION.VM.INVALID_KEYBOARD_LAYOUT")
     private String vncKeyboardLayout;
 
+    @CopyOnNewVersion
     @EditableField
     private int minAllocatedMem;
 
+    @CopyOnNewVersion
     @EditableField
     private boolean runAndPause;
 
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java
index d867358..adfbdcb 100644
--- 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java
@@ -102,6 +102,7 @@
     VAR__ACTION__EXTEND_IMAGE_SIZE,
     VAR__ACTION__REMOVE_BRICKS_STOP,
     VAR__ACTION__REMOVE_BRICKS_COMMIT,
+    VAR__ACTION__UPDATE_VM_VERSION,
 
     // Host statuses replacements
     VAR__HOST_STATUS__UP,
@@ -161,6 +162,8 @@
     ACTION_TYPE_FAILED_CANNOT_USE_LATEST_WITH_CLONE(ErrorType.BAD_PARAMETERS),
     ACTION_TYPE_FAILED_VM_NOT_EXIST(ErrorType.BAD_PARAMETERS),
     ACTION_TYPE_FAILED_VM_ALREADY_EXIST(ErrorType.CONFLICT),
+    ACTION_TYPE_FAILED_VM_NOT_SET_FOR_LATEST(ErrorType.BAD_PARAMETERS),
+    ACTION_TYPE_FAILED_VM_ALREADY_IN_LATEST_VERSION(ErrorType.BAD_PARAMETERS),
     ACTION_TYPE_FAILED_VM_GUID_ALREADY_EXIST(ErrorType.CONFLICT),
     ACTION_TYPE_FAILED_VM_ATTACHED_TO_POOL(ErrorType.CONFLICT),
     ACTION_TYPE_FAILED_VM_STATUS_ILLEGAL(ErrorType.CONFLICT),
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAO.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAO.java
index 9e2ac37..7c3a3e3 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAO.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAO.java
@@ -290,4 +290,15 @@
      * @return
      */
     List<VM> getAllRunningByCluster(Guid clusterId);
+
+    /**
+     * Retrieves all ids of vms that are candidate for version update for this 
base template:
+     * template_version_number is set to null
+     * status is down
+     * vm is stateless or belong to vm pool
+     * (for vm in pool, check there is no stateless snapshot for it [manual 
pool])
+     *
+     * @return the list of ids of these vms
+     */
+    List<Guid> getVmIdsForVersionUpdate(Guid baseTemplateId);
 }
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAODbFacadeImpl.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAODbFacadeImpl.java
index d1349dc..8984322 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAODbFacadeImpl.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmDAODbFacadeImpl.java
@@ -277,6 +277,13 @@
                         .addValue("cluster_id", clusterId));
     }
 
+    @Override
+    public List<Guid> getVmIdsForVersionUpdate(Guid baseTemplateId) {
+        return getCallsHandler().executeReadList("getVmIdsForVersionUpdate",
+                createGuidMapper(), getCustomMapSqlParameterSource()
+                    .addValue("base_template_id", baseTemplateId));
+    }
+
     static final class VMRowMapper implements RowMapper<VM> {
         public static final VMRowMapper instance = new VMRowMapper();
 
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAO.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAO.java
index 073abc4..9dfa337 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAO.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAO.java
@@ -85,4 +85,11 @@
     public void incrementDbGeneration(Guid id);
 
     List<Guid> getOrderedVmGuidsForRunMultipleActions(List<Guid> guids);
+
+    /**
+     * remove with optionally remove/keep vm permissions
+     * @param id vm to remove
+     * @param removePermissions flag to indicate if to remove the permissions 
or keep them
+     */
+    public void remove(Guid id, boolean removePermissions);
 }
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAODbFacadeImpl.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAODbFacadeImpl.java
index 6552eb1..69328e7 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAODbFacadeImpl.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/VmStaticDAODbFacadeImpl.java
@@ -104,7 +104,13 @@
 
     @Override
     public void remove(Guid id) {
-        getCallsHandler().executeModification("DeleteVmStatic", 
getIdParamterSource(id));
+        remove(id, true);
+    }
+
+    public void remove(Guid id, boolean removePermissions) {
+        getCallsHandler().executeModification("DeleteVmStatic",
+                getIdParamterSource(id)
+                        .addValue("remove_permissions", removePermissions));
     }
 
     private MapSqlParameterSource getIdParamterSource(Guid id) {
@@ -179,7 +185,7 @@
     public Long getDbGeneration(Guid id) {
         return getCallsHandler().executeRead("GetDbGeneration", getLongMapper()
                 , getCustomMapSqlParameterSource()
-                        .addValue("vm_guid", id));
+                .addValue("vm_guid", id));
     }
 
     public List<Guid> getOrderedVmGuidsForRunMultipleActions(List<Guid> guids) 
{
diff --git 
a/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties 
b/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties
index 3c97e10..1307857 100644
--- 
a/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties
+++ 
b/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties
@@ -173,6 +173,8 @@
 ACTION_TYPE_FAILED_VM_IN_USE_BY_OTHER_USER=Cannot ${action} ${type}. The VM is 
in use by other user.
 ACTION_TYPE_FAILED_VM_NOT_FOUND=Cannot ${action} ${type}. VM is not found.
 ACTION_TYPE_FAILED_CANNOT_USE_LATEST_WITH_CLONE=Cannot ${action} ${type}. 
Cannot use 'Latest Version' when using clone from Template.
+ACTION_TYPE_FAILED_VM_NOT_SET_FOR_LATEST=Cannot ${action} ${type}. Vm is set 
to use a specific version, and not automatically update to the latest version.
+ACTION_TYPE_FAILED_VM_ALREADY_IN_LATEST_VERSION=Cannot ${action} ${type}. Vm 
is already at the latest version.
 ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE=Cannot ${action} ${type}. VM is non 
migratable.
 
ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE_AND_IS_NOT_FORCED_BY_USER_TO_MIGRATE=Cannot
 ${action} ${type}. VM is non migratable and user did not specify the 
force-migration flag
 ACTION_TYPE_FAILED_VM_IS_PINNED_TO_HOST=Cannot ${action} ${type}. VM is pinned 
to Host.
@@ -332,6 +334,7 @@
 VAR__ACTION__SCAN_ALIGNMENT=$action scan alignment
 VAR__ACTION__FORCE_SELECT=$action force select
 VAR__ACTION__EXTEND_IMAGE_SIZE=$action extend
+VAR__ACTION__UPDATE_VM_VERSION=$action update version for
 VAR__HOST_STATUS__UP=$hostStatus Up
 VAR__HOST_STATUS__UP_MAINTENANCE_OR_NON_OPERATIONAL=$hostStatus Up, 
Maintenance or Non operational
 VAR__HOST_STATUS__UP_OR_MAINTENANCE=$hostStatus 'Up' or 'Maintenance'
diff --git 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDAOTest.java
 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDAOTest.java
index 85e57e8..78a97b3 100644
--- 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDAOTest.java
+++ 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmDAOTest.java
@@ -27,6 +27,7 @@
     private static final Guid USER_ID = new 
Guid("9bf7c640-b620-456f-a550-0348f366544b");
     private static final Guid STORAGE_DOMAIN_ID = new 
Guid("72e3a666-89e1-4005-a7ca-f7548004a9ab");
     private static final Guid POOL_ID = new 
Guid("103cfd1d-18b1-4790-8a0c-1e52621b0076");
+    private static final Guid VM_TO_UPDATE_ID = new 
Guid("77296e00-0cad-4e5a-9299-008a7b6f5002");
 
     private static final int VM_COUNT = 7;
     private VmDAO dao;
@@ -500,4 +501,11 @@
         assertNotNull(result);
         assertFalse(result.isEmpty());
     }
+
+    @Test
+    public void testGetVmIdsForVersionUpdate() {
+        List<Guid> vmIdsToUpdate = 
dao.getVmIdsForVersionUpdate(FixturesTool.VM_TEMPLATE_RHEL5);
+
+        assertTrue(vmIdsToUpdate.contains(VM_TO_UPDATE_ID));
+    }
 }
diff --git 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmStaticDAOTest.java
 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmStaticDAOTest.java
index 07a99d9..0d27169 100644
--- 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmStaticDAOTest.java
+++ 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/VmStaticDAOTest.java
@@ -181,6 +181,24 @@
         dao.remove(EXISTING_VM_ID);
         VmStatic result = dao.get(EXISTING_VM_ID);
         assertNull(result);
+        PermissionDAO permissionsDao = dbFacade.getPermissionDao();
+        assertEquals("vm permissions wasn't removed", 0, 
permissionsDao.getAllForEntity(EXISTING_VM_ID).size());
+    }
+
+    @Test
+    public void testRemoveWithoutPermissions() {
+        for (Snapshot s : dbFacade.getSnapshotDao().getAll()) {
+            dbFacade.getSnapshotDao().remove(s.getId());
+        }
+
+        PermissionDAO permissionsDao = dbFacade.getPermissionDao();
+        int numberOfPermissionsBeforeRemove = 
permissionsDao.getAllForEntity(EXISTING_VM_ID).size();
+
+        dao.remove(EXISTING_VM_ID, false);
+        VmStatic result = dao.get(EXISTING_VM_ID);
+        assertNull(result);
+
+        assertEquals("vm permissions changed during remove although shouldnt 
have.", numberOfPermissionsBeforeRemove, 
permissionsDao.getAllForEntity(EXISTING_VM_ID).size());
     }
 
     @Test
diff --git a/backend/manager/modules/dal/src/test/resources/fixtures.xml 
b/backend/manager/modules/dal/src/test/resources/fixtures.xml
index bf4d6d0..bf8bf30 100644
--- a/backend/manager/modules/dal/src/test/resources/fixtures.xml
+++ b/backend/manager/modules/dal/src/test/resources/fixtures.xml
@@ -2362,7 +2362,7 @@
             <null />
             <value>1</value>
             <value></value>
-            <value>0</value>
+            <value>1</value>
             <value>1</value>
             <value>2010-11-18 11:13:24</value>
             <null />
diff --git 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
index 3825f02..5801437 100644
--- 
a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
+++ 
b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java
@@ -445,6 +445,12 @@
     @DefaultStringValue("Cannot ${action} ${type}. Cannot use 'Latest Version' 
when using clone from Template.")
     String ACTION_TYPE_FAILED_CANNOT_USE_LATEST_WITH_CLONE();
 
+    @DefaultStringValue("Cannot ${action} ${type}. Vm is set to use a specific 
version, and not automatically update to the latest version.")
+    String ACTION_TYPE_FAILED_VM_NOT_SET_FOR_LATEST();
+
+    @DefaultStringValue("Cannot ${action} ${type}. Vm is already at the latest 
version.")
+    String ACTION_TYPE_FAILED_VM_ALREADY_IN_LATEST_VERSION();
+
     @DefaultStringValue("Cannot ${action} ${type}. VM is non migratable.")
     String ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE();
 
@@ -910,6 +916,9 @@
     @DefaultStringValue("$action disable")
     String VAR__ACTION__DISABLE();
 
+    @DefaultStringValue("$action update version for")
+    String VAR__ACTION__UPDATE_VM_VERSION();
+
     @DefaultStringValue("$hostStatus Up")
     String VAR__HOST_STATUS__UP();
 
diff --git 
a/frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
 
b/frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
index 5149a20..bae94da 100644
--- 
a/frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
+++ 
b/frontend/webadmin/modules/userportal-gwtp/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
@@ -166,6 +166,8 @@
 ACTION_TYPE_FAILED_VM_IN_USE_BY_OTHER_USER=Cannot ${action} ${type}. The VM is 
in use by other user.
 ACTION_TYPE_FAILED_VM_NOT_FOUND=Cannot ${action} ${type}. VM is not found.
 ACTION_TYPE_FAILED_CANNOT_USE_LATEST_WITH_CLONE=Cannot ${action} ${type}. 
Cannot use 'Latest Version' when using clone from Template.
+ACTION_TYPE_FAILED_VM_NOT_SET_FOR_LATEST=Cannot ${action} ${type}. Vm is set 
to use a specific version, and not automatically update to the latest version.
+ACTION_TYPE_FAILED_VM_ALREADY_IN_LATEST_VERSION=Cannot ${action} ${type}. Vm 
is already at the latest version.
 ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE=Cannot ${action} ${type}. VM is non 
migratable.
 
ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE_AND_IS_NOT_FORCED_BY_USER_TO_MIGRATE=Cannot
 ${action} ${type}. VM is non migratable and user did not specify the 
force-migration flag
 ACTION_TYPE_FAILED_VM_IS_PINNED_TO_HOST=Cannot ${action} ${type}. VM is pinned 
to Host.
@@ -311,6 +313,7 @@
 VAR__ACTION__ASSIGN=$action assign
 VAR__ACTION__SCAN_ALIGNMENT=$action scan alignment
 VAR__ACTION__EXTEND_IMAGE_SIZE=$action extend
+VAR__ACTION__UPDATE_VM_VERSION=$action update version for
 VAR__HOST_STATUS__UP=$hostStatus Up
 VAR__HOST_STATUS__UP_MAINTENANCE_OR_NON_OPERATIONAL=$hostStatus Up, 
Maintenance or Non operational
 VAR__HOST_STATUS__UP_OR_MAINTENANCE=$hostStatus 'Up' or 'Maintenance'
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
 
b/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
index 8f3559c..3e7aa6e 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
+++ 
b/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/frontend/AppErrors.properties
@@ -170,6 +170,8 @@
 ACTION_TYPE_FAILED_VM_IN_USE_BY_OTHER_USER=Cannot ${action} ${type}. The VM is 
in use by other user.
 ACTION_TYPE_FAILED_VM_NOT_FOUND=Cannot ${action} ${type}. VM is not found.
 ACTION_TYPE_FAILED_CANNOT_USE_LATEST_WITH_CLONE=Cannot ${action} ${type}. 
Cannot use 'Latest Version' when using clone from Template.
+ACTION_TYPE_FAILED_VM_NOT_SET_FOR_LATEST=Cannot ${action} ${type}. Vm is set 
to use a specific version, and not automatically update to the latest version.
+ACTION_TYPE_FAILED_VM_ALREADY_IN_LATEST_VERSION=Cannot ${action} ${type}. Vm 
is already at the latest version.
 ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE=Cannot ${action} ${type}. VM is non 
migratable.
 
ACTION_TYPE_FAILED_VM_IS_NON_MIGRTABLE_AND_IS_NOT_FORCED_BY_USER_TO_MIGRATE=Cannot
 ${action} ${type}. VM is non migratable and user did not specify the 
force-migration flag
 ACTION_TYPE_FAILED_VM_IS_PINNED_TO_HOST=Cannot ${action} ${type}. VM is pinned 
to Host.
@@ -335,6 +337,7 @@
 VAR__ACTION__SCAN_ALIGNMENT=$action scan alignment
 VAR__ACTION__FORCE_SELECT=$action force select
 VAR__ACTION__EXTEND_IMAGE_SIZE=$action extend
+VAR__ACTION__UPDATE_VM_VERSION=$action update version for
 VAR__HOST_STATUS__UP=$hostStatus Up
 VAR__HOST_STATUS__UP_MAINTENANCE_OR_NON_OPERATIONAL=$hostStatus Up, 
Maintenance or Non operational
 VAR__HOST_STATUS__UP_OR_MAINTENANCE=$hostStatus 'Up' or 'Maintenance'
diff --git a/packaging/dbscripts/vms_sp.sql b/packaging/dbscripts/vms_sp.sql
index 10bed79..5c2cde2 100644
--- a/packaging/dbscripts/vms_sp.sql
+++ b/packaging/dbscripts/vms_sp.sql
@@ -620,7 +620,7 @@
 
 
 
-Create or replace FUNCTION DeleteVmStatic(v_vm_guid UUID)
+Create or replace FUNCTION DeleteVmStatic(v_vm_guid UUID, v_remove_permissions 
boolean)
 RETURNS VOID
    AS $procedure$
    DECLARE
@@ -634,7 +634,9 @@
       AND   entity_type = 'VM';
 
                        -- delete VM permissions --
-      DELETE FROM permissions where object_id = v_vm_guid;
+      if v_remove_permissions then
+        DELETE FROM permissions where object_id = v_vm_guid;
+      end if;
 END; $procedure$
 LANGUAGE plpgsql;
 
@@ -1154,3 +1156,22 @@
 END; $procedure$
 LANGUAGE plpgsql;
 
+
+Create or replace FUNCTION GetVmIdsForVersionUpdate(v_base_template_id UUID) 
RETURNS SETOF UUID STABLE
+AS $procedure$
+BEGIN
+RETURN QUERY select vs.vm_guid
+             from vm_static vs
+               natural join vm_dynamic
+             where (vmt_guid = v_base_template_id or vmt_guid in
+                          (select vm_guid from vm_static where vmt_guid = 
v_base_template_id))
+               and template_version_number is null and entity_type='VM' and 
status=0
+                   and (is_stateless = TRUE or
+                        (exists (select * from vm_pool_map where vm_guid = 
vs.vm_guid)
+                         and not exists
+                        (SELECT *
+                         FROM   snapshots
+                         WHERE  vm_id = vs.vm_guid
+                                AND    snapshot_type = 'STATELESS')));
+END; $procedure$
+LANGUAGE plpgsql;


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

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

Reply via email to