This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 11df71e55cc8d5cd709d3c7b99f432ee8dce2974
Merge: 7324ef45d46 ae5308bdd20
Author: Daan Hoogland <[email protected]>
AuthorDate: Tue Feb 17 11:52:39 2026 +0100

    Merge branch '4.20' into '4.22'

 .../cloudstack/backup/RestoreBackupCommand.java    |  18 +--
 .../java/com/cloud/resource/ResourceManager.java   |   2 +
 .../java/com/cloud/dc/ClusterDetailsDaoImpl.java   |   2 +-
 .../com/cloud/dc/dao/DataCenterDetailsDaoImpl.java |   2 +-
 .../main/java/com/cloud/host/dao/HostDaoImpl.java  |   2 +-
 .../storage/datastore/db/ImageStoreDaoImpl.java    |   2 +-
 .../src/main/java/com/cloud/utils/db/Filter.java   |  13 +-
 .../java/com/cloud/utils/db/GenericDaoBase.java    |   6 +-
 .../test/java/com/cloud/utils/db/FilterTest.java   |  58 +++++++
 .../com/cloud/utils/db/GenericDaoBaseTest.java     |  68 ++++++++
 .../apache/cloudstack/quota/QuotaManagerImpl.java  |  12 +-
 .../activationrule/presetvariables/Account.java    |   2 -
 .../presetvariables/BackupOffering.java            |   1 -
 .../presetvariables/ComputeOffering.java           |   3 -
 .../presetvariables/Configuration.java             |   1 -
 .../DiskOfferingPresetVariables.java               |  12 --
 .../activationrule/presetvariables/Domain.java     |   1 -
 .../presetvariables/GenericPresetVariable.java     |  18 +--
 .../quota/activationrule/presetvariables/Host.java |   2 -
 .../presetvariables/PresetVariableHelper.java      |  12 +-
 .../quota/activationrule/presetvariables/Role.java |   9 +-
 .../activationrule/presetvariables/Storage.java    |  11 +-
 .../activationrule/presetvariables/Tariff.java     |   1 -
 .../activationrule/presetvariables/Value.java      |  48 ++----
 .../cloudstack/quota/QuotaManagerImplTest.java     |  24 +--
 .../presetvariables/AccountTest.java               |  34 ----
 .../presetvariables/BackupOfferingTest.java        |  36 -----
 .../presetvariables/ComputeOfferingTest.java       |  35 -----
 .../presetvariables/ComputingResourcesTest.java    |  40 -----
 .../activationrule/presetvariables/DomainTest.java |  35 -----
 .../presetvariables/GenericPresetVariableTest.java |  73 ---------
 .../activationrule/presetvariables/HostTest.java   |  34 ----
 .../presetvariables/PresetVariableHelperTest.java  | 134 +++++-----------
 .../presetvariables/ResourceTest.java              |  40 -----
 .../activationrule/presetvariables/RoleTest.java   |  34 ----
 .../presetvariables/StorageTest.java               |  41 -----
 .../activationrule/presetvariables/ValueTest.java  | 175 ---------------------
 .../cloudstack/backup/NASBackupProvider.java       |  30 +++-
 .../LibvirtRestoreBackupCommandWrapper.java        |  67 ++++----
 .../LibvirtRestoreBackupCommandWrapperTest.java    |  19 ++-
 .../cloudstack/metrics/PrometheusExporterImpl.java |  43 +++++
 .../metrics/PrometheusExporterImplTest.java        | 108 +++++++++++++
 .../com/cloud/resource/ResourceManagerImpl.java    |  27 +++-
 .../storage/heuristics/HeuristicRuleHelper.java    |  20 +--
 .../heuristics/presetvariables/Account.java        |   2 -
 .../storage/heuristics/presetvariables/Domain.java |   1 -
 .../GenericHeuristicPresetVariable.java            |  17 +-
 .../presetvariables/SecondaryStorage.java          |   4 -
 .../heuristics/presetvariables/Snapshot.java       |  10 +-
 .../heuristics/presetvariables/Template.java       |  24 ++-
 .../storage/heuristics/presetvariables/Volume.java |  10 +-
 .../cloud/resource/MockResourceManagerImpl.java    |   5 +
 .../heuristics/HeuristicRuleHelperTest.java        |  16 ++
 .../heuristics/presetvariables/AccountTest.java    |  46 ------
 .../heuristics/presetvariables/DomainTest.java     |  41 -----
 .../GenericHeuristicPresetVariableTest.java        |  40 -----
 .../presetvariables/SecondaryStorageTest.java      |  45 ------
 .../heuristics/presetvariables/SnapshotTest.java   |  44 ------
 .../heuristics/presetvariables/TemplateTest.java   |  46 ------
 .../heuristics/presetvariables/VolumeTest.java     |  44 ------
 .../storage/template/UploadManagerImpl.java        |  51 +++++-
 .../storage/template/UploadManagerImplTest.java    |  85 ++++++++++
 .../java/com/cloud/usage/UsageManagerImpl.java     |  20 ++-
 .../utils/jsinterpreter/JsInterpreter.java         |  33 ++--
 .../utils/jsinterpreter/TagAsRuleHelper.java       |  21 ++-
 .../utils/jsinterpreter/JsInterpreterTest.java     |  18 ---
 66 files changed, 710 insertions(+), 1268 deletions(-)

diff --cc 
core/src/main/java/org/apache/cloudstack/backup/RestoreBackupCommand.java
index 8e68f4f1e41,0bc6865d9e5..f5ad5fbea2c
--- a/core/src/main/java/org/apache/cloudstack/backup/RestoreBackupCommand.java
+++ b/core/src/main/java/org/apache/cloudstack/backup/RestoreBackupCommand.java
@@@ -31,14 -30,11 +31,14 @@@ public class RestoreBackupCommand exten
      private String backupPath;
      private String backupRepoType;
      private String backupRepoAddress;
 -    private List<String> volumePaths;
 +    private List<String> backupVolumesUUIDs;
 +    private List<PrimaryDataStoreTO> restoreVolumePools;
 +    private List<String> restoreVolumePaths;
+     private List<String> backupFiles;
      private String diskType;
      private Boolean vmExists;
