Refactor and marvin tests stabilization
diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java
index 907b93e..a2baf7c 100644
--- a/api/src/main/java/com/cloud/event/EventTypes.java
+++ b/api/src/main/java/com/cloud/event/EventTypes.java
@@ -584,6 +584,15 @@
     public static final String EVENT_TEMPLATE_DIRECT_DOWNLOAD_FAILURE = "TEMPLATE.DIRECT.DOWNLOAD.FAILURE";
     public static final String EVENT_ISO_DIRECT_DOWNLOAD_FAILURE = "ISO.DIRECT.DOWNLOAD.FAILURE";
 
+    // Backup and Recovery events
+    public static final String EVENT_ADD_VM_TO_BACKUP_POLICY = "ADD.VM.TO.BACKUP.POLICY";
+    public static final String EVENT_REMOVE_VM_FROM_BACKUP_POLICY = "REMOVE.VM.FROM.BACKUP.POLICY";
+    public static final String EVENT_IMPORT_BACKUP_POLICY = "IMPORT.BACKUP.POLICY";
+    public static final String EVENT_CREATE_VM_BACKUP = "CREATE.VM.BACKUP";
+    public static final String EVENT_DELETE_VM_BACKUP = "DELETE.VM.BACKUP";
+    public static final String EVENT_RESTORE_VM_FROM_BACKUP = "RESTORE.VM.FROM.BACKUP";
+    public static final String EVENT_RESTORE_VOLUME_FROM_BACKUP_AND_ATTACH_TO_VM = "RESTORE.VOLUME.FROM.BACKUP.AND.ATTACH.TO.VM";
+
     static {
 
         // TODO: need a way to force author adding event types to declare the entity details as well, with out braking
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ImportBackupPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ImportBackupPolicyCmd.java
index 1dbe033..c94b9e2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ImportBackupPolicyCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ImportBackupPolicyCmd.java
@@ -18,10 +18,12 @@
 
 import javax.inject.Inject;
 
+import com.cloud.event.EventTypes;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
@@ -43,7 +45,7 @@
         description = "Imports a backup policy from the backup provider",
         responseObject = BackupPolicyResponse.class, since = "4.12.0",
         authorized = {RoleType.Admin})