-     private String restoreVolumeUUID;
      private VirtualMachine.State vmState;
 +    private Integer mountTimeout;
  
      protected RestoreBackupCommand() {
          super();
@@@ -76,22 -72,22 +76,30 @@@
          this.backupRepoAddress = backupRepoAddress;
      }
  
 -    public List<String> getVolumePaths() {
 -        return volumePaths;
 +    public List<PrimaryDataStoreTO> getRestoreVolumePools() {
 +        return restoreVolumePools;
      }
  
 -    public void setVolumePaths(List<String> volumePaths) {
 -        this.volumePaths = volumePaths;
 +    public void setRestoreVolumePools(List<PrimaryDataStoreTO> 
restoreVolumePools) {
 +        this.restoreVolumePools = restoreVolumePools;
 +    }
 +
 +    public List<String> getRestoreVolumePaths() {
 +        return restoreVolumePaths;
 +    }
 +
 +    public void setRestoreVolumePaths(List<String> restoreVolumePaths) {
 +        this.restoreVolumePaths = restoreVolumePaths;
      }
  
+     public List<String> getBackupFiles() {
+         return backupFiles;
+     }
+ 
+     public void setBackupFiles(List<String> backupFiles) {
+         this.backupFiles = backupFiles;
+     }
+ 
      public Boolean isVmExists() {
          return vmExists;
      }
diff --cc engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
index 8f218841b07,8c3604d352b..2d8fcca6cdb
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
@@@ -1385,34 -1343,12 +1385,34 @@@ public class HostDaoImpl extends Generi
          return listBy(sc);
      }
  
 +    @Override
 +    public List<HostVO> findHypervisorHostInZone(long zoneId) {
 +        SearchCriteria<HostVO> sc = TypeStatusStateSearch.create();
 +        sc.setParameters("type", Host.Type.Routing);
 +        sc.setParameters("zone", zoneId);
 +        sc.setParameters("status", Status.Up);
 +        sc.setParameters("resourceState", ResourceState.Enabled);
 +
 +        return listBy(sc);
 +    }
 +
 +    @Override
 +    public List<HostVO> findHypervisorHostInPod(long podId) {
 +        SearchCriteria<HostVO> sc = TypeStatusStateSearch.create();
 +        sc.setParameters("type", Host.Type.Routing);
 +        sc.setParameters("pod", podId);
 +        sc.setParameters("status", Status.Up);
 +        sc.setParameters("resourceState", ResourceState.Enabled);
 +
 +        return listBy(sc);
 +    }
 +
      @Override
      public HostVO findAnyStateHypervisorHostInCluster(long clusterId) {
 -        SearchCriteria<HostVO> sc = TypeClusterStatusSearch.create();
 +        SearchCriteria<HostVO> sc = TypeStatusStateSearch.create();
          sc.setParameters("type", Host.Type.Routing);
          sc.setParameters("cluster", clusterId);
-         List<HostVO> list = listBy(sc, new Filter(1));
+         List<HostVO> list = listBy(sc, new Filter(1, true));
          return list.isEmpty() ? null : list.get(0);
      }
  
diff --cc 
framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java
index 7949259bc82,7c3eaead63f..816144aa2f1
--- 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java
+++ 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java
@@@ -468,14 -467,9 +468,14 @@@ public class QuotaManagerImpl extends M
  
          }
  
 +        Configuration configuration = presetVariables.getConfiguration();
 +        if (configuration != null) {
 +            jsInterpreter.injectVariable("configuration", 
configuration.toString());
 +        }
 +
          jsInterpreter.injectVariable("resourceType", 
presetVariables.getResourceType());
-         jsInterpreter.injectVariable("value", 
presetVariables.getValue().toString());
-         jsInterpreter.injectVariable("zone", 
presetVariables.getZone().toString());
+         jsInterpreter.injectVariable("value", presetVariables.getValue());
+         jsInterpreter.injectVariable("zone", presetVariables.getZone());
      }
  
      /**
diff --cc 
framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Account.java
index 2420d577f10,289958fe447..e34c8d3f31d
--- 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Account.java
+++ 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Account.java
@@@ -36,15 -28,6 +36,13 @@@ public class Account extends GenericPre
  
      public void setRole(Role role) {
          this.role = role;
-         fieldNamesToIncludeInToString.add("role");
      }
  
 +    public String getCreated() {
 +        return created;
 +    }
 +
 +    public void setCreated(Date created) {
 +        this.created = 
DateUtil.displayDateInTimezone(TimeZone.getTimeZone("GMT"), created);
-         fieldNamesToIncludeInToString.add("created");
 +    }
  }
diff --cc 
framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/ComputeOffering.java
index 09182711ca8,9f9575052d3..74cb695010b
--- 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/ComputeOffering.java
+++ 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/ComputeOffering.java
@@@ -32,16 -27,6 +32,13 @@@ public class ComputeOffering extends Ge
  
      public void setCustomized(boolean customized) {
          this.customized = customized;
-         fieldNamesToIncludeInToString.add("customized");
      }
  
 +    public boolean offerHa() {
 +        return offerHa;
 +    }
 +
 +    public void setOfferHa(boolean offerHa) {
 +        this.offerHa = offerHa;
-         fieldNamesToIncludeInToString.add("offerHa");
 +    }
- 
  }
diff --cc 
framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Configuration.java
index e59f78af8d9,00000000000..48fee552c5a
mode 100644,000000..100644
--- 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Configuration.java
+++ 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Configuration.java
@@@ -1,35 -1,0 +1,34 @@@
 +// Licensed to the Apache Software Foundation (ASF) under one
 +// or more contributor license agreements.  See the NOTICE file
 +// distributed with this work for additional information
 +// regarding copyright ownership.  The ASF licenses this file
 +// to you under the Apache License, Version 2.0 (the
 +// "License"); you may not use this file except in compliance
 +// with the License.  You may obtain a copy of the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing,
 +// software distributed under the License is distributed on an
 +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +// KIND, either express or implied.  See the License for the
 +// specific language governing permissions and limitations
 +// under the License.
 +
 +package org.apache.cloudstack.quota.activationrule.presetvariables;
 +
 +import org.apache.cloudstack.quota.constant.QuotaTypes;
 +
 +public class Configuration extends GenericPresetVariable{
 +
 +    @PresetVariableDefinition(description = "A boolean informing if the 
cluster configuration force.ha is enabled or not.", supportedTypes = 
{QuotaTypes.RUNNING_VM})
 +    private boolean forceHa;
 +
 +    public boolean getForceHa() {
 +        return forceHa;
 +    }
 +
 +    public void setForceHa(boolean forceHa) {
 +        this.forceHa = forceHa;
-         fieldNamesToIncludeInToString.add("forceHa");
 +    }
 +}
diff --cc 
framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/DiskOfferingPresetVariables.java
index b2f5f69502f,00000000000..68ba6a331eb
mode 100644,000000..100644
--- 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/DiskOfferingPresetVariables.java
+++ 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/DiskOfferingPresetVariables.java
@@@ -1,165 -1,0 +1,153 @@@
 +// Licensed to the Apache Software Foundation (ASF) under one
 +// or more contributor license agreements.  See the NOTICE file
 +// distributed with this work for additional information
 +// regarding copyright ownership.  The ASF licenses this file
 +// to you under the Apache License, Version 2.0 (the
 +// "License"); you may not use this file except in compliance
 +// with the License.  You may obtain a copy of the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing,
 +// software distributed under the License is distributed on an
 +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +// KIND, either express or implied.  See the License for the
 +// specific language governing permissions and limitations
 +// under the License.
 +
 +package org.apache.cloudstack.quota.activationrule.presetvariables;
 +
 +public class DiskOfferingPresetVariables extends GenericPresetVariable {
 +
 +    @PresetVariableDefinition(description = "A long informing the bytes read 
rate of the disk offering.")
 +    private Long bytesReadRate;
 +
 +    @PresetVariableDefinition(description = "A long informing the burst bytes 
read rate of the disk offering.")
 +    private Long bytesReadBurst;
 +
 +    @PresetVariableDefinition(description = "The length (in seconds) of the 
bytes read burst.")
 +    private Long bytesReadBurstLength;
 +
 +    @PresetVariableDefinition(description = "A long informing the bytes write 
rate of the disk offering.")
 +    private Long bytesWriteRate;
 +
 +    @PresetVariableDefinition(description = "A long informing the burst bytes 
write rate of the disk offering.")
 +    private Long bytesWriteBurst;
 +
 +    @PresetVariableDefinition(description = "The length (in seconds) of the 
bytes write burst.")
 +    private Long bytesWriteBurstLength;
 +
 +    @PresetVariableDefinition(description = "A long informing the I/O 
requests read rate of the disk offering.")
 +    private Long iopsReadRate;
 +
 +    @PresetVariableDefinition(description = "A long informing the burst I/O 
requests read rate of the disk offering.")
 +    private Long iopsReadBurst;
 +
 +    @PresetVariableDefinition(description = "The length (in seconds) of the 
IOPS read burst.")
 +    private Long iopsReadBurstLength;
 +
 +    @PresetVariableDefinition(description = "A long informing the I/O 
requests write rate of the disk offering.")
 +    private Long iopsWriteRate;
 +
 +    @PresetVariableDefinition(description = "A long informing the burst I/O 
requests write rate of the disk offering.")
 +    private Long iopsWriteBurst;
 +
 +    @PresetVariableDefinition(description = "The length (in seconds) of the 
IOPS write burst.")
 +    private Long iopsWriteBurstLength;
 +
 +    public Long getBytesReadRate() {
 +        return bytesReadRate;
 +    }
 +
 +    public void setBytesReadRate(Long bytesReadRate) {
 +        this.bytesReadRate = bytesReadRate;
-         fieldNamesToIncludeInToString.add("bytesReadRate");
 +    }
 +
 +    public Long getBytesReadBurst() {
 +        return bytesReadBurst;
 +    }
 +
 +    public void setBytesReadBurst(Long bytesReadBurst) {
 +        this.bytesReadBurst = bytesReadBurst;
-         fieldNamesToIncludeInToString.add("bytesReadBurst");
 +    }
 +
 +    public Long getBytesReadBurstLength() {
 +        return bytesReadBurstLength;
 +    }
 +
 +    public void setBytesReadBurstLength(Long bytesReadBurstLength) {
 +        this.bytesReadBurstLength = bytesReadBurstLength;
-         fieldNamesToIncludeInToString.add("bytesReadBurstLength");
 +    }
 +
 +    public Long getBytesWriteRate() {
 +        return bytesWriteRate;
 +    }
 +
 +    public void setBytesWriteRate(Long bytesWriteRate) {
 +        this.bytesWriteRate = bytesWriteRate;
-         fieldNamesToIncludeInToString.add("bytesWriteRate");
 +    }
 +
 +    public Long getBytesWriteBurst() {
 +        return bytesWriteBurst;
 +    }
 +
 +    public void setBytesWriteBurst(Long bytesWriteBurst) {
 +        this.bytesWriteBurst = bytesWriteBurst;
-         fieldNamesToIncludeInToString.add("bytesWriteBurst");
 +    }
 +
 +    public Long getBytesWriteBurstLength() {
 +        return bytesWriteBurstLength;
 +    }
 +
 +    public void setBytesWriteBurstLength(Long bytesWriteBurstLength) {
 +        this.bytesWriteBurstLength = bytesWriteBurstLength;
-         fieldNamesToIncludeInToString.add("bytesWriteBurstLength");
 +    }
 +
 +    public Long getIopsReadRate() {
 +        return iopsReadRate;
 +    }
 +
 +    public void setIopsReadRate(Long iopsReadRate) {
 +        this.iopsReadRate = iopsReadRate;
-         fieldNamesToIncludeInToString.add("iopsReadRate");
 +    }
 +
 +    public Long getIopsReadBurst() {
 +        return iopsReadBurst;
 +    }
 +
 +    public void setIopsReadBurst(Long iopsReadBurst) {
 +        this.iopsReadBurst = iopsReadBurst;
-         fieldNamesToIncludeInToString.add("iopsReadBurst");
 +    }
 +
 +    public Long getIopsReadBurstLength() {
 +        return iopsReadBurstLength;
 +    }
 +
 +    public void setIopsReadBurstLength(Long iopsReadBurstLength) {
 +        this.iopsReadBurstLength = iopsReadBurstLength;
-         fieldNamesToIncludeInToString.add("iopsReadBurstLength");
 +    }
 +
 +    public Long getIopsWriteRate() {
 +        return iopsWriteRate;
 +    }
 +
 +    public void setIopsWriteRate(Long iopsWriteRate) {
 +        this.iopsWriteRate = iopsWriteRate;
-         fieldNamesToIncludeInToString.add("iopsWriteRate");
 +    }
 +
 +    public Long getIopsWriteBurst() {
 +        return iopsWriteBurst;
 +    }
 +
 +    public void setIopsWriteBurst(Long iopsWriteBurst) {
 +        this.iopsWriteBurst = iopsWriteBurst;
-         fieldNamesToIncludeInToString.add("iopsWriteBurst");
 +    }
 +
 +    public Long getIopsWriteBurstLength() {
 +        return iopsWriteBurstLength;
 +    }
 +
 +    public void setIopsWriteBurstLength(Long iopsWriteBurstLength) {
 +        this.iopsWriteBurstLength = iopsWriteBurstLength;
-         fieldNamesToIncludeInToString.add("iopsWriteBurstLength");
 +    }
 +}
diff --cc 
framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelper.java
index 2a6ad132f63,918cf78b4e6..a2fca7b80fd
--- 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelper.java
+++ 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelper.java
@@@ -538,8 -490,7 +538,8 @@@ public class PresetVariableHelper 
          
value.setDiskOffering(getPresetVariableValueDiskOffering(volumeVo.getDiskOfferingId()));
          value.setId(volumeVo.getUuid());
          value.setName(volumeVo.getName());
-         value.setProvisioningType(volumeVo.getProvisioningType());
-         value.setVolumeType(volumeVo.getVolumeType());
++        value.setVolumeType(volumeVo.getVolumeType().toString());
+         value.setProvisioningType(volumeVo.getProvisioningType().toString());
  
          Long poolId = volumeVo.getPoolId();
          if (poolId == null) {
diff --cc 
framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Value.java
index 77e539db0f3,98f9c2678a8..ac776d13c57
--- 
a/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Value.java
+++ 
b/framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Value.java
@@@ -94,10 -90,6 +90,10 @@@ public class Value extends GenericPrese
  
      @PresetVariableDefinition(description = "The volume format. Values can 
be: RAW, VHD, VHDX, OVA and QCOW2.", supportedTypes = {QuotaTypes.VOLUME, 
QuotaTypes.VOLUME_SECONDARY})
      private String volumeFormat;
 +
 +    @PresetVariableDefinition(description = "The volume type. Values can be: 
UNKNOWN, ROOT, SWAP, DATADISK and ISO.", supportedTypes = {QuotaTypes.VOLUME})
-     private Volume.Type volumeType;
++    private String volumeType;
 +
      private String state;
  
      public Host getHost() {
@@@ -196,16 -178,14 +182,14 @@@
  
      public void setTemplate(GenericPresetVariable template) {
          this.template = template;
-         fieldNamesToIncludeInToString.add("template");
      }
  
 -    public GenericPresetVariable getDiskOffering() {
 +    public DiskOfferingPresetVariables getDiskOffering() {
          return diskOffering;
      }
  
 -    public void setDiskOffering(GenericPresetVariable diskOffering) {
 +    public void setDiskOffering(DiskOfferingPresetVariables diskOffering) {
          this.diskOffering = diskOffering;
-         fieldNamesToIncludeInToString.add("diskOffering");
      }
  
      public Storage getStorage() {
@@@ -262,15 -236,6 +240,14 @@@
          return volumeFormat;
      }
  
-     public Volume.Type getVolumeType() {
++    public String getVolumeType() {
 +        return volumeType;
 +    }
 +
-     public void setVolumeType(Volume.Type volumeType) {
++    public void setVolumeType(String volumeType) {
 +        this.volumeType = volumeType;
-         fieldNamesToIncludeInToString.add("volumeType");
 +    }
 +
      public String getState() {
          return state;
      }
diff --cc 
framework/quota/src/test/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelperTest.java
index c692cb7c1e7,095ab422ee7..85397503587
--- 
a/framework/quota/src/test/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelperTest.java
+++ 
b/framework/quota/src/test/java/org/apache/cloudstack/quota/activationrule/presetvariables/PresetVariableHelperTest.java
@@@ -214,15 -208,14 +214,15 @@@ public class PresetVariableHelperTest 
          value.setComputeOffering(getComputeOfferingForTests());
          value.setTags(Collections.singletonMap("tag1", "value1"));
          value.setTemplate(getGenericPresetVariableForTests());
 -        value.setDiskOffering(getGenericPresetVariableForTests());
 +        value.setDiskOffering(getDiskOfferingForTests());
-         value.setProvisioningType(ProvisioningType.THIN);
+         value.setProvisioningType(ProvisioningType.THIN.toString());
          value.setStorage(getStorageForTests());
          value.setSize(ByteScaleUtils.GiB);
-         value.setSnapshotType(Snapshot.Type.HOURLY);
+         value.setSnapshotType(Snapshot.Type.HOURLY.toString());
          value.setTag("tag_test");
-         value.setVmSnapshotType(VMSnapshot.Type.Disk);
+         value.setVmSnapshotType(VMSnapshot.Type.Disk.toString());
          value.setComputingResources(getComputingResourcesForTests());
-         value.setVolumeType(Volume.Type.DATADISK);
++        value.setVolumeType(Volume.Type.DATADISK.toString());
          return value;
      }
  
@@@ -296,11 -280,11 +296,11 @@@
          return quotaTypesMap.entrySet();
      }
  
 -    private List<UserVmDetailVO> getVmDetailsForTests() {
 -        List<UserVmDetailVO> details = new LinkedList<>();
 -        details.add(new UserVmDetailVO(1l, "test_with_value", "277", false));
 -        details.add(new UserVmDetailVO(1l, "test_with_invalid_value", 
"invalid", false));
 -        details.add(new UserVmDetailVO(1l, "test_with_null", null, false));
 +    private List<VMInstanceDetailVO> getVmDetailsForTests() {
 +        List<VMInstanceDetailVO> details = new LinkedList<>();
-         details.add(new VMInstanceDetailVO(1l, "test_with_value", "277", 
false));
-         details.add(new VMInstanceDetailVO(1l, "test_with_invalid_value", 
"invalid", false));
-         details.add(new VMInstanceDetailVO(1l, "test_with_null", null, 
false));
++        details.add(new VMInstanceDetailVO(1L, "test_with_value", "277", 
false));
++        details.add(new VMInstanceDetailVO(1L, "test_with_invalid_value", 
"invalid", false));
++        details.add(new VMInstanceDetailVO(1L, "test_with_null", null, 
false));
          return details;
      }
  
@@@ -428,12 -367,10 +420,11 @@@
          Account account = getAccountForTests();
          Mockito.doReturn(account.getId()).when(accountVoMock).getUuid();
          Mockito.doReturn(account.getName()).when(accountVoMock).getName();
 +        
Mockito.doReturn(account.getCreated()).when(accountVoMock).getCreated();
  
--        Account result = presetVariableHelperSpy.getPresetVariableAccount(1l);
++        Account result = presetVariableHelperSpy.getPresetVariableAccount(1L);
  
          assertPresetVariableIdAndName(account, result);
-         validateFieldNamesToIncludeInToString(Arrays.asList("created", "id", 
"name"), result);
      }
  
      @Test
@@@ -467,9 -404,9 +458,9 @@@
  
              Mockito.doReturn(role.getId()).when(roleVoMock).getUuid();
              Mockito.doReturn(role.getName()).when(roleVoMock).getName();
-             Mockito.doReturn(role.getType()).when(roleVoMock).getRoleType();
+             
Mockito.doReturn(RoleType.fromString(role.getType())).when(roleVoMock).getRoleType();
  
--            Role result = presetVariableHelperSpy.getPresetVariableRole(1l);
++            Role result = presetVariableHelperSpy.getPresetVariableRole(1L);
  
              assertPresetVariableIdAndName(role, result);
              Assert.assertEquals(role.getType(), result.getType());
@@@ -489,7 -424,7 +478,7 @@@
          Mockito.doReturn(domain.getName()).when(domainVoMock).getName();
          Mockito.doReturn(domain.getPath()).when(domainVoMock).getPath();
  
--        Domain result = presetVariableHelperSpy.getPresetVariableDomain(1l);
++        Domain result = presetVariableHelperSpy.getPresetVariableDomain(1L);
  
          assertPresetVariableIdAndName(domain, result);
          Assert.assertEquals(domain.getPath(), result.getPath());
@@@ -507,10 -440,9 +494,9 @@@
          Mockito.doReturn(expected.getId()).when(dataCenterVoMock).getUuid();
          Mockito.doReturn(expected.getName()).when(dataCenterVoMock).getName();
  
--        GenericPresetVariable result = 
presetVariableHelperSpy.getPresetVariableZone(1l);
++        GenericPresetVariable result = 
presetVariableHelperSpy.getPresetVariableZone(1L);
  
          assertPresetVariableIdAndName(expected, result);
-         validateFieldNamesToIncludeInToString(Arrays.asList("id", "name"), 
result);
      }
  
      @Test
@@@ -541,7 -472,7 +526,7 @@@
          Mockito.doReturn(new Date()).when(usageVoMock).getEndDate();
          
Mockito.doReturn(expected).when(usageDaoMock).listAccountResourcesInThePeriod(Mockito.anyLong(),
 Mockito.anyInt(), Mockito.any(Date.class), Mockito.any(Date.class));
  
--        List<Resource> result = 
presetVariableHelperSpy.getPresetVariableAccountResources(usageVoMock, 1l, 0);
++        List<Resource> result = 
presetVariableHelperSpy.getPresetVariableAccountResources(usageVoMock, 1L, 0);
  
          for (int i = 0; i < expected.size(); i++) {
              Assert.assertEquals(expected.get(i).first(), 
result.get(i).getZoneId());
@@@ -614,7 -543,7 +597,6 @@@
      public void 
setPresetVariableHostInValueIfUsageTypeIsRunningVmTestQuotaTypeIsRunningVmSetHost()
 {
          Value result = new Value();
          Host expectedHost = getHostForTests();
--        List<HostTagVO> expectedHostTags = getHostTagsForTests();
  
          
Mockito.doReturn(expectedHost).when(presetVariableHelperSpy).getPresetVariableValueHost(Mockito.anyLong());
          
presetVariableHelperSpy.setPresetVariableHostInValueIfUsageTypeIsRunningVm(result,
 UsageTypes.RUNNING_VM, vmInstanceVoMock);
@@@ -638,7 -566,7 +619,7 @@@
          Mockito.doReturn(expected.getName()).when(hostVoMock).getName();
          
Mockito.doReturn(hostTagVOListMock).when(hostTagsDaoMock).getHostTags(Mockito.anyLong());
  
--        Host result = presetVariableHelperSpy.getPresetVariableValueHost(1l);
++        Host result = presetVariableHelperSpy.getPresetVariableValueHost(1L);
  
          assertPresetVariableIdAndName(expected, result);
          Assert.assertEquals(expected.getTags(), result.getTags());
@@@ -657,7 -584,7 +637,7 @@@
          Mockito.doReturn(expected.getName()).when(hostVoMock).getName();
          
Mockito.doReturn(hostTagVOListMock).when(hostTagsDaoMock).getHostTags(Mockito.anyLong());
  
--        Host result = presetVariableHelperSpy.getPresetVariableValueHost(1l);
++        Host result = presetVariableHelperSpy.getPresetVariableValueHost(1L);
  
          assertPresetVariableIdAndName(expected, result);
          Assert.assertEquals(new ArrayList<>(), result.getTags());
@@@ -674,29 -600,13 +653,28 @@@
          String expected = "os_display_name";
          Mockito.doReturn(expected).when(guestOsVoMock).getDisplayName();
  
--        String result = 
presetVariableHelperSpy.getPresetVariableValueOsName(1l);
++        String result = 
presetVariableHelperSpy.getPresetVariableValueOsName(1L);
  
          Assert.assertEquals(expected, result);
      }
  
      @Test
 -    public void 
getPresetVariableValueComputeOfferingTestSetFieldsAndReturnObject() {
 +    public void 
getPresetVariableValueComputeOfferingForTestSetFieldsAndReturnObjectForRunningVm()
 {
 +        ComputeOffering expected = getComputeOfferingForTests();
 +        
Mockito.doReturn(expected.getId()).when(serviceOfferingVoMock).getUuid();
 +        
Mockito.doReturn(expected.getName()).when(serviceOfferingVoMock).getName();
 +        
Mockito.doReturn(expected.isCustomized()).when(serviceOfferingVoMock).isDynamic();
 +        
Mockito.doReturn(expected.offerHa()).when(serviceOfferingVoMock).isOfferHA();
 +
 +        ComputeOffering result = 
presetVariableHelperSpy.getPresetVariableValueComputeOffering(serviceOfferingVoMock,
 UsageTypes.RUNNING_VM);
 +
 +        assertPresetVariableIdAndName(expected, result);
 +        Assert.assertEquals(expected.isCustomized(), result.isCustomized());
 +        Assert.assertEquals(expected.offerHa(), result.offerHa());
-         validateFieldNamesToIncludeInToString(Arrays.asList("id", "name", 
"customized", "offerHa"), result);
 +    }
 +
 +    @Test
 +    public void 
getPresetVariableValueComputeOfferingForTestSetFieldsAndReturnObjectForAllocatedVm()
 {
          ComputeOffering expected = getComputeOfferingForTests();
          
Mockito.doReturn(expected.getId()).when(serviceOfferingVoMock).getUuid();
          
Mockito.doReturn(expected.getName()).when(serviceOfferingVoMock).getName();
@@@ -720,10 -628,9 +696,9 @@@
          Mockito.doReturn(expected.getId()).when(vmTemplateVoMock).getUuid();
          Mockito.doReturn(expected.getName()).when(vmTemplateVoMock).getName();
  
--        GenericPresetVariable result = 
presetVariableHelperSpy.getPresetVariableValueTemplate(1l);
++        GenericPresetVariable result = 
presetVariableHelperSpy.getPresetVariableValueTemplate(1L);
  
          assertPresetVariableIdAndName(expected, result);
-         validateFieldNamesToIncludeInToString(Arrays.asList("id", "name"), 
result);
      }
  
      @Test
@@@ -735,7 -642,7 +710,7 @@@
          
Mockito.doReturn(listExpected).when(resourceTagDaoMock).listBy(Mockito.anyLong(),
 Mockito.any(ResourceObjectType.class));
  
          Arrays.asList(ResourceObjectType.values()).forEach(type -> {
--            Map<String, String> result = 
presetVariableHelperSpy.getPresetVariableValueResourceTags(1l, type);
++            Map<String, String> result = 
presetVariableHelperSpy.getPresetVariableValueResourceTags(1L, type);
  
              for (ResourceTag expected: listExpected) {
                  Assert.assertEquals(expected.getValue(), 
result.get(expected.getKey()));
@@@ -760,15 -667,14 +735,15 @@@
  
              VolumeVO volumeVoMock = Mockito.mock(VolumeVO.class);
              
Mockito.doReturn(volumeVoMock).when(volumeDaoMock).findByIdIncludingRemoved(Mockito.anyLong());
--            Mockito.doReturn(1l).when(volumeVoMock).getPoolId();
++            Mockito.doReturn(1L).when(volumeVoMock).getPoolId();
  
              mockMethodValidateIfObjectIsNull();
  
              Mockito.doReturn(expected.getId()).when(volumeVoMock).getUuid();
              Mockito.doReturn(expected.getName()).when(volumeVoMock).getName();
              
Mockito.doReturn(expected.getDiskOffering()).when(presetVariableHelperSpy).getPresetVariableValueDiskOffering(Mockito.anyLong());
-             
Mockito.doReturn(expected.getProvisioningType()).when(volumeVoMock).getProvisioningType();
-             
Mockito.doReturn(expected.getVolumeType()).when(volumeVoMock).getVolumeType();
+             
Mockito.doReturn(ProvisioningType.getProvisioningType(expected.getProvisioningType())).when(volumeVoMock).getProvisioningType();
++            
Mockito.doReturn(Volume.Type.valueOf(expected.getVolumeType())).when(volumeVoMock).getVolumeType();
              
Mockito.doReturn(expected.getStorage()).when(presetVariableHelperSpy).getPresetVariableValueStorage(Mockito.anyLong(),
 Mockito.anyInt());
              
Mockito.doReturn(expected.getTags()).when(presetVariableHelperSpy).getPresetVariableValueResourceTags(Mockito.anyLong(),
 Mockito.any(ResourceObjectType.class));
              Mockito.doReturn(expected.getSize()).when(volumeVoMock).getSize();
@@@ -811,8 -714,7 +784,8 @@@
              Mockito.doReturn(expected.getId()).when(volumeVoMock).getUuid();
              Mockito.doReturn(expected.getName()).when(volumeVoMock).getName();
              
Mockito.doReturn(expected.getDiskOffering()).when(presetVariableHelperSpy).getPresetVariableValueDiskOffering(Mockito.anyLong());
-             
Mockito.doReturn(expected.getProvisioningType()).when(volumeVoMock).getProvisioningType();
-             
Mockito.doReturn(expected.getVolumeType()).when(volumeVoMock).getVolumeType();
++            
Mockito.doReturn(Volume.Type.valueOf(expected.getVolumeType())).when(volumeVoMock).getVolumeType();
+             
Mockito.doReturn(ProvisioningType.getProvisioningType(expected.getProvisioningType())).when(volumeVoMock).getProvisioningType();
              
Mockito.doReturn(expected.getTags()).when(presetVariableHelperSpy).getPresetVariableValueResourceTags(Mockito.anyLong(),
 Mockito.any(ResourceObjectType.class));
              Mockito.doReturn(expected.getSize()).when(volumeVoMock).getSize();
              Mockito.doReturn(imageFormat).when(volumeVoMock).getFormat();
@@@ -850,11 -749,9 +821,9 @@@
          Mockito.doReturn(expected.getId()).when(diskOfferingVoMock).getUuid();
          
Mockito.doReturn(expected.getName()).when(diskOfferingVoMock).getName();
  
--        GenericPresetVariable result = 
presetVariableHelperSpy.getPresetVariableValueDiskOffering(1l);
++        GenericPresetVariable result = 
presetVariableHelperSpy.getPresetVariableValueDiskOffering(1L);
  
          assertPresetVariableIdAndName(expected, result);
-         validateFieldNamesToIncludeInToString(Arrays.asList("bytesReadBurst", 
"bytesReadBurstLength", "bytesReadRate", "bytesWriteBurst", 
"bytesWriteBurstLength", "bytesWriteRate",
-                 "id", "iopsReadBurst", "iopsReadBurstLength", "iopsReadRate", 
"iopsWriteBurst", "iopsWriteBurstLength", "iopsWriteRate", "name"), result);
      }
  
      @Test
@@@ -862,7 -759,7 +831,7 @@@
          Storage expected = getStorageForTests();
          
Mockito.doReturn(expected).when(presetVariableHelperSpy).getSecondaryStorageForSnapshot(Mockito.anyLong(),
 Mockito.anyInt());
  
--        Storage result = 
presetVariableHelperSpy.getPresetVariableValueStorage(1l, 2);
++        Storage result = 
presetVariableHelperSpy.getPresetVariableValueStorage(1L, 2);
  
          Assert.assertEquals(expected, result);
          Mockito.verify(primaryStorageDaoMock, 
Mockito.never()).findByIdIncludingRemoved(Mockito.anyLong());
@@@ -880,10 -777,10 +849,10 @@@
  
          Mockito.doReturn(expected.getId()).when(storagePoolVoMock).getUuid();
          
Mockito.doReturn(expected.getName()).when(storagePoolVoMock).getName();
-         
Mockito.doReturn(expected.getScope()).when(storagePoolVoMock).getScope();
+         
Mockito.doReturn(ScopeType.validateAndGetScopeType(expected.getScope())).when(storagePoolVoMock).getScope();
          
Mockito.doReturn(storageTagVOListMock).when(storagePoolTagsDaoMock).findStoragePoolTags(Mockito.anyLong());
  
--        Storage result = 
presetVariableHelperSpy.getPresetVariableValueStorage(1l, 2);
++        Storage result = 
presetVariableHelperSpy.getPresetVariableValueStorage(1L, 2);
  
          assertPresetVariableIdAndName(expected, result);
          Assert.assertEquals(expected.getScope(), result.getScope());
@@@ -904,10 -799,10 +871,10 @@@
  
          Mockito.doReturn(expected.getId()).when(storagePoolVoMock).getUuid();
          
Mockito.doReturn(expected.getName()).when(storagePoolVoMock).getName();
-         
Mockito.doReturn(expected.getScope()).when(storagePoolVoMock).getScope();
+         
Mockito.doReturn(ScopeType.validateAndGetScopeType(expected.getScope())).when(storagePoolVoMock).getScope();
          
Mockito.doReturn(storageTagVOListMock).when(storagePoolTagsDaoMock).findStoragePoolTags(Mockito.anyLong());
  
--        Storage result = 
presetVariableHelperSpy.getPresetVariableValueStorage(1l, 2);
++        Storage result = 
presetVariableHelperSpy.getPresetVariableValueStorage(1L, 2);
  
          assertPresetVariableIdAndName(expected, result);
          Assert.assertEquals(expected.getScope(), result.getScope());
@@@ -921,7 -814,7 +886,7 @@@
      public void 
getSecondaryStorageForSnapshotTestAllTypesAndDoNotBackupSnapshotReturnNull() {
          presetVariableHelperSpy.backupSnapshotAfterTakingSnapshot = false;
          getQuotaTypesForTests().forEach(type -> {
--            Storage result = 
presetVariableHelperSpy.getSecondaryStorageForSnapshot(1l, type.getKey());
++            Storage result = 
presetVariableHelperSpy.getSecondaryStorageForSnapshot(1L, type.getKey());
              Assert.assertNull(result);
          });
      }
@@@ -930,7 -823,7 +895,7 @@@
      public void 
getSecondaryStorageForSnapshotTestAllTypesExceptSnapshotAndBackupSnapshotReturnNull()
 {
          presetVariableHelperSpy.backupSnapshotAfterTakingSnapshot = true;
          getQuotaTypesForTests(UsageTypes.SNAPSHOT).forEach(type -> {
--            Storage result = 
presetVariableHelperSpy.getSecondaryStorageForSnapshot(1l, type.getKey());
++            Storage result = 
presetVariableHelperSpy.getSecondaryStorageForSnapshot(1L, type.getKey());
              Assert.assertNull(result);
          });
      }
@@@ -947,10 -840,9 +912,9 @@@
          Mockito.doReturn(expected.getName()).when(imageStoreVoMock).getName();
          presetVariableHelperSpy.backupSnapshotAfterTakingSnapshot = true;
  
--        Storage result = 
presetVariableHelperSpy.getSecondaryStorageForSnapshot(1l, UsageTypes.SNAPSHOT);
++        Storage result = 
presetVariableHelperSpy.getSecondaryStorageForSnapshot(1L, UsageTypes.SNAPSHOT);
  
          assertPresetVariableIdAndName(expected, result);
-         validateFieldNamesToIncludeInToString(Arrays.asList("id", "name"), 
result);
      }
  
      @Test
@@@ -1025,7 -915,7 +987,7 @@@
              
Mockito.doReturn(expected.getName()).when(snapshotVoMock).getName();
              
Mockito.doReturn(expected.getSize()).when(snapshotVoMock).getSize();
              Mockito.doReturn((short) 
3).when(snapshotVoMock).getSnapshotType();
--            
Mockito.doReturn(1l).when(presetVariableHelperSpy).getSnapshotDataStoreId(Mockito.anyLong(),
 Mockito.anyLong());
++            
Mockito.doReturn(1L).when(presetVariableHelperSpy).getSnapshotDataStoreId(Mockito.anyLong(),
 Mockito.anyLong());
              
Mockito.doReturn(expected.getStorage()).when(presetVariableHelperSpy).getPresetVariableValueStorage(Mockito.anyLong(),
 Mockito.anyInt());
              
Mockito.doReturn(expected.getTags()).when(presetVariableHelperSpy).getPresetVariableValueResourceTags(Mockito.anyLong(),
 Mockito.any(ResourceObjectType.class));
              
Mockito.doReturn(hypervisorType).when(snapshotVoMock).getHypervisorType();
@@@ -1056,12 -944,12 +1016,12 @@@
      public void 
getSnapshotDataStoreIdTestDoNotBackupSnapshotToSecondaryRetrievePrimaryStorage()
 {
          SnapshotDataStoreVO snapshotDataStoreVoMock = 
Mockito.mock(SnapshotDataStoreVO.class);
  
--        Long expected = 1l;
++        Long expected = 1L;
          
Mockito.doReturn(snapshotDataStoreVoMock).when(snapshotDataStoreDaoMock).findOneBySnapshotAndDatastoreRole(Mockito.anyLong(),
 Mockito.any(DataStoreRole.class));
          
Mockito.doReturn(expected).when(snapshotDataStoreVoMock).getDataStoreId();
          presetVariableHelperSpy.backupSnapshotAfterTakingSnapshot = false;
  
--        Long result = presetVariableHelperSpy.getSnapshotDataStoreId(1l, 1l);
++        Long result = presetVariableHelperSpy.getSnapshotDataStoreId(1L, 1L);
  
          Assert.assertEquals(expected, result);
  
@@@ -1078,7 -966,7 +1038,7 @@@
      public void 
getSnapshotDataStoreIdTestBackupSnapshotToSecondaryRetrieveSecondaryStorage() {
          SnapshotDataStoreVO snapshotDataStoreVoMock = 
Mockito.mock(SnapshotDataStoreVO.class);
  
--        Long expected = 2l;
++        Long expected = 2L;
          ImageStoreVO imageStore = Mockito.mock(ImageStoreVO.class);
          
Mockito.when(imageStoreDaoMock.findById(Mockito.anyLong())).thenReturn(imageStore);
          Mockito.when(imageStore.getDataCenterId()).thenReturn(1L);
@@@ -1086,7 -974,7 +1046,7 @@@
          
Mockito.doReturn(expected).when(snapshotDataStoreVoMock).getDataStoreId();
          presetVariableHelperSpy.backupSnapshotAfterTakingSnapshot = true;
  
--        Long result = presetVariableHelperSpy.getSnapshotDataStoreId(2l, 1L);
++        Long result = presetVariableHelperSpy.getSnapshotDataStoreId(2L, 1L);
  
          Assert.assertEquals(expected, result);
  
@@@ -1228,7 -1109,7 +1181,7 @@@
  
      @Test
      public void getDetailByNameTestReturnsValue() {
--        int expected = 
Integer.valueOf(getVmDetailsForTests().get(0).getValue());
++        int expected = 
Integer.parseInt(getVmDetailsForTests().get(0).getValue());
          int result = 
presetVariableHelperSpy.getDetailByName(getVmDetailsForTests(), 
"test_with_value", expected);
          Assert.assertEquals(expected, result);
      }
@@@ -1311,7 -1190,7 +1262,7 @@@
          
Mockito.doReturn(expected.getName()).when(backupOfferingVoMock).getName();
          
Mockito.doReturn(expected.getExternalId()).when(backupOfferingVoMock).getExternalId();
  
--        BackupOffering result = 
presetVariableHelperSpy.getPresetVariableValueBackupOffering(1l);
++        BackupOffering result = 
presetVariableHelperSpy.getPresetVariableValueBackupOffering(1L);
  
          assertPresetVariableIdAndName(expected, result);
          Assert.assertEquals(expected.getExternalId(), result.getExternalId());
diff --cc 
plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java
index 3b2c2692b0d,565ea29acf8..f2ea8ac71c9
--- 
a/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java
+++ 
b/plugins/backup/nas/src/main/java/org/apache/cloudstack/backup/NASBackupProvider.java
@@@ -68,8 -56,8 +68,7 @@@ import java.util.Date
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
 -import java.util.HashMap;
  import java.util.Objects;
- import java.util.Optional;
  import java.util.UUID;
  import java.util.stream.Collectors;
  
@@@ -279,24 -210,12 +278,25 @@@ public class NASBackupProvider extends 
          return backupDao.persist(backup);
      }
  
 +    @Override
 +    public Pair<Boolean, String> restoreBackupToVM(VirtualMachine vm, Backup 
backup, String hostIp, String dataStoreUuid) {
 +        return restoreVMBackup(vm, backup);
 +    }
 +
      @Override
      public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
 +        return restoreVMBackup(vm, backup).first();
 +    }
 +
 +    private Pair<Boolean, String> restoreVMBackup(VirtualMachine vm, Backup 
backup) {
-         List<String> backedVolumesUUIDs = backup.getBackedUpVolumes().stream()
+         List<Backup.VolumeInfo> backedVolumes = backup.getBackedUpVolumes();
 -        List<VolumeVO> volumes = backedVolumes.stream()
 -                .map(volume -> volumeDao.findByUuid(volume.getUuid()))
 -                .sorted((v1, v2) -> Long.compare(v1.getDeviceId(), 
v2.getDeviceId()))
++        List<String> backedVolumesUUIDs = backedVolumes.stream()
 +                
.sorted(Comparator.comparingLong(Backup.VolumeInfo::getDeviceId))
 +                .map(Backup.VolumeInfo::getUuid)
 +                .collect(Collectors.toList());
 +
 +        List<VolumeVO> restoreVolumes = 
volumeDao.findByInstance(vm.getId()).stream()
 +                .sorted(Comparator.comparingLong(VolumeVO::getDeviceId))
                  .collect(Collectors.toList());
  
          LOG.debug("Restoring vm {} from backup {} on the NAS Backup 
Provider", vm, backup);
@@@ -309,27 -228,31 +309,36 @@@
          restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
          restoreCommand.setMountOptions(backupRepository.getMountOptions());
          restoreCommand.setVmName(vm.getName());
 -        restoreCommand.setVolumePaths(getVolumePaths(volumes));
 +        restoreCommand.setBackupVolumesUUIDs(backedVolumesUUIDs);
 +        Pair<List<PrimaryDataStoreTO>, List<String>> volumePoolsAndPaths = 
getVolumePoolsAndPaths(restoreVolumes);
 +        restoreCommand.setRestoreVolumePools(volumePoolsAndPaths.first());
 +        restoreCommand.setRestoreVolumePaths(volumePoolsAndPaths.second());
+         restoreCommand.setBackupFiles(getBackupFiles(backedVolumes));
          restoreCommand.setVmExists(vm.getRemoved() == null);
          restoreCommand.setVmState(vm.getState());
 +        restoreCommand.setMountTimeout(NASBackupRestoreMountTimeout.value());
  
 -        BackupAnswer answer = null;
 +        BackupAnswer answer;
          try {
              answer = (BackupAnswer) agentManager.send(host.getId(), 
restoreCommand);
          } catch (AgentUnavailableException e) {
              throw new CloudRuntimeException("Unable to contact backend 
control plane to initiate backup");
          } catch (OperationTimedoutException e) {
 -            throw new CloudRuntimeException("Operation to initiate backup 
timed out, please try again");
 +            throw new CloudRuntimeException("Operation to restore backup 
timed out, please try again");
          }
 -        return answer.getResult();
 +        return new Pair<>(answer.getResult(), answer.getDetails());
      }
  
+     private List<String> getBackupFiles(List<Backup.VolumeInfo> 
backedVolumes) {
+         List<String> backupFiles = new ArrayList<>();
+         for (Backup.VolumeInfo backedVolume : backedVolumes) {
+             backupFiles.add(backedVolume.getPath());
+         }
+         return backupFiles;
+     }
+ 
 -    private List<String> getVolumePaths(List<VolumeVO> volumes) {
 +    private Pair<List<PrimaryDataStoreTO>, List<String>> 
getVolumePoolsAndPaths(List<VolumeVO> volumes) {
 +        List<PrimaryDataStoreTO> volumePools = new ArrayList<>();
          List<String> volumePaths = new ArrayList<>();
          for (VolumeVO volume : volumes) {
              StoragePoolVO storagePool = 
primaryDataStoreDao.findById(volume.getPoolId());
@@@ -360,14 -273,20 +369,20 @@@
      }
  
      @Override
 -    public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String 
volumeUuid, String hostIp, String dataStoreUuid, Pair<String, 
VirtualMachine.State> vmNameAndState) {
 -        final VolumeVO volume = volumeDao.findByUuid(volumeUuid);
 -        final VirtualMachine backupSourceVm = 
vmInstanceDao.findById(backup.getVmId());
 -        final StoragePoolHostVO dataStore = 
storagePoolHostDao.findByUuid(dataStoreUuid);
 +    public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, 
Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid, 
Pair<String, VirtualMachine.State> vmNameAndState) {
 +        final VolumeVO volume = 
volumeDao.findByUuid(backupVolumeInfo.getUuid());
 +        final DiskOffering diskOffering = 
diskOfferingDao.findByUuid(backupVolumeInfo.getDiskOfferingId());
 +        final StoragePoolVO pool = 
primaryDataStoreDao.findByUuid(dataStoreUuid);
          final HostVO hostVO = hostDao.findByIp(hostIp);
  
-         LOG.debug("Restoring vm volume {} from backup {} on the NAS Backup 
Provider", backupVolumeInfo, backup);
 -        Backup.VolumeInfo matchingVolume = 
getBackedUpVolumeInfo(backup.getBackedUpVolumes(), volumeUuid);
++        Backup.VolumeInfo matchingVolume = 
getBackedUpVolumeInfo(backup.getBackedUpVolumes(), volume.getUuid());
+         if (matchingVolume == null) {
 -            throw new CloudRuntimeException(String.format("Unable to find 
volume %s in the list of backed up volumes for backup %s, cannot proceed with 
restore", volumeUuid, backup));
++            throw new CloudRuntimeException(String.format("Unable to find 
volume %s in the list of backed up volumes for backup %s, cannot proceed with 
restore", volume.getUuid(), backup));
+         }
+         Long backedUpVolumeSize = matchingVolume.getSize();
+ 
+         LOG.debug("Restoring vm volume {} from backup {} on the NAS Backup 
Provider", volume, backup);
 -        BackupRepository backupRepository = 
getBackupRepository(backupSourceVm, backup);
 +        BackupRepository backupRepository = getBackupRepository(backup);
  
          VolumeVO restoredVolume = new VolumeVO(Volume.Type.DATADISK, null, 
backup.getZoneId(),
                  backup.getDomainId(), backup.getAccountId(), 0, null,
@@@ -380,17 -298,12 +395,17 @@@
          restoredVolume.setUuid(volumeUUID);
          restoredVolume.setRemoved(null);
          restoredVolume.setDisplayVolume(true);
 -        restoredVolume.setPoolId(dataStore.getPoolId());
 +        restoredVolume.setPoolId(pool.getId());
 +        restoredVolume.setPoolType(pool.getPoolType());
          restoredVolume.setPath(restoredVolume.getUuid());
          restoredVolume.setState(Volume.State.Copying);
-         restoredVolume.setSize(backupVolumeInfo.getSize());
 -        restoredVolume.setFormat(Storage.ImageFormat.QCOW2);
+         restoredVolume.setSize(backedUpVolumeSize);
 -        restoredVolume.setDiskOfferingId(volume.getDiskOfferingId());
 +        restoredVolume.setDiskOfferingId(diskOffering.getId());
 +        if (pool.getPoolType() != Storage.StoragePoolType.RBD) {
 +            restoredVolume.setFormat(Storage.ImageFormat.QCOW2);
 +        } else {
 +            restoredVolume.setFormat(Storage.ImageFormat.RAW);
 +        }
  
          RestoreBackupCommand restoreCommand = new RestoreBackupCommand();
          restoreCommand.setBackupPath(backup.getExternalId());
@@@ -404,10 -316,8 +419,10 @@@
          restoreCommand.setMountOptions(backupRepository.getMountOptions());
          restoreCommand.setVmExists(null);
          restoreCommand.setVmState(vmNameAndState.second());
-         restoreCommand.setRestoreVolumeUUID(backupVolumeInfo.getUuid());
 +        restoreCommand.setMountTimeout(NASBackupRestoreMountTimeout.value());
++        
restoreCommand.setBackupFiles(Collections.singletonList(matchingVolume.getPath()));
  
 -        BackupAnswer answer = null;
 +        BackupAnswer answer;
          try {
              answer = (BackupAnswer) agentManager.send(hostVO.getId(), 
restoreCommand);
          } catch (AgentUnavailableException e) {
diff --cc 
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java
index fd94013dd50,47b903c47a7..714e3844b34
--- 
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java
+++ 
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapper.java
@@@ -69,78 -57,68 +69,85 @@@ public class LibvirtRestoreBackupComman
          String mountOptions = command.getMountOptions();
          Boolean vmExists = command.isVmExists();
          String diskType = command.getDiskType();
 -        List<String> volumePaths = command.getVolumePaths();
 +        List<String> backedVolumeUUIDs = command.getBackupVolumesUUIDs();
 +        List<PrimaryDataStoreTO> restoreVolumePools = 
command.getRestoreVolumePools();
 +        List<String> restoreVolumePaths = command.getRestoreVolumePaths();
-         String restoreVolumeUuid = command.getRestoreVolumeUUID();
 +        Integer mountTimeout = command.getMountTimeout() * 1000;
 +        int timeout = command.getWait();
 +        KVMStoragePoolManager storagePoolMgr = 
serverResource.getStoragePoolMgr();
+         List<String> backupFiles = command.getBackupFiles();
  
          String newVolumeId = null;
          try {
 +            String mountDirectory = mountBackupDirectory(backupRepoAddress, 
backupRepoType, mountOptions, mountTimeout);
              if (Objects.isNull(vmExists)) {
 -                String volumePath = volumePaths.get(0);
 +                PrimaryDataStoreTO volumePool = restoreVolumePools.get(0);
 +                String volumePath = restoreVolumePaths.get(0);
+                 String backupFile = backupFiles.get(0);
                  int lastIndex = volumePath.lastIndexOf("/");
                  newVolumeId = volumePath.substring(lastIndex + 1);
-                 restoreVolume(storagePoolMgr, backupPath, volumePool, 
volumePath, diskType, restoreVolumeUuid,
 -                restoreVolume(backupPath, backupRepoType, backupRepoAddress, 
volumePath, diskType, backupFile,
 -                        new Pair<>(vmName, command.getVmState()), 
mountOptions);
++                restoreVolume(storagePoolMgr, backupPath, volumePool, 
volumePath, diskType, backupFile,
 +                        new Pair<>(vmName, command.getVmState()), 
mountDirectory, timeout);
              } else if (Boolean.TRUE.equals(vmExists)) {
-                 restoreVolumesOfExistingVM(storagePoolMgr, 
restoreVolumePools, restoreVolumePaths, backedVolumeUUIDs, backupPath, 
mountDirectory, timeout);
 -                restoreVolumesOfExistingVM(volumePaths, backupPath, 
backupFiles, backupRepoType, backupRepoAddress, mountOptions);
++                restoreVolumesOfExistingVM(storagePoolMgr, 
restoreVolumePools, restoreVolumePaths, backedVolumeUUIDs, backupPath, 
backupFiles, mountDirectory, timeout);
              } else {
-                 restoreVolumesOfDestroyedVMs(storagePoolMgr, 
restoreVolumePools, restoreVolumePaths, vmName, backupPath, mountDirectory, 
timeout);
 -                restoreVolumesOfDestroyedVMs(volumePaths, vmName, backupPath, 
backupFiles, backupRepoType, backupRepoAddress, mountOptions);
++                restoreVolumesOfDestroyedVMs(storagePoolMgr, 
restoreVolumePools, restoreVolumePaths, backupPath, backupFiles, 
mountDirectory, timeout);
              }
          } catch (CloudRuntimeException e) {
 -            String errorMessage = "Failed to restore backup for VM: " + 
vmName + ".";
 -            if (e.getMessage() != null && !e.getMessage().isEmpty()) {
 -                errorMessage += " Details: " + e.getMessage();
 -            }
 -            logger.error(errorMessage);
 +            String errorMessage = e.getMessage() != null ? e.getMessage() : 
"";
              return new BackupAnswer(command, false, errorMessage);
          }
  
          return new BackupAnswer(command, true, newVolumeId);
      }
  
 -    private void restoreVolumesOfExistingVM(List<String> volumePaths, String 
backupPath, List<String> backupFiles,
 -                                             String backupRepoType, String 
backupRepoAddress, String mountOptions) {
 +    private void verifyBackupFile(String backupPath, String volUuid) {
 +        if (!checkBackupPathExists(backupPath)) {
 +            throw new CloudRuntimeException(String.format("Backup file for 
the volume [%s] does not exist.", volUuid));
 +        }
 +        if (!checkBackupFileImage(backupPath)) {
 +            throw new CloudRuntimeException(String.format("Backup qcow2 file 
for the volume [%s] is corrupt.", volUuid));
 +        }
 +    }
 +
-     private void restoreVolumesOfExistingVM(KVMStoragePoolManager 
storagePoolMgr, List<PrimaryDataStoreTO> restoreVolumePools, List<String> 
restoreVolumePaths, List<String> backedVolumesUUIDs,
-                                             String backupPath, String 
mountDirectory, int timeout) {
++    private void restoreVolumesOfExistingVM(KVMStoragePoolManager 
storagePoolMgr, List<PrimaryDataStoreTO> restoreVolumePools,
++                                            List<String> restoreVolumePaths, 
List<String> backedVolumesUUIDs,
++                                            String backupPath, List<String> 
backupFiles, String mountDirectory, int timeout) {
          String diskType = "root";
 -        String mountDirectory = mountBackupDirectory(backupRepoAddress, 
backupRepoType, mountOptions);
          try {
 -            for (int idx = 0; idx < volumePaths.size(); idx++) {
 -                String volumePath = volumePaths.get(idx);
 +            for (int idx = 0; idx < restoreVolumePaths.size(); idx++) {
 +                PrimaryDataStoreTO restoreVolumePool = 
restoreVolumePools.get(idx);
 +                String restoreVolumePath = restoreVolumePaths.get(idx);
+                 String backupFile = backupFiles.get(idx);
 -                String bkpPath = getBackupPath(mountDirectory, backupPath, 
backupFile, diskType);
 +                String backupVolumeUuid = backedVolumesUUIDs.get(idx);
-                 Pair<String, String> bkpPathAndVolUuid = 
getBackupPath(mountDirectory, null, backupPath, diskType, backupVolumeUuid);
++                String fullPath = getBackupPath(mountDirectory, backupPath, 
backupFile, diskType);
                  diskType = "datadisk";
-                 verifyBackupFile(bkpPathAndVolUuid.first(), 
bkpPathAndVolUuid.second());
-                 if (!replaceVolumeWithBackup(storagePoolMgr, 
restoreVolumePool, restoreVolumePath, bkpPathAndVolUuid.first(), timeout)) {
-                     throw new CloudRuntimeException(String.format("Unable to 
restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
 -                if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
 -                    throw new CloudRuntimeException(String.format("Unable to 
restore backup from volume [%s].", volumePath));
++
++                verifyBackupFile(fullPath, backupVolumeUuid);
++                if (!replaceVolumeWithBackup(storagePoolMgr, 
restoreVolumePool, restoreVolumePath, fullPath, timeout)) {
++                    throw new CloudRuntimeException(String.format("Unable to 
restore contents from the backup volume [%s].", backupVolumeUuid));
                  }
              }
          } finally {
              unmountBackupDirectory(mountDirectory);
              deleteTemporaryDirectory(mountDirectory);
          }
 -
      }
  
-     private void restoreVolumesOfDestroyedVMs(KVMStoragePoolManager 
storagePoolMgr, List<PrimaryDataStoreTO> volumePools, List<String> volumePaths, 
String vmName, String backupPath, String mountDirectory, int timeout) {
 -    private void restoreVolumesOfDestroyedVMs(List<String> volumePaths, 
String vmName, String backupPath, List<String> backupFiles,
 -                                              String backupRepoType, String 
backupRepoAddress, String mountOptions) {
 -        String mountDirectory = mountBackupDirectory(backupRepoAddress, 
backupRepoType, mountOptions);
++    private void restoreVolumesOfDestroyedVMs(KVMStoragePoolManager 
storagePoolMgr, List<PrimaryDataStoreTO> volumePools,
++                                              List<String> volumePaths, 
String backupPath, List<String> backupFiles, String mountDirectory, int 
timeout) {
          String diskType = "root";
          try {
 -            for (int idx = 0; idx < volumePaths.size(); idx++) {
 -                String volumePath = volumePaths.get(idx);
 -                String backupFile = backupFiles.get(idx);
 +            for (int i = 0; i < volumePaths.size(); i++) {
 +                PrimaryDataStoreTO volumePool = volumePools.get(i);
 +                String volumePath = volumePaths.get(i);
-                 Pair<String, String> bkpPathAndVolUuid = 
getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
++                String backupFile = backupFiles.get(i);
+                 String bkpPath = getBackupPath(mountDirectory, backupPath, 
backupFile, diskType);
++                String volumeUuid = 
volumePath.substring(volumePath.lastIndexOf(File.separator) + 1);
                  diskType = "datadisk";
-                 verifyBackupFile(bkpPathAndVolUuid.first(), 
bkpPathAndVolUuid.second());
-                 if (!replaceVolumeWithBackup(storagePoolMgr, volumePool, 
volumePath, bkpPathAndVolUuid.first(), timeout)) {
-                     throw new CloudRuntimeException(String.format("Unable to 
restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
 -                if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
 -                    throw new CloudRuntimeException(String.format("Unable to 
restore backup from volume [%s].", volumePath));
++                verifyBackupFile(bkpPath, volumeUuid);
++                if (!replaceVolumeWithBackup(storagePoolMgr, volumePool, 
volumePath, bkpPath, timeout)) {
++                    throw new CloudRuntimeException(String.format("Unable to 
restore contents from the backup volume [%s].", volumeUuid));
                  }
              }
          } finally {
@@@ -149,17 -127,17 +156,20 @@@
          }
      }
  
-     private void restoreVolume(KVMStoragePoolManager storagePoolMgr, String 
backupPath, PrimaryDataStoreTO volumePool, String volumePath, String diskType, 
String volumeUUID,
 -    private void restoreVolume(String backupPath, String backupRepoType, 
String backupRepoAddress, String volumePath,
 -                               String diskType, String backupFile, 
Pair<String, VirtualMachine.State> vmNameAndState, String mountOptions) {
 -        String mountDirectory = mountBackupDirectory(backupRepoAddress, 
backupRepoType, mountOptions);
++    private void restoreVolume(KVMStoragePoolManager storagePoolMgr, String 
backupPath, PrimaryDataStoreTO volumePool, String volumePath, String diskType, 
String backupFile,
 +                               Pair<String, VirtualMachine.State> 
vmNameAndState, String mountDirectory, int timeout) {
-         Pair<String, String> bkpPathAndVolUuid;
+         String bkpPath;
++        String volumeUuid;
          try {
-             bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, 
backupPath, diskType, volumeUUID);
-             verifyBackupFile(bkpPathAndVolUuid.first(), 
bkpPathAndVolUuid.second());
-             if (!replaceVolumeWithBackup(storagePoolMgr, volumePool, 
volumePath, bkpPathAndVolUuid.first(), timeout, true)) {
-                 throw new CloudRuntimeException(String.format("Unable to 
restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
+             bkpPath = getBackupPath(mountDirectory, backupPath, backupFile, 
diskType);
 -            if (!replaceVolumeWithBackup(volumePath, bkpPath)) {
 -                throw new CloudRuntimeException(String.format("Unable to 
restore backup from volume [%s].", volumePath));
++            volumeUuid = 
volumePath.substring(volumePath.lastIndexOf(File.separator) + 1);
++            verifyBackupFile(bkpPath, volumeUuid);
++            if (!replaceVolumeWithBackup(storagePoolMgr, volumePool, 
volumePath, bkpPath, timeout, true)) {
++                throw new CloudRuntimeException(String.format("Unable to 
restore contents from the backup volume [%s].", volumeUuid));
++
              }
              if (VirtualMachine.State.Running.equals(vmNameAndState.second())) 
{
 -                if (!attachVolumeToVm(vmNameAndState.first(), volumePath)) {
 +                if (!attachVolumeToVm(storagePoolMgr, vmNameAndState.first(), 
volumePool, volumePath)) {
                      throw new CloudRuntimeException(String.format("Failed to 
attach volume to VM: %s", vmNameAndState.first()));
                  }
              }
@@@ -170,43 -150,35 +180,43 @@@
      }
  
  
 -    private String mountBackupDirectory(String backupRepoAddress, String 
backupRepoType, String mountOptions) {
 +    private String mountBackupDirectory(String backupRepoAddress, String 
backupRepoType, String mountOptions, Integer mountTimeout) {
          String randomChars = RandomStringUtils.random(5, true, false);
          String mountDirectory = String.format("%s.%s",BACKUP_TEMP_FILE_PREFIX 
, randomChars);
 +
          try {
              mountDirectory = 
Files.createTempDirectory(mountDirectory).toString();
 -            String mount = String.format(MOUNT_COMMAND, backupRepoType, 
backupRepoAddress, mountDirectory);
 -            if ("cifs".equals(backupRepoType)) {
 -                if (Objects.isNull(mountOptions) || 
mountOptions.trim().isEmpty()) {
 -                    mountOptions = "nobrl";
 -                } else {
 -                    mountOptions += ",nobrl";
 -                }
 -            }
 -            if (Objects.nonNull(mountOptions) && 
!mountOptions.trim().isEmpty()) {
 -                mount += " -o " + mountOptions;
 +        } catch (IOException e) {
-             logger.error(String.format("Failed to create the tmp mount 
directory {} for restore", mountDirectory), e);
++            logger.error("Failed to create the tmp mount directory {} for 
restore", mountDirectory, e);
 +            throw new CloudRuntimeException("Failed to create the tmp mount 
directory for restore on the KVM host");
 +        }
 +
 +        String mount = String.format(MOUNT_COMMAND, backupRepoType, 
backupRepoAddress, mountDirectory);
 +        if ("cifs".equals(backupRepoType)) {
 +            if (Objects.isNull(mountOptions) || 
mountOptions.trim().isEmpty()) {
 +                mountOptions = "nobrl";
 +            } else {
 +                mountOptions += ",nobrl";
              }
 -            Script.runSimpleBashScript(mount);
 -        } catch (Exception e) {
 -            throw new CloudRuntimeException(String.format("Failed to mount %s 
to %s", backupRepoType, backupRepoAddress), e);
 +        }
 +        if (Objects.nonNull(mountOptions) && !mountOptions.trim().isEmpty()) {
 +            mount += " -o " + mountOptions;
 +        }
 +
 +        int exitValue = Script.runSimpleBashScriptForExitValue(mount, 
mountTimeout, false);
 +        if (exitValue != 0) {
-             logger.error(String.format("Failed to mount repository {} of type 
{} to the directory {}", backupRepoAddress, backupRepoType, mountDirectory));
++            logger.error("Failed to mount repository {} of type {} to the 
directory {}", backupRepoAddress, backupRepoType, mountDirectory);
 +            throw new CloudRuntimeException("Failed to mount the backup 
repository on the KVM host");
          }
          return mountDirectory;
      }
  
      private void unmountBackupDirectory(String backupDirectory) {
 -        try {
 -            String umountCmd = String.format(UMOUNT_COMMAND, backupDirectory);
 -            Script.runSimpleBashScript(umountCmd);
 -        } catch (Exception e) {
 -            throw new CloudRuntimeException(String.format("Failed to unmount 
backup directory: %s", backupDirectory), e);
 +        String umountCmd = String.format(UMOUNT_COMMAND, backupDirectory);
 +        int exitValue = Script.runSimpleBashScriptForExitValue(umountCmd);
 +        if (exitValue != 0) {
-             logger.error(String.format("Failed to unmount backup directory 
{}", backupDirectory));
++            logger.error("Failed to unmount backup directory {}", 
backupDirectory);
 +            throw new CloudRuntimeException("Failed to unmount the backup 
directory");
          }
      }
  
@@@ -214,26 -186,19 +224,25 @@@
          try {
              Files.deleteIfExists(Paths.get(backupDirectory));
          } catch (IOException e) {
-             logger.error(String.format("Failed to delete backup directory: 
%s", backupDirectory), e);
 -            throw new CloudRuntimeException(String.format("Failed to delete 
backup directory: %s", backupDirectory), e);
++            logger.error("Failed to delete backup directory: {}}", 
backupDirectory, e);
 +            throw new CloudRuntimeException("Failed to delete the backup 
directory");
          }
      }
  
-     private Pair<String, String> getBackupPath(String mountDirectory, String 
volumePath, String backupPath, String diskType, String volumeUuid) {
+     private String getBackupPath(String mountDirectory, String backupPath, 
String backupFile, String diskType) {
          String bkpPath = String.format(FILE_PATH_PLACEHOLDER, mountDirectory, 
backupPath);
-         String volUuid = Objects.isNull(volumeUuid) ? 
volumePath.substring(volumePath.lastIndexOf(File.separator) + 1) : volumeUuid;
-         String backupFileName = String.format("%s.%s.qcow2", 
diskType.toLowerCase(Locale.ROOT), volUuid);
+         String backupFileName = String.format("%s.%s.qcow2", 
diskType.toLowerCase(Locale.ROOT), backupFile);
          bkpPath = String.format(FILE_PATH_PLACEHOLDER, bkpPath, 
backupFileName);
-         return new Pair<>(bkpPath, volUuid);
+         return bkpPath;
      }
  
 -    private boolean replaceVolumeWithBackup(String volumePath, String 
backupPath) {
 -        int exitValue = 
Script.runSimpleBashScriptForExitValue(String.format(RSYNC_COMMAND, backupPath, 
volumePath));
 +    private boolean checkBackupFileImage(String backupPath) {
 +        int exitValue = 
Script.runSimpleBashScriptForExitValue(String.format("qemu-img check %s", 
backupPath));
 +        return exitValue == 0;
 +    }
 +
 +    private boolean checkBackupPathExists(String backupPath) {
 +        int exitValue = 
Script.runSimpleBashScriptForExitValue(String.format("ls %s", backupPath));
          return exitValue == 0;
      }
  
diff --cc 
plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapperTest.java
index 7bcd0bf18e6,00000000000..d72dc0d8ac3
mode 100644,000000..100644
--- 
a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapperTest.java
+++ 
b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtRestoreBackupCommandWrapperTest.java
@@@ -1,526 -1,0 +1,529 @@@
 +// Licensed to the Apache Software Foundation (ASF) under one
 +// or more contributor license agreements.  See the NOTICE file
 +// distributed with this work for additional information
 +// regarding copyright ownership.  The ASF licenses this file
 +// to you under the Apache License, Version 2.0 (the
 +// "License"); you may not use this file except in compliance
 +// with the License.  You may obtain a copy of the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing,
 +// software distributed under the License is distributed on an
 +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +// KIND, either express or implied.  See the License for the
 +// specific language governing permissions and limitations
 +// under the License.
 +package com.cloud.hypervisor.kvm.resource.wrapper;
 +
 +import com.cloud.agent.api.Answer;
 +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
 +import com.cloud.utils.script.Script;
 +import com.cloud.vm.VirtualMachine;
 +import org.apache.cloudstack.backup.BackupAnswer;
 +import org.apache.cloudstack.backup.RestoreBackupCommand;
 +import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
 +import org.junit.Assert;
 +import org.junit.Before;
 +import org.junit.Test;
 +import org.junit.runner.RunWith;
 +import org.mockito.MockedStatic;
 +import org.mockito.Mockito;
 +import org.mockito.junit.MockitoJUnitRunner;
 +
 +import java.io.IOException;
 +import java.nio.file.Files;
 +import java.nio.file.Path;
 +import java.util.Arrays;
 +
 +import static org.mockito.ArgumentMatchers.any;
 +import static org.mockito.ArgumentMatchers.anyInt;
 +import static org.mockito.ArgumentMatchers.anyString;
 +import static org.mockito.Mockito.lenient;
 +import static org.mockito.Mockito.mockStatic;
 +import static org.mockito.Mockito.when;
 +
 +@RunWith(MockitoJUnitRunner.class)
 +public class LibvirtRestoreBackupCommandWrapperTest {
 +
 +    private LibvirtRestoreBackupCommandWrapper wrapper;
 +    private LibvirtComputingResource libvirtComputingResource;
 +    private RestoreBackupCommand command;
 +
 +    @Before
 +    public void setUp() {
 +        wrapper = new LibvirtRestoreBackupCommandWrapper();
 +        libvirtComputingResource = 
Mockito.mock(LibvirtComputingResource.class);
 +        command = Mockito.mock(RestoreBackupCommand.class);
 +    }
 +
 +    @Test
 +    public void testExecuteWithVmExistsNull() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        when(command.getBackupRepoType()).thenReturn("nfs");
 +        when(command.getMountOptions()).thenReturn("rw");
 +        when(command.isVmExists()).thenReturn(null);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
-         when(command.getRestoreVolumeUUID()).thenReturn("volume-123");
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        when(command.getVmState()).thenReturn(VirtualMachine.State.Running);
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenReturn(0); // Other commands success
 +                scriptMock.when(() -> Script.runSimpleBashScript(anyString()))
 +                        .thenReturn("vda"); // Current device
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertTrue(backupAnswer.getResult());
 +                Assert.assertEquals("volume-123", backupAnswer.getDetails());
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithVmExistsTrue() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        when(command.getBackupRepoType()).thenReturn("nfs");
 +        when(command.getMountOptions()).thenReturn("rw");
 +        when(command.isVmExists()).thenReturn(true);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
 +        
when(command.getBackupVolumesUUIDs()).thenReturn(Arrays.asList("volume-123"));
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenReturn(0); // Other commands success
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertTrue(backupAnswer.getResult());
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithVmExistsFalse() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        when(command.getBackupRepoType()).thenReturn("nfs");
 +        when(command.getMountOptions()).thenReturn("rw");
 +        when(command.isVmExists()).thenReturn(false);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenReturn(0); // Other commands success
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertTrue(backupAnswer.getResult());
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithCifsMountType() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("//192.168.1.100/backup");
 +        when(command.getBackupRepoType()).thenReturn("cifs");
 +        
when(command.getMountOptions()).thenReturn("username=user,password=pass");
 +        when(command.isVmExists()).thenReturn(null);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
-         when(command.getRestoreVolumeUUID()).thenReturn("volume-123");
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        when(command.getVmState()).thenReturn(VirtualMachine.State.Running);
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenReturn(0); // Other commands success
 +                scriptMock.when(() -> Script.runSimpleBashScript(anyString()))
 +                        .thenReturn("vda"); // Current device
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertTrue(backupAnswer.getResult());
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithMountFailure() throws Exception {
 +        lenient().when(command.getVmName()).thenReturn("test-vm");
 +        lenient().when(command.getBackupPath()).thenReturn("backup/path");
 +        
lenient().when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        lenient().when(command.getBackupRepoType()).thenReturn("nfs");
 +        lenient().when(command.getMountOptions()).thenReturn("rw");
 +        lenient().when(command.isVmExists()).thenReturn(null);
 +        lenient().when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
lenient().when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
-         
lenient().when(command.getRestoreVolumeUUID()).thenReturn("volume-123");
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        
lenient().when(command.getVmState()).thenReturn(VirtualMachine.State.Running);
 +        lenient().when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(1); // Mount failure
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertFalse(backupAnswer.getResult());
 +                Assert.assertTrue(backupAnswer.getDetails().contains("Failed 
to mount the backup repository"));
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithBackupFileNotFound() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        when(command.getBackupRepoType()).thenReturn("nfs");
 +        when(command.getMountOptions()).thenReturn("rw");
 +        when(command.isVmExists()).thenReturn(null);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
-         when(command.getRestoreVolumeUUID()).thenReturn("volume-123");
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        when(command.getVmState()).thenReturn(VirtualMachine.State.Running);
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenAnswer(invocation -> {
 +                            String command = invocation.getArgument(0);
 +                            if (command.contains("ls ")) {
 +                                return 1; // File not found
 +                            }
 +                            return 0; // Other commands success
 +                        });
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertFalse(backupAnswer.getResult());
 +                Assert.assertTrue(backupAnswer.getDetails().contains("Backup 
file for the volume [volume-123] does not exist"));
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithCorruptBackupFile() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        when(command.getBackupRepoType()).thenReturn("nfs");
 +        when(command.getMountOptions()).thenReturn("rw");
 +        when(command.isVmExists()).thenReturn(null);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
-         when(command.getRestoreVolumeUUID()).thenReturn("volume-123");
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        when(command.getVmState()).thenReturn(VirtualMachine.State.Running);
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenAnswer(invocation -> {
 +                            String command = invocation.getArgument(0);
 +                            if (command.contains("ls ")) {
 +                                return 0; // File exists
 +                            } else if (command.contains("qemu-img check")) {
 +                                return 1; // Corrupt file
 +                            }
 +                            return 0; // Other commands success
 +                        });
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertFalse(backupAnswer.getResult());
 +                Assert.assertTrue(backupAnswer.getDetails().contains("Backup 
qcow2 file for the volume [volume-123] is corrupt"));
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithRsyncFailure() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        when(command.getBackupRepoType()).thenReturn("nfs");
 +        when(command.getMountOptions()).thenReturn("rw");
 +        when(command.isVmExists()).thenReturn(null);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
-         when(command.getRestoreVolumeUUID()).thenReturn("volume-123");
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        when(command.getVmState()).thenReturn(VirtualMachine.State.Running);
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenAnswer(invocation -> {
 +                            String command = invocation.getArgument(0);
 +                            if (command.contains("ls ")) {
 +                                return 0; // File exists
 +                            } else if (command.contains("qemu-img check")) {
 +                                return 0; // File is valid
 +                            } else if (command.contains("rsync")) {
 +                                return 1; // Rsync failure
 +                            }
 +                            return 0; // Other commands success
 +                        });
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertFalse(backupAnswer.getResult());
 +                Assert.assertTrue(backupAnswer.getDetails().contains("Unable 
to restore contents from the backup volume [volume-123]"));
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithAttachVolumeFailure() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        when(command.getBackupRepoType()).thenReturn("nfs");
 +        when(command.getMountOptions()).thenReturn("rw");
 +        when(command.isVmExists()).thenReturn(null);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
-         when(command.getRestoreVolumeUUID()).thenReturn("volume-123");
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        when(command.getVmState()).thenReturn(VirtualMachine.State.Running);
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenAnswer(invocation -> {
 +                            String command = invocation.getArgument(0);
 +                            if (command.contains("ls ")) {
 +                                return 0; // File exists
 +                            } else if (command.contains("qemu-img check")) {
 +                                return 0; // File is valid
 +                            } else if (command.contains("rsync")) {
 +                                return 0; // Rsync success
 +                            } else if (command.contains("virsh attach-disk")) 
{
 +                                return 1; // Attach failure
 +                            }
 +                            return 0; // Other commands success
 +                        });
 +                scriptMock.when(() -> Script.runSimpleBashScript(anyString()))
 +                        .thenReturn("vda"); // Current device
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertFalse(backupAnswer.getResult());
 +                Assert.assertTrue(backupAnswer.getDetails().contains("Failed 
to attach volume to VM: test-vm"));
 +            }
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithTempDirectoryCreationFailure() throws 
Exception {
 +        lenient().when(command.getVmName()).thenReturn("test-vm");
 +        lenient().when(command.getBackupPath()).thenReturn("backup/path");
 +        
lenient().when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        lenient().when(command.getBackupRepoType()).thenReturn("nfs");
 +        lenient().when(command.getMountOptions()).thenReturn("rw");
 +        lenient().when(command.isVmExists()).thenReturn(null);
 +        lenient().when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        
when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(primaryDataStore));
 +        
lenient().when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList("/var/lib/libvirt/images/volume-123"));
-         
lenient().when(command.getRestoreVolumeUUID()).thenReturn("volume-123");
++        
when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123"));
 +        
lenient().when(command.getVmState()).thenReturn(VirtualMachine.State.Running);
 +        lenient().when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            filesMock.when(() -> Files.createTempDirectory(anyString()))
 +                    .thenThrow(new IOException("Failed to create temp 
directory"));
 +
 +            Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +            Assert.assertNotNull(result);
 +            Assert.assertTrue(result instanceof BackupAnswer);
 +            BackupAnswer backupAnswer = (BackupAnswer) result;
 +            Assert.assertFalse(backupAnswer.getResult());
 +            Assert.assertTrue(backupAnswer.getDetails().contains("Failed to 
create the tmp mount directory for restore"));
 +        }
 +    }
 +
 +    @Test
 +    public void testExecuteWithMultipleVolumes() throws Exception {
 +        when(command.getVmName()).thenReturn("test-vm");
 +        when(command.getBackupPath()).thenReturn("backup/path");
 +        
when(command.getBackupRepoAddress()).thenReturn("192.168.1.100:/backup");
 +        when(command.getBackupRepoType()).thenReturn("nfs");
 +        when(command.getMountOptions()).thenReturn("rw");
 +        when(command.isVmExists()).thenReturn(true);
 +        when(command.getDiskType()).thenReturn("root");
 +        PrimaryDataStoreTO primaryDataStore1 = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        PrimaryDataStoreTO primaryDataStore2 = 
Mockito.mock(PrimaryDataStoreTO.class);
 +        when(command.getRestoreVolumePools()).thenReturn(Arrays.asList(
 +                primaryDataStore1,
 +                primaryDataStore2
 +        ));
 +        when(command.getRestoreVolumePaths()).thenReturn(Arrays.asList(
 +                "/var/lib/libvirt/images/volume-123",
 +                "/var/lib/libvirt/images/volume-456"
 +        ));
 +        
when(command.getBackupVolumesUUIDs()).thenReturn(Arrays.asList("volume-123", 
"volume-456"));
++        when(command.getBackupFiles()).thenReturn(Arrays.asList("volume-123", 
"volume-456"));
 +        when(command.getMountTimeout()).thenReturn(30);
 +
 +        try (MockedStatic<Files> filesMock = mockStatic(Files.class)) {
 +            Path tempPath = Mockito.mock(Path.class);
 +            when(tempPath.toString()).thenReturn("/tmp/csbackup.abc123");
 +            filesMock.when(() -> 
Files.createTempDirectory(anyString())).thenReturn(tempPath);
 +
 +            try (MockedStatic<Script> scriptMock = mockStatic(Script.class)) {
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString(), anyInt(), 
any(Boolean.class)))
 +                        .thenReturn(0); // Mount success
 +                scriptMock.when(() -> 
Script.runSimpleBashScriptForExitValue(anyString()))
 +                        .thenReturn(0); // All other commands success
 +
 +                filesMock.when(() -> 
Files.deleteIfExists(any(Path.class))).thenReturn(true);
 +
 +                Answer result = wrapper.execute(command, 
libvirtComputingResource);
 +
 +                Assert.assertNotNull(result);
 +                Assert.assertTrue(result instanceof BackupAnswer);
 +                BackupAnswer backupAnswer = (BackupAnswer) result;
 +                Assert.assertTrue(backupAnswer.getResult());
 +            }
 +        }
 +    }
 +}
diff --cc 
services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java
index ae02d7e8aa7,e98791822d0..aacca9926f7
--- 
a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java
+++ 
b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java
@@@ -32,11 -33,10 +34,11 @@@ import java.util.concurrent.Executors
  
  import javax.naming.ConfigurationException;
  
- import com.cloud.agent.api.Answer;
- 
- import com.cloud.agent.api.ConvertSnapshotCommand;
  import org.apache.cloudstack.storage.resource.SecondaryStorageResource;
+ import org.apache.commons.lang3.StringUtils;
  
+ import com.cloud.agent.api.Answer;
++import com.cloud.agent.api.ConvertSnapshotCommand;
  import com.cloud.agent.api.storage.CreateEntityDownloadURLAnswer;
  import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand;
  import com.cloud.agent.api.storage.DeleteEntityDownloadURLCommand;

Reply via email to