-public class ImportBackupPolicyCmd extends BaseCmd {
+public class ImportBackupPolicyCmd extends BaseAsyncCmd {
     public static final String APINAME = "importBackupPolicy";
 
     @Inject
@@ -122,4 +124,14 @@
     public long getEntityOwnerId() {
         return CallContext.current().getCallingAccount().getId();
     }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_IMPORT_BACKUP_POLICY;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Importing backup policy: " + policyName + " (externalId=" + policyExternalId + ") on zone " + zoneId ;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/AddVMToBackupPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/AddVMToBackupPolicyCmd.java
index c6d1219..3074188 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/AddVMToBackupPolicyCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/AddVMToBackupPolicyCmd.java
@@ -18,11 +18,12 @@
 
 import javax.inject.Inject;
 
+import com.cloud.event.EventTypes;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
-import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.BaseAsyncCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.BackupPolicyResponse;
@@ -41,7 +42,7 @@
         description = "Assigns a VM to an existing backup policy",
         responseObject = SuccessResponse.class, since = "4.12.0",
         authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
-public class AddVMToBackupPolicyCmd extends BaseCmd {
+public class AddVMToBackupPolicyCmd extends BaseAsyncCmd {
     public static final String APINAME = "addVMToBackupPolicy";
 
     @Inject
@@ -106,4 +107,14 @@
     public long getEntityOwnerId() {
         return CallContext.current().getCallingAccount().getId();
     }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_ADD_VM_TO_BACKUP_POLICY;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Adding VM " + vmId + " to backup policy " + policyId;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateVMBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateVMBackupCmd.java
index 6855c99..94a821a 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateVMBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateVMBackupCmd.java
@@ -19,15 +19,18 @@
 
 import javax.inject.Inject;
 
+import com.cloud.event.EventTypes;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.api.response.BackupResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.backup.Backup;
 import org.apache.cloudstack.backup.BackupManager;
 import org.apache.cloudstack.context.CallContext;
 
@@ -40,9 +43,9 @@
 
 @APICommand(name = CreateVMBackupCmd.APINAME,
         description = "Create VM backup",
-        responseObject = SuccessResponse.class, since = "4.12.0",
+        responseObject = BackupResponse.class, since = "4.12.0",
         authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
-public class CreateVMBackupCmd extends BaseCmd {
+public class CreateVMBackupCmd extends BaseAsyncCmd {
     public static final String APINAME = "createVMBackup";
 
     @Inject
@@ -76,10 +79,9 @@
     @Override
     public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
         try {
-            boolean result = backupManager.createBackup(vmId);
-            // FIXME: the response type
-            if (result) {
-                SuccessResponse response = new SuccessResponse(getCommandName());
+            Backup backup = backupManager.createBackup(vmId);
+            if (backup != null) {
+                BackupResponse response = _responseGenerator.createBackupResponse(backup);
                 response.setResponseName(getCommandName());
                 setResponseObject(response);
             } else {
@@ -99,4 +101,14 @@
     public long getEntityOwnerId() {
         return CallContext.current().getCallingAccount().getId();
     }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_CREATE_VM_BACKUP;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Creating backup for VM " + vmId;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteVMBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteVMBackupCmd.java
index 1faa628..fde8a9f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteVMBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DeleteVMBackupCmd.java
@@ -26,8 +26,8 @@
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.BackupResponse;
 import org.apache.cloudstack.api.response.SuccessResponse;
-import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.backup.BackupManager;
 import org.apache.cloudstack.context.CallContext;
 
@@ -52,19 +52,19 @@
     //////////////// API parameters /////////////////////
     /////////////////////////////////////////////////////
 
-    @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
+    @Parameter(name = ApiConstants.ID,
             type = CommandType.UUID,
-            entityType = UserVmResponse.class,
+            entityType = BackupResponse.class,
             required = true,
-            description = "id of the VM")
-    private Long vmId;
+            description = "id of backup")
+    private Long backupId;
 
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
 
-    public Long getVmId() {
-        return vmId;
+    public Long getId() {
+        return backupId;
     }
 
     /////////////////////////////////////////////////////
@@ -74,7 +74,7 @@
     @Override
     public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
         try {
-            boolean result = backupManager.deleteBackup(vmId);
+            boolean result = backupManager.deleteBackup(backupId);
             // FIXME: the response type
             if (result) {
                 SuccessResponse response = new SuccessResponse(getCommandName());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListVMBackupsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListVMBackupsCmd.java
index d444480..a9b183f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListVMBackupsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListVMBackupsCmd.java
@@ -31,7 +31,6 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.BackupResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
-import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.backup.Backup;
 import org.apache.cloudstack.backup.BackupManager;
 import org.apache.cloudstack.context.CallContext;
@@ -62,10 +61,6 @@
             description = "id of the VM")
     private Long vmId;
 
-    @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
-            description = "The zone ID")
-    private Long zoneId;
-
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -74,10 +69,6 @@
         return vmId;
     }
 
-    public Long getZoneId() {
-        return zoneId;
-    }
-
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -85,7 +76,7 @@
     @Override
     public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
         try{
-            List<Backup> backups = backupManager.listVMBackups(getZoneId(), getVmId());
+            List<Backup> backups = backupManager.listVMBackups(getVmId());
             setupResponseBackupList(backups);
         } catch (Exception e) {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicyCmd.java
index c9c5518..e28e670 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicyCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicyCmd.java
@@ -19,11 +19,12 @@
 
 import javax.inject.Inject;
 
+import com.cloud.event.EventTypes;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
-import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.BaseAsyncCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.BackupPolicyResponse;
@@ -42,7 +43,7 @@
         description = "Removes a VM from an existing backup policy",
         responseObject = SuccessResponse.class, since = "4.12.0",
         authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
-public class RemoveVMFromBackupPolicyCmd extends BaseCmd {
+public class RemoveVMFromBackupPolicyCmd extends BaseAsyncCmd {
     public static final String APINAME = "removeVMFromBackupPolicy";
 
     @Inject
@@ -108,4 +109,13 @@
         return CallContext.current().getCallingAccount().getId();
     }
 
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_REMOVE_VM_FROM_BACKUP_POLICY;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Removing VM " + vmId + " from backup policy " + policyId;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVMBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVMFromBackupCmd.java
similarity index 78%
rename from api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVMBackupCmd.java
rename to api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVMFromBackupCmd.java
index 7ffc881..019b535 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVMBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVMFromBackupCmd.java
@@ -19,17 +19,17 @@
 
 import javax.inject.Inject;
 
+import com.cloud.event.EventTypes;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.BackupResponse;
 import org.apache.cloudstack.api.response.SuccessResponse;
-import org.apache.cloudstack.api.response.UserVmResponse;
-import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.backup.BackupManager;
 import org.apache.cloudstack.context.CallContext;
 
@@ -40,12 +40,12 @@
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-@APICommand(name = RestoreVMBackupCmd.APINAME,
-        description = "Restore VM backup",
+@APICommand(name = RestoreVMFromBackupCmd.APINAME,
+        description = "Restore VM from backup",
         responseObject = SuccessResponse.class, since = "4.12.0",
         authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
-public class RestoreVMBackupCmd extends BaseCmd {
-    public static final String APINAME = "restoreVMBackup";
+public class RestoreVMFromBackupCmd extends BaseAsyncCmd {
+    public static final String APINAME = "restoreVMFromBackup";
 
     @Inject
     private BackupManager backupManager;
@@ -61,34 +61,14 @@
             description = "id of the backup")
     private Long backupId;
 
-    //FIXME: is this necessary when backup id is known? unless we want to restore to a different VM?
-    @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
-            type = CommandType.UUID,
-            entityType = UserVmResponse.class,
-            required = true,
-            description = "id of the VM")
-    private Long vmId;
-
-    @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
-            description = "The zone ID")
-    private Long zoneId;
-
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
 
-    public Long getVmId() {
-        return vmId;
-    }
-
     public Long getBackupId() {
         return backupId;
     }
 
-    public Long getZoneId() {
-        return zoneId;
-    }
-
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -96,7 +76,7 @@
     @Override
     public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
         try {
-            boolean result = backupManager.restoreBackup(zoneId, vmId, backupId);
+            boolean result = backupManager.restoreVMFromBackup(backupId);
             if (result) {
                 SuccessResponse response = new SuccessResponse(getCommandName());
                 response.setResponseName(getCommandName());
@@ -119,4 +99,13 @@
         return CallContext.current().getCallingAccount().getId();
     }
 
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_RESTORE_VM_FROM_BACKUP;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Restoring VM from backup " + backupId;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVolumeFromBackupAndAttachToVMCmd.java
similarity index 88%
rename from api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupVolumeCmd.java
rename to api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVolumeFromBackupAndAttachToVMCmd.java
index f9cbe26..1567e7f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVolumeFromBackupAndAttachToVMCmd.java
@@ -19,10 +19,12 @@
 
 import javax.inject.Inject;
 
+import com.cloud.event.EventTypes;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
@@ -30,7 +32,6 @@
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.api.response.VolumeResponse;
-import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.backup.BackupManager;
 import org.apache.cloudstack.context.CallContext;
 
@@ -41,12 +42,12 @@
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-@APICommand(name = RestoreBackupVolumeCmd.APINAME,
+@APICommand(name = RestoreVolumeFromBackupAndAttachToVMCmd.APINAME,
         description = "Restore and attach a backed up volume to VM",
         responseObject = SuccessResponse.class, since = "4.12.0",
         authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
-public class RestoreBackupVolumeCmd extends BaseCmd {
-    public static final String APINAME = "restoreBackupVolumeAndAttachToVM";
+public class RestoreVolumeFromBackupAndAttachToVMCmd extends BaseAsyncCmd {
+    public static final String APINAME = "restoreVolumeFromBackupAndAttachToVM";
 
     @Inject
     private BackupManager backupManager;
@@ -79,10 +80,6 @@
             description = "id of the VM where to attach the restored volume")
     private Long vmId;
 
-    @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
-            description = "The zone ID")
-    private Long zoneId;
-
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -99,10 +96,6 @@
         return backupId;
     }
 
-    public Long getZoneId() {
-        return zoneId;
-    }
-
     @Override
     public String getCommandName() {
         return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
@@ -120,7 +113,7 @@
     @Override
     public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
         try {
-            boolean result = backupManager.restoreBackupVolumeAndAttachToVM(zoneId, volumeId, vmId, backupId);
+            boolean result = backupManager.restoreBackupVolumeAndAttachToVM(volumeId, vmId, backupId);
             if (result) {
                 SuccessResponse response = new SuccessResponse(getCommandName());
                 response.setResponseName(getCommandName());
@@ -132,4 +125,14 @@
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
         }
     }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_RESTORE_VOLUME_FROM_BACKUP_AND_ATTACH_TO_VM;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Restoring volume "+ volumeId + " from backup " + backupId + " and attaching it to VM " + vmId;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
index 77e916a..2cc58af 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
@@ -24,6 +24,7 @@
 import org.apache.cloudstack.api.EntityReference;
 import org.apache.cloudstack.backup.Backup;
 
+import java.util.Date;
 import java.util.List;
 
 @EntityReference(value = Backup.class)
@@ -69,6 +70,10 @@
     @Param(description = "backup volume ids")
     private Backup.Status status;
 
+    @SerializedName(ApiConstants.START_DATE)
+    @Param(description = "backup start date")
+    private Date startDate;
+
     public String getId() {
         return id;
     }
@@ -148,4 +153,12 @@
     public void setVolumeIds(List<String> volumeIds) {
         this.volumeIds = volumeIds;
     }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/backup/Backup.java b/api/src/main/java/org/apache/cloudstack/backup/Backup.java
index 9ffbf4a..79d4626 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/Backup.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/Backup.java
@@ -39,4 +39,5 @@
     List<Long> getVolumeIds();
     Status getStatus();
     Date getStartTime();
+    Date getRemoved();
 }
diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
index 0a83ee0..c25ef18 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
@@ -67,7 +67,7 @@
     /**
      * List existing backups for a VM
      */
-    List<Backup> listVMBackups(Long zoneId, Long vmId);
+    List<Backup> listVMBackups(Long vmId);
 
     /**
      * List backup policies
@@ -82,24 +82,23 @@
      * @param vmId Virtual Machine ID
      * @return returns operation success
      */
-    boolean createBackup(Long vmId);
+    Backup createBackup(Long vmId);
 
     /**
-     * Deletes backup of a VM
-     * @param vmId Virtual Machine ID
+     * Deletes a backup
      * @return returns operation success
      */
-    boolean deleteBackup(Long vmId);
+    boolean deleteBackup(Long backupId);
 
     /**
-     * Restore a full backed up VM
+     * Restore a full VM from backup
      */
-    boolean restoreBackup(Long zoneId, Long vmId, Long backupId);
+    boolean restoreVMFromBackup(Long backupId);
 
     /**
      * Restore a backed up volume and attach it to a VM
      */
-    boolean restoreBackupVolumeAndAttachToVM(Long zoneId, Long volumeId, Long vmId, Long backupId);
+    boolean restoreBackupVolumeAndAttachToVM(Long volumeId, Long vmId, Long backupId);
 
     /**
      * Deletes a backup policy
diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java b/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
index 0e3980b..4e857ae 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
@@ -63,7 +63,7 @@
      * @param vm
      * @return true if backup successfully starts
      */
-    boolean startBackup(BackupPolicy policy, VirtualMachine vm);
+    Backup createVMBackup(BackupPolicy policy, VirtualMachine vm);
 
     /**
      * Restore VM from backup
@@ -79,4 +79,9 @@
      * List VM Backups
      */
     List<Backup> listVMBackups(Long zoneId, VirtualMachine vm);
+
+    /**
+     * Remove a VM backup
+     */
+    boolean removeVMBackup(VirtualMachine vm, String backupId);
 }
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupTO.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupTO.java
index 61f0b90..6b3c24c 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupTO.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupTO.java
@@ -165,6 +165,11 @@
         return startTime;
     }
 
+    @Override
+    public Date getRemoved() {
+        return null;
+    }
+
     public void setStartTime(Date startTime) {
         this.startTime = startTime;
     }
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java
index f7b3f78..9a6f04c 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java
@@ -71,7 +71,7 @@
     private Long parentId;
 
     @Column(name = "vm_id")
-    private long vmId;
+    private Long vmId;
 
     @Column(name = "volumes")
     private String volumes;
@@ -83,6 +83,10 @@
     @Temporal(value = TemporalType.TIMESTAMP)
     private Date startTime;
 
+    @Column(name = "removed")
+    @Temporal(value = TemporalType.TIMESTAMP)
+    private Date removed;
+
     @Transient
     private List<Long> volumeIds;
 
@@ -173,7 +177,7 @@
         this.parentId = parentId;
     }
 
-    public void setVmId(long vmId) {
+    public void setVmId(Long vmId) {
         this.vmId = vmId;
     }
 
@@ -224,6 +228,14 @@
         }
     }
 
+    public Date getRemoved() {
+        return removed;
+    }
+
+    public void setRemoved(Date removed) {
+        this.removed = removed;
+    }
+
     protected String getVolumes() {
         return volumes;
     }
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupDao.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupDao.java
index fb6f01b..9bb8ea1 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupDao.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupDao.java
@@ -30,4 +30,5 @@
     List<Backup> syncVMBackups(Long zoneId, Long vmId, List<Backup> externalBackups);
 
     BackupResponse newBackupResponse(Backup backup);
+    BackupVO getBackupVO(Backup backup);
 }
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupDaoImpl.java
index 0661ab8..f10d2f9 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupDaoImpl.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupDaoImpl.java
@@ -82,7 +82,7 @@
         return findOneBy(sc);
     }
 
-    private BackupVO getBackupVO(Backup backup) {
+    public BackupVO getBackupVO(Backup backup) {
         BackupVO backupVO = new BackupVO();
         backupVO.setZoneId(backup.getZoneId());
         backupVO.setAccountId(backup.getAccountId());
@@ -146,6 +146,7 @@
             backupResponse.setVolumeIds(volIds);
         }
         backupResponse.setStatus(backup.getStatus());
+        backupResponse.setStartDate(backup.getStartTime());
         backupResponse.setObjectName("backup");
         return backupResponse;
     }
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41110to41200.sql b/engine/schema/src/main/resources/META-INF/db/schema-41110to41200.sql
index c347f7a..4e69653 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41110to41200.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41110to41200.sql
@@ -64,14 +64,15 @@
   `uuid` varchar(40) NOT NULL,
   `account_id` bigint(20) unsigned NOT NULL,
   `zone_id` bigint(20) unsigned NOT NULL,
-  `external_id` varchar(40) NOT NULL COMMENT 'backup ID on provider side',
+  `external_id` varchar(80) NOT NULL COMMENT 'backup ID on provider side',
   `name` varchar(255) NOT NULL COMMENT 'backup name',
   `description` varchar(255) COMMENT 'backup description',
   `parent_id` bigint(20) unsigned COMMENT 'backup parent id',
   `vm_id` bigint(20) unsigned NOT NULL,
   `volumes` varchar(100),
   `status` varchar(20) NOT NULL,
-  `start` timestamp,
+  `start` datetime DEFAULT NULL,
+  `removed` datetime DEFAULT NULL,
   PRIMARY KEY (`id`),
   CONSTRAINT `fk_backup__account_id` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE,
   CONSTRAINT `fk_backup__zone_id` FOREIGN KEY (`zone_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE,
diff --git a/plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java b/plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java
index 8916451..0aacf91 100644
--- a/plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java
+++ b/plugins/backup/dummy/src/main/java/org/apache/cloudstack/backup/DummyBackupProvider.java
@@ -17,9 +17,11 @@
 package org.apache.cloudstack.backup;
 
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
 
+import org.apache.cloudstack.backup.dao.BackupDao;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.to.VolumeTO;
@@ -28,10 +30,15 @@
 import com.cloud.utils.component.AdapterBase;
 import com.cloud.vm.VirtualMachine;
 
+import javax.inject.Inject;
+
 public class DummyBackupProvider extends AdapterBase implements BackupProvider {
 
     private static final Logger s_logger = Logger.getLogger(DummyBackupProvider.class);
 
+    @Inject
+    private BackupDao backupDao;
+
     @Override
     public String getName() {
         return "dummy";
@@ -69,8 +76,24 @@
     }
 
     @Override
-    public boolean startBackup(BackupPolicy policy, VirtualMachine vm) {
-        return true;
+    public Backup createVMBackup(BackupPolicy policy, VirtualMachine vm) {
+        s_logger.debug("Creating VM backup for VM " + vm.getInstanceName() + " from backup policy " + policy.getName());
+
+        List<Backup> backups = backupDao.listByVmId(vm.getDataCenterId(), vm.getId());
+        String backupNumber = String.valueOf(backups.size() + 1);
+        Backup lastBackup = null;
+        if (backups.size() > 0) {
+            backups.sort(Comparator.comparing(Backup::getStartTime));
+            lastBackup = backups.get(backups.size() - 1);
+        }
+        BackupTO newBackup = new BackupTO(vm.getDataCenterId(), vm.getAccountId(),
+                "xxxx-xxxx-" + vm.getUuid() + "-" + backupNumber, "Backup-" + vm.getUuid() + backupNumber,
+                "VM-" + vm.getInstanceName() + "-backup-" + backupNumber,
+                lastBackup != null ? lastBackup.getExternalId() : null, vm.getId(), null,
+                Backup.Status.BackedUp, new Date());
+        backups.add(newBackup);
+
+        return newBackup;
     }
 
     @Override
@@ -89,15 +112,19 @@
     @Override
     public List<Backup> listVMBackups(Long zoneId, VirtualMachine vm) {
         s_logger.debug("Listing VM " + vm.getInstanceName() + "backups on the Dummy Backup Provider");
+        return backupDao.listByVmId(vm.getDataCenterId(), vm.getId());
+    }
 
-        BackupTO backup1 = new BackupTO(zoneId, vm.getAccountId(),
-                "xxxx-xxxx", "Backup-1", "VM-" + vm.getInstanceName() + "-backup-1",
-                null, vm.getId(), null, Backup.Status.BackedUp, new Date());
+    @Override
+    public boolean removeVMBackup(VirtualMachine vm, String backupId) {
+        s_logger.debug("Removing VM backup " + backupId + " for VM " + vm.getInstanceName() + " on the Dummy Backup Provider");
 
-        BackupTO backup2 = new BackupTO(zoneId, vm.getAccountId(), "yyyy-yyyy",
-                "Backup-2", "VM-" + vm.getInstanceName() + "-backup-2",
-                backup1.getExternalId(), vm.getId(), null, Backup.Status.BackedUp, new Date());
-
-        return Arrays.asList(backup1, backup2);
+        List<Backup> backups = backupDao.listByVmId(vm.getDataCenterId(), vm.getId());
+        for (Backup backup : backups) {
+            if (backup.getExternalId().equals(backupId)) {
+                return true;
+            }
+        }
+        return false;
     }
 }
diff --git a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java
index 9bed15b..84e442a 100644
--- a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java
+++ b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java
@@ -128,8 +128,10 @@
     }
 
     @Override
-    public boolean startBackup(BackupPolicy policy, VirtualMachine vm) {
-        return getClient(vm.getDataCenterId()).startBackupJob(policy.getExternalId());
+    public Backup createVMBackup(BackupPolicy policy, VirtualMachine vm) {
+        //TODO: Return backup
+        getClient(vm.getDataCenterId()).startBackupJob(policy.getExternalId());
+        return null;
     }
 
     @Override
@@ -151,6 +153,12 @@
     }
 
     @Override
+    public boolean removeVMBackup(VirtualMachine vm, String backupId) {
+        //TODO: Implement
+        return false;
+    }
+
+    @Override
     public String getConfigComponentName() {
         return BackupService.class.getSimpleName();
     }
diff --git a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamBackup.java b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamBackup.java
index a72e8d2..285542a 100644
--- a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamBackup.java
+++ b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamBackup.java
@@ -83,6 +83,11 @@
     }
 
     @Override
+    public Date getRemoved() {
+        return null;
+    }
+
+    @Override
     public String getUuid() {
         return uid;
     }
diff --git a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
index 623bac5..b57ab16 100644
--- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
@@ -25,6 +25,8 @@
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.event.ActionEvent;
+import com.cloud.event.EventTypes;
 import org.apache.cloudstack.api.command.admin.backup.DeleteBackupPolicyCmd;
 import org.apache.cloudstack.api.command.admin.backup.ImportBackupPolicyCmd;
 import org.apache.cloudstack.api.command.admin.backup.ListBackupProvidersCmd;
@@ -35,14 +37,13 @@
 import org.apache.cloudstack.api.command.user.backup.ListBackupPolicyVMMappingsCmd;
 import org.apache.cloudstack.api.command.user.backup.ListVMBackupsCmd;
 import org.apache.cloudstack.api.command.user.backup.RemoveVMFromBackupPolicyCmd;
-import org.apache.cloudstack.api.command.user.backup.RestoreBackupVolumeCmd;
-import org.apache.cloudstack.api.command.user.backup.RestoreVMBackupCmd;
+import org.apache.cloudstack.api.command.user.backup.RestoreVolumeFromBackupAndAttachToVMCmd;
+import org.apache.cloudstack.api.command.user.backup.RestoreVMFromBackupCmd;
 import org.apache.cloudstack.backup.dao.BackupDao;
 import org.apache.cloudstack.backup.dao.BackupPolicyDao;
 import org.apache.cloudstack.backup.dao.BackupPolicyVMMapDao;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.framework.config.ConfigKey;
-import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.BooleanUtils;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
@@ -89,6 +90,7 @@
     private List<BackupProvider> backupProviders;
 
     @Override
+    @ActionEvent(eventType = EventTypes.EVENT_IMPORT_BACKUP_POLICY, eventDescription = "importing backup policy", async = true)
     public BackupPolicy importBackupPolicy(Long zoneId, String policyExternalId, String policyName, String policyDescription) {
         final BackupProvider provider = getBackupProvider(zoneId);
         if (!provider.isBackupPolicy(zoneId, policyExternalId)) {
@@ -105,6 +107,7 @@
     }
 
     @Override
+    @ActionEvent(eventType = EventTypes.EVENT_ADD_VM_TO_BACKUP_POLICY, eventDescription = "adding VM to backup policy", async = true)
     public boolean addVMToBackupPolicy(Long policyId, Long virtualMachineId) {
         VMInstanceVO vm = vmInstanceDao.findById(virtualMachineId);
         if (vm == null) {
@@ -132,6 +135,7 @@
     }
 
     @Override
+    @ActionEvent(eventType = EventTypes.EVENT_REMOVE_VM_FROM_BACKUP_POLICY, eventDescription = "removing VM from backup policy", async = true)
     public boolean removeVMFromBackupPolicy(Long policyId, Long vmId) {
         BackupPolicyVO policy = backupPolicyDao.findById(policyId);
         if (policy == null) {
@@ -171,19 +175,15 @@
     }
 
     @Override
-    public List<Backup> listVMBackups(Long zoneId, Long vmId) {
-        BackupProvider backupProvider = getBackupProvider(zoneId);
+    //TODO: Add background job to sync VM backups from the provider
+    public List<Backup> listVMBackups(Long vmId) {
         VMInstanceVO vm = vmInstanceDao.findById(vmId);
         if (vm == null) {
             throw new CloudRuntimeException("VM " + vmId + " does not exist");
         }
-        List<Backup> existingBackups = backupDao.listByVmId(zoneId, vmId);
-        if (CollectionUtils.isNotEmpty(existingBackups)) {
-            return existingBackups;
-        } else {
-            List<Backup> externalBackups = backupProvider.listVMBackups(zoneId, vm);
-            return backupDao.syncVMBackups(zoneId, vmId, externalBackups);
-        }
+        Long zoneId = vm.getDataCenterId();
+        BackupProvider backupProvider = getBackupProvider(zoneId);
+        return backupDao.listByVmId(zoneId, vmId);
     }
 
     /**
@@ -229,48 +229,76 @@
     }
 
     @Override
-    public boolean createBackup(Long vmId) {
+    @ActionEvent(eventType = EventTypes.EVENT_CREATE_VM_BACKUP, eventDescription = "creating VM backup", async = true)
+    public Backup createBackup(Long vmId) {
         VMInstanceVO vm = vmInstanceDao.findById(vmId);
         if (vm == null) {
             throw new CloudRuntimeException("VM does not exist");
         }
         BackupPolicyVMMap vmMap = backupPolicyVMMapDao.findByVMId(vmId);
+        if (vmMap == null) {
+            throw new CloudRuntimeException("VM " + vmId + " is not assigned to any backup policy");
+        }
         BackupPolicyVO policy = backupPolicyDao.findById(vmMap.getPolicyId());
         if (policy == null) {
             throw new CloudRuntimeException("Policy does not exist");
         }
         BackupProvider backupProvider = getBackupProvider(vm.getDataCenterId());
-        // FIXME: on successfully started, add an entry in DB?
-        return backupProvider.startBackup(policy, vm);
+
+        Backup vmBackup = backupProvider.createVMBackup(policy, vm);
+        if (vmBackup == null) {
+            return null;
+        }
+        BackupVO backupVO = backupDao.getBackupVO(vmBackup);
+        return backupDao.persist(backupVO);
     }
 
     @Override
-    public boolean deleteBackup(Long vmId) {
-        // TODO: implement me
-        return false;
-    }
-
-    @Override
-    public boolean restoreBackup(Long zoneId, Long vmId, Long backupId) {
-        BackupProvider backupProvider = getBackupProvider(zoneId);
+    @ActionEvent(eventType = EventTypes.EVENT_DELETE_VM_BACKUP, eventDescription = "deleting VM backup", async = true)
+    public boolean deleteBackup(Long backupId) {
+        BackupVO backup = backupDao.findById(backupId);
+        if (backup == null) {
+            throw new CloudRuntimeException("Backup " + backupId + " does not exist");
+        }
+        Long zoneId = backup.getZoneId();
+        Long vmId = backup.getVmId();
         VMInstanceVO vm = vmInstanceDao.findById(vmId);
         if (vm == null) {
             throw new CloudRuntimeException("VM " + vmId + " does not exist");
         }
+        BackupProvider backupProvider = getBackupProvider(backup.getZoneId());
+        boolean result = backupProvider.removeVMBackup(vm, backup.getExternalId());
+        if (result) {
+            backupDao.remove(backupId);
+        }
+        return result;
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_RESTORE_VM_FROM_BACKUP, eventDescription = "restoring VM from backup", async = true)
+    public boolean restoreVMFromBackup(Long backupId) {
         BackupVO backup = backupDao.findById(backupId);
         if (backup == null) {
             throw new CloudRuntimeException("Backup " + backupId + " does not exist");
         }
+        Long vmId = backup.getVmId();
+        BackupProvider backupProvider = getBackupProvider(backup.getZoneId());
+        VMInstanceVO vm = vmInstanceDao.findById(vmId);
+        if (vm == null) {
+            throw new CloudRuntimeException("VM " + vmId + " does not exist");
+        }
         return backupProvider.restoreVMFromBackup(vm.getUuid(), backup.getUuid());
     }
 
     @Override
-    public boolean restoreBackupVolumeAndAttachToVM(Long zoneId, Long volumeId, Long vmId, Long backupId) {
-        BackupProvider backupProvider = getBackupProvider(zoneId);
+    @ActionEvent(eventType = EventTypes.EVENT_RESTORE_VM_FROM_BACKUP, eventDescription = "restoring VM from backup", async = true)
+    public boolean restoreBackupVolumeAndAttachToVM(Long volumeId, Long vmId, Long backupId) {
         BackupVO backup = backupDao.findById(backupId);
         if (backup == null) {
             throw new CloudRuntimeException("Backup " + backupId + " does not exist");
         }
+        BackupProvider backupProvider = getBackupProvider(backup.getZoneId());
+
         VMInstanceVO vm = vmInstanceDao.findById(vmId);
         if (vm == null) {
             throw new CloudRuntimeException("VM " + vmId + " does not exist");
@@ -346,8 +374,8 @@
         cmdList.add(ListVMBackupsCmd.class);
         cmdList.add(CreateVMBackupCmd.class);
         cmdList.add(DeleteVMBackupCmd.class);
-        cmdList.add(RestoreVMBackupCmd.class);
-        cmdList.add(RestoreBackupVolumeCmd.class);
+        cmdList.add(RestoreVMFromBackupCmd.class);
+        cmdList.add(RestoreVolumeFromBackupAndAttachToVMCmd.class);
 
         return cmdList;
     }
diff --git a/test/integration/smoke/test_backup_recovery.py b/test/integration/smoke/test_backup_recovery.py
index b976434..f9a00b9 100644
--- a/test/integration/smoke/test_backup_recovery.py
+++ b/test/integration/smoke/test_backup_recovery.py
@@ -18,7 +18,7 @@
 
 from marvin.cloudstackTestCase import cloudstackTestCase
 from marvin.lib.utils import (cleanup_resources)
-from marvin.lib.base import (Account, ServiceOffering, VirtualMachine, BackupPolicy, Configurations)
+from marvin.lib.base import (Account, ServiceOffering, VirtualMachine, BackupPolicy, Configurations, VMBackup)
 from marvin.lib.common import (get_domain, get_zone, get_template)
 from nose.plugins.attrib import attr
 from marvin.codes import FAILED
@@ -50,8 +50,8 @@
 
         # Check backup configuration values, set them to enable the dummy provider
 
-        backup_enabled_cfg = Configurations.list(cls.api_client, name='backup.framework.enabled')
-        backup_provider_cfg = Configurations.list(cls.api_client, name='backup.framework.provider.plugin')
+        backup_enabled_cfg = Configurations.list(cls.api_client, name='backup.framework.enabled', zoneid=cls.zone.id)
+        backup_provider_cfg = Configurations.list(cls.api_client, name='backup.framework.provider.plugin', zoneid=cls.zone.id)
         cls.backup_enabled = backup_enabled_cfg[0].value
         cls.backup_provider = backup_provider_cfg[0].value
 
@@ -110,20 +110,24 @@
         # 3. Delete backup policy
         # 4. List internal backup policies, policy id should not be listed
 
+        # Import backup policy
         ext_policy = self.external_policies[1]
         self.debug("Importing backup policy %s - %s" % (ext_policy.externalid, ext_policy.name))
         policy = BackupPolicy.importExisting(self.apiclient, self.zone.id, ext_policy.externalid,
                                              ext_policy.name, ext_policy.description)
 
+        # Verify policy is listed
         imported_policies = BackupPolicy.listInternal(self.apiclient, self.zone.id)
         self.assertIsInstance(imported_policies, list, "List Backup Policies should return a valid response")
         self.assertNotEqual(len(imported_policies), 0, "Check if the list API returns a non-empty response")
         matching_policies = [x for x in imported_policies if x.id == policy.id]
         self.assertNotEqual(len(matching_policies), 0, "Check if there is a matching policy")
 
+        # Delete backup policy
         self.debug("Deleting backup policy %s" % policy.id)
         policy.delete(self.apiclient)
 
+        #  Verify policy is not listed
         imported_policies = BackupPolicy.listInternal(self.apiclient, self.zone.id)
         self.assertIsInstance(imported_policies, list, "List Backup Policies should return a valid response")
         matching_policies = [x for x in imported_policies if x.id == policy.id]
@@ -141,28 +145,58 @@
         # 3. Remove VM from backup policy
         # 4. Verify there is no mapping between the VM and the backup policy
 
+        # Add VM to backup policy
         self.debug("Adding VM %s to backup policy %s" % (self.vm.id, self.policy.id))
-        self.policy.addVM(self.apiclient, self.vm.id, self.zone.id)
+        self.policy.addVM(self.apiclient, self.vm.id)
 
         # Verify a mapping between backup policy and VM is created on DB
-        qresultset = self.dbclient.execute("select id from vm_instance where uuid='%s';" % self.vm.id)
-        vm_id = qresultset[0][0]
+        mappings = BackupPolicy.listVMMappings(self.apiclient, self.policy.id, self.vm.id, self.zone.id)
+        self.assertNotEqual(len(mappings), 0, "A mapping between VM and backup policy should exist")
+        self.assertNotEqual(mappings[0], None, "A mapping between VM and backup policy should exist")
 
-        qresultset = self.dbclient.execute("select id from backup_policy where uuid='%s';" % self.policy.id)
-        policy_id = qresultset[0][0]
-
-        qresultset = self.dbclient.execute("select id from backup_policy_vm_map where policy_id='%d' and vm_id = '%d';"
-                                           % (policy_id, vm_id))
-
-        map = qresultset[0]
-        self.assertNotEqual(len(map), 0, "A mapping between VM and backup policy should exist on DB")
-        self.assertNotEqual(map[0], None, "A mapping between VM and backup policy should exist on DB")
-
+        # Remove VM from backup policy
         self.debug("Removing VM %s from backup policy %s" % (self.vm.id, self.policy.id))
-        self.policy.removeVM(self.apiclient, self.vm.id, self.zone.id)
+        self.policy.removeVM(self.apiclient, self.vm.id)
 
-        # Verify mapping is removed from DB
-        qresultset = self.dbclient.execute("select id from backup_policy_vm_map where policy_id='%d' and vm_id = '%d';"
-                                           % (policy_id, vm_id))
+        # Verify mapping is removed
+        zone_mappings = BackupPolicy.listVMMappings(self.apiclient, zoneid=self.zone.id)
+        matching_mappings = [x for x in zone_mappings if x.policyid == self.policy.id and x.virtualmachineid == self.vm.id]
+        self.assertEqual(len(matching_mappings), 0, "The mapping between VM and backup policy should be removed")
 
-        self.assertEqual(len(qresultset), 0, "The mapping between VM and backup policy should be removed from DB")
+    @attr(tags=["advanced", "backup"], required_hardware="false")
+    def test_vm_backup_lifecycle(self):
+        """
+        Test VM backup lifecycle
+        """
+
+        # Validate the following:
+        # 1. List VM backups, verify no backups are created
+        # 2. Add VM to policy
+        # 3. Create VM backup
+        # 4. List VM backups, verify backup is created
+        # 5. Delete VM backup
+        # 6. List VM backups, verify backup is deleted
+        # 7. Remove VM from policy
+
+        # Verify there are no backups for the VM
+        backups = VMBackup.list(self.apiclient, self.vm.id)
+        self.assertEqual(backups, None, "There should not exist any backup for the VM")
+
+        # Create a VM backup
+        self.policy.addVM(self.apiclient, self.vm.id)
+        VMBackup.create(self.apiclient, self.vm.id)
+
+        # Verify backup is created for the VM
+        backups = VMBackup.list(self.apiclient, self.vm.id)
+        self.assertEqual(len(backups), 1, "There should exist only one backup for the VM")
+        backup = backups[0]
+
+        # Delete backup
+        VMBackup.delete(self.apiclient, backup.id)
+
+        # Verify backup is deleted
+        backups = VMBackup.list(self.apiclient, self.vm.id)
+        self.assertEqual(backups, None, "There should not exist any backup for the VM")
+
+        # Remove VM from policy
+        self.policy.removeVM(self.apiclient, self.vm.id)
\ No newline at end of file
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index 6087753..56eaab2 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -5426,20 +5426,76 @@
         cmd.id = self.id
         return (apiclient.deleteBackupPolicy(cmd))
 
-    def addVM(self, apiclient, vmid, zoneid):
+    def addVM(self, apiclient, vmid):
         """Add a VM to a backup policy"""
 
-        cmd = addVirtualMachineToBackupPolicy.addVirtualMachineToBackupPolicyCmd()
-        cmd.backuppolicyid = self.id
+        cmd = addVMToBackupPolicy.addVMToBackupPolicyCmd()
+        cmd.policyid = self.id
         cmd.virtualmachineid = vmid
-        cmd.zoneid = zoneid
-        return (apiclient.addVirtualMachineToBackupPolicy(cmd))
+        return (apiclient.addVMToBackupPolicy(cmd))
 
-    def removeVM(self, apiclient, vmid, zoneid):
+    def removeVM(self, apiclient, vmid):
         """Remove a VM from a backup policy"""
 
-        cmd = removeVirtualMachineFromBackupPolicy.removeVirtualMachineFromBackupPolicyCmd()
-        cmd.backuppolicyid = self.id
+        cmd = removeVMFromBackupPolicy.removeVMFromBackupPolicyCmd()
+        cmd.policyid = self.id
         cmd.virtualmachineid = vmid
-        cmd.zoneid = zoneid
-        return (apiclient.removeVirtualMachineFromBackupPolicy(cmd))
\ No newline at end of file
+        return (apiclient.removeVMFromBackupPolicy(cmd))
+
+    @classmethod
+    def listVMMappings(self, apiclient, policyid=None, vmid=None, zoneid=None):
+        """List VM - Backup policies mappings"""
+
+        cmd = listBackupPolicyVMMappings.listBackupPolicyVMMappingsCmd()
+        if vmid:
+            cmd.virtualmachineid = vmid
+        if zoneid:
+            cmd.zoneid = zoneid
+        if policyid:
+            cmd.policyid = policyid
+        return (apiclient.listBackupPolicyVMMappings(cmd))
+
+class VMBackup:
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(self, apiclient, vmid):
+        """Create VM backup"""
+
+        cmd = createVMBackup.createVMBackupCmd()
+        cmd.virtualmachineid = vmid
+        return (apiclient.createVMBackup(cmd))
+
+    @classmethod
+    def delete(self, apiclient, id):
+        """Delete VM backup"""
+
+        cmd = deleteVMBackup.deleteVMBackupCmd()
+        cmd.id = id
+        return (apiclient.deleteVMBackup(cmd))
+
+    @classmethod
+    def list(self, apiclient, vmid):
+        """List VM backups"""
+
+        cmd = listVMBackups.listVMBackupsCmd()
+        cmd.virtualmachineid = vmid
+        return (apiclient.listVMBackups(cmd))
+
+    def restoreVM(self, apiclient):
+        """Restore VM from backup"""
+
+        cmd = restoreVMFromBackup.restoreVMFromBackupCmd()
+        cmd.id = self.id
+        return (apiclient.restoreVMFromBackup(cmd))
+
+    def restoreVolumeAndAttachToVM(self, apiclient, volumeid, vmid):
+        """Restore volume from backup and attach it to VM"""
+
+        cmd = restoreVolumeFromBackupAndAttachToVM.restoreVolumeFromBackupAndAttachToVMCmd()
+        cmd.id = self.id
+        cmd.volumeid = volumeid
+        cmd.virtualmachineid = vmid
+        return (apiclient.restoreVolumeFromBackupAndAttachToVM(cmd))
\ No newline at end of file