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 b61255af605..97beea3ea91 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 @@ -108,7 +108,7 @@ public class ImportBackupPolicyCmd extends BaseCmd { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { try { - BackupPolicy policy = backupManager.addBackupPolicy(zoneId, policyExternalId, policyName, description); + BackupPolicy policy = backupManager.importBackupPolicy(zoneId, policyExternalId, policyName, description); if (policy != null) { BackupPolicyResponse response = _responseGenerator.createBackupPolicyResponse(policy); response.setResponseName(getCommandName()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/AssignBackupPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/AddVMToBackupPolicyCmd.java similarity index 90% rename from api/src/main/java/org/apache/cloudstack/api/command/user/backup/AssignBackupPolicyCmd.java rename to api/src/main/java/org/apache/cloudstack/api/command/user/backup/AddVMToBackupPolicyCmd.java index aca2457e201..487460874ef 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/AssignBackupPolicyCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/AddVMToBackupPolicyCmd.java @@ -38,12 +38,12 @@ import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; -@APICommand(name = AssignBackupPolicyCmd.APINAME, +@APICommand(name = AddVMToBackupPolicyCmd.APINAME, 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 AssignBackupPolicyCmd extends BaseCmd { - public static final String APINAME = "assignBackupPolicy"; +public class AddVMToBackupPolicyCmd extends BaseCmd { + public static final String APINAME = "addVirtualMachineToBackupPolicy"; @Inject BackupManager backupManager; @@ -88,7 +88,7 @@ public class AssignBackupPolicyCmd extends BaseCmd { @Override public String getCommandName() { - return AssignBackupPolicyCmd.APINAME + RESPONSE_SUFFIX; + return AddVMToBackupPolicyCmd.APINAME.toLowerCase() + RESPONSE_SUFFIX; } @Override @@ -103,10 +103,7 @@ public class AssignBackupPolicyCmd extends BaseCmd { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { try { - Long virtualMachineId = getVirtualMachineId(); - Long policyId = getPolicyId(); - Long zoneId = getZoneId(); - boolean result = backupManager.assignVMToBackupPolicy(zoneId, policyId, virtualMachineId); + boolean result = backupManager.addVMToBackupPolicy(zoneId, policyId, virtualMachineId); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); response.setResponseName(getCommandName()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupPoliciesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupPoliciesCmd.java index 35c012cfaf0..78ef2165ade 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupPoliciesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupPoliciesCmd.java @@ -54,8 +54,12 @@ public class ListBackupPoliciesCmd extends BaseBackupListCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, entityType = BackupPolicyResponse.class, + description = "The backup policy ID") + private Long policyId; + @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class, - description = "The zone ID", required = true) + description = "The zone ID") private Long zoneId; @Parameter(name = ApiConstants.EXTERNAL, type = CommandType.BOOLEAN, @@ -74,6 +78,10 @@ public class ListBackupPoliciesCmd extends BaseBackupListCmd { return BooleanUtils.isTrue(external); } + public Long getPolicyId() { + return policyId; + } + @Override public String getCommandName() { return APINAME.toLowerCase() + RESPONSE_SUFFIX; @@ -86,7 +94,7 @@ public class ListBackupPoliciesCmd extends BaseBackupListCmd { @Override public void execute() throws ResourceUnavailableException, ServerApiException, ConcurrentOperationException { try { - List backupPolicies = backupManager.listBackupPolicies(zoneId, external); + List backupPolicies = backupManager.listBackupPolicies(zoneId, external, policyId); setupResponseBackupPolicyList(backupPolicies); } catch (InvalidParameterValueException e) { throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicy.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicy.java new file mode 100644 index 00000000000..f9136e6cca3 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicy.java @@ -0,0 +1,121 @@ +// 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.api.command.user.backup; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +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.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.BackupPolicyResponse; +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; + +import javax.inject.Inject; + +@APICommand(name = RemoveVMFromBackupPolicy.APINAME, + 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 RemoveVMFromBackupPolicy extends BaseCmd { + + public static final String APINAME = "removeVirtualMachineFromBackupPolicy"; + + @Inject + BackupManager backupManager; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, + type = CommandType.UUID, + entityType = UserVmResponse.class, + required = true, + description = "id of the VM to be removed from the backup policy") + private Long virtualMachineId; + + @Parameter(name = ApiConstants.BACKUP_POLICY_ID, + type = CommandType.UUID, + entityType = BackupPolicyResponse.class, + required = true, + description = "id of the backup policy") + private Long policyId; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.UUID, + entityType = ZoneResponse.class, + description = "the zone ID", required = true) + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getVirtualMachineId() { + return virtualMachineId; + } + + public Long getPolicyId() { + return policyId; + } + + public Long getZoneId() { + return zoneId; + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + boolean result = backupManager.removeVMFromBackupPolicy(zoneId, policyId, virtualMachineId); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove VM from backup policy"); + } + } catch (Exception e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } +} 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 3a9e06c84c1..9b8a8eb7371 100644 --- a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java +++ b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java @@ -47,12 +47,12 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer * @param policyName internal name for the backup policy * @param policyDescription internal description for the backup policy */ - BackupPolicy addBackupPolicy(Long zoneId, String policyExternalId, String policyName, String policyDescription); + BackupPolicy importBackupPolicy(Long zoneId, String policyExternalId, String policyName, String policyDescription); /** * Assign VM to existing backup policy */ - boolean assignVMToBackupPolicy(Long zoneId, Long policyId, Long virtualMachineId); + boolean addVMToBackupPolicy(Long zoneId, Long policyId, Long virtualMachineId); /** * List existing backups for a VM @@ -63,8 +63,9 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer * List backup policies * @param zoneId zone id * @param external if true, only external backup policies are listed + * @param policyId if not null, only the policy with this id is listed */ - List listBackupPolicies(Long zoneId, Boolean external); + List listBackupPolicies(Long zoneId, Boolean external, Long policyId); /** * Restore a full backed up VM @@ -80,4 +81,9 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer * Deletes a backup policy */ boolean deleteBackupPolicy(Long policyId); + + /** + * Remove a VM from a backup policy + */ + boolean removeVMFromBackupPolicy(Long zoneId, Long policyId, Long vmId); } 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 b9d87575c6d..48f9a4ca42f 100644 --- a/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java +++ b/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java @@ -38,7 +38,12 @@ public interface BackupProvider { * Assign VM to backup policy * @return true if VM is successfully assigned, false if not */ - boolean assignVMToBackupPolicy(String vmUuid, String policyUuid); + boolean addVMToBackupPolicy(String vmUuid, String policyUuid); + + /** + * Remove a VM form a backup policy + */ + boolean removeVMFromBackupPolicy(String vmUuid, String policyUuid); /** * Returns the list of existing backup policies on the provider diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupPolicyVMMapDao.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupPolicyVMMapDao.java index bcb8cc0e11a..c362804275f 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupPolicyVMMapDao.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupPolicyVMMapDao.java @@ -28,4 +28,5 @@ public interface BackupPolicyVMMapDao extends GenericDao listByPolicyId(long policyId); + BackupPolicyVMMapVO findByPolicyIdAndVMId(long policyId, long vmId); } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupPolicyVMMapDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupPolicyVMMapDaoImpl.java index a0f5e3c208d..21902ab77ef 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupPolicyVMMapDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/dao/BackupPolicyVMMapDaoImpl.java @@ -66,4 +66,12 @@ public class BackupPolicyVMMapDaoImpl extends GenericDaoBase sc = mapSearch.create(); + sc.setParameters("policy_id", policyId); + sc.setParameters("vm_id", vmId); + return findOneBy(sc); + } } 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 03217ad7d35..5e89cbffbab 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 @@ -40,11 +40,17 @@ public class DummyBackupProvider extends AdapterBase implements BackupProvider { } @Override - public boolean assignVMToBackupPolicy(String vmUuid, String policyUuid) { + public boolean addVMToBackupPolicy(String vmUuid, String policyUuid) { s_logger.debug("Assigning VM " + vmUuid + " to backup policy " + policyUuid); return true; } + @Override + public boolean removeVMFromBackupPolicy(String vmUuid, String policyUuid) { + s_logger.debug("Removing VM " + vmUuid + " to backup policy " + policyUuid); + return true; + } + @Override public List listBackupPolicies(Long zoneId) { s_logger.debug("Listing backup policies on Dummy B&R Plugin"); 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 11e975f50fd..31ef27b7ed6 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 @@ -79,7 +79,12 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider, } @Override - public boolean assignVMToBackupPolicy(String vmUuid, String policyUuid) { + public boolean addVMToBackupPolicy(String vmUuid, String policyUuid) { + return false; + } + + @Override + public boolean removeVMFromBackupPolicy(String vmUuid, String policyUuid) { return false; } 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 b51f424a5ff..05511d22390 100644 --- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.backup; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -34,11 +35,12 @@ import com.cloud.user.AccountService; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.dao.VMInstanceDao; import org.apache.cloudstack.api.command.admin.backup.DeleteBackupPolicyCmd; -import org.apache.cloudstack.api.command.user.backup.AssignBackupPolicyCmd; +import org.apache.cloudstack.api.command.user.backup.AddVMToBackupPolicyCmd; import org.apache.cloudstack.api.command.admin.backup.ImportBackupPolicyCmd; import org.apache.cloudstack.api.command.user.backup.ListBackupPoliciesCmd; import org.apache.cloudstack.api.command.admin.backup.ListBackupProvidersCmd; import org.apache.cloudstack.api.command.user.backup.ListBackupsCmd; +import org.apache.cloudstack.api.command.user.backup.RemoveVMFromBackupPolicy; import org.apache.cloudstack.api.command.user.backup.RestoreBackupCmd; import org.apache.cloudstack.api.command.user.backup.RestoreBackupVolumeCmd; import org.apache.cloudstack.backup.dao.BackupDao; @@ -82,7 +84,7 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { private List backupProviders; @Override - public BackupPolicy addBackupPolicy(Long zoneId, String policyExternalId, String policyName, String policyDescription) { + public BackupPolicy importBackupPolicy(Long zoneId, String policyExternalId, String policyName, String policyDescription) { BackupProvider provider = getBackupProvider(zoneId); if (!provider.isBackupPolicy(policyExternalId)) { throw new CloudRuntimeException("Policy " + policyExternalId + " does not exist on provider " + provider.getName() + " on zone " + zoneId); @@ -98,7 +100,7 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { } @Override - public boolean assignVMToBackupPolicy(Long zoneId, Long policyId, Long virtualMachineId) { + public boolean addVMToBackupPolicy(Long zoneId, Long policyId, Long virtualMachineId) { VMInstanceVO vmInstanceVO = vmInstanceDao.findById(virtualMachineId); if (vmInstanceVO == null) { throw new CloudRuntimeException("VM " + virtualMachineId + " does not exist"); @@ -109,7 +111,7 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { } String vmUuid = vmInstanceVO.getUuid(); BackupProvider backupProvider = getBackupProvider(zoneId); - boolean result = backupProvider.assignVMToBackupPolicy(vmUuid, policy.getUuid()); + boolean result = backupProvider.addVMToBackupPolicy(vmUuid, policy.getExternalId()); if (result) { BackupPolicyVMMapVO map = backupPolicyVMMapDao.findByVMId(virtualMachineId); if (map != null) { @@ -124,6 +126,28 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { return result; } + @Override + public boolean removeVMFromBackupPolicy(Long zoneId, Long policyId, Long vmId) { + BackupPolicyVO policy = backupPolicyDao.findById(policyId); + if (policy == null) { + throw new CloudRuntimeException("Policy " + policyId + " does not exist"); + } + VMInstanceVO vm = vmInstanceDao.findById(vmId); + if (vm == null) { + throw new CloudRuntimeException("VM " + vmId + " does not exist"); + } + BackupProvider backupProvider = getBackupProvider(zoneId); + boolean result = backupProvider.removeVMFromBackupPolicy(vm.getUuid(), policy.getExternalId()); + if (result) { + BackupPolicyVMMapVO map = backupPolicyVMMapDao.findByPolicyIdAndVMId(policyId, vmId); + backupPolicyVMMapDao.expunge(map.getId()); + LOG.debug("Successfully removed VM " + vmId + " from backup policy " + policy.getName()); + } else { + LOG.debug("Could not remove VM " + vmId + " from backup policy " + policyId); + } + return result; + } + @Override public List listBackups(Long vmId) { return backupDao.listByVmId(vmId); @@ -150,9 +174,25 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { return backupPolicyDao.listByZone(zoneId); } + /** + * List imported backup policy with id policyId + */ + private List listInternalPolicyById(Long policyId) { + BackupPolicyVO policy = backupPolicyDao.findById(policyId); + if (policy == null) { + throw new CloudRuntimeException("Policy " + policyId + " does not exist"); + } + LOG.debug("Listing imported backup policy with id: " + policyId); + return Collections.singletonList(policy); + } + @Override - public List listBackupPolicies(Long zoneId, Boolean external) { - return BooleanUtils.isTrue(external) ? listExternalPolicies(zoneId) : listInternalPolicies(zoneId); + public List listBackupPolicies(Long zoneId, Boolean external, Long policyId) { + if (policyId != null) { + return listInternalPolicyById(policyId); + } else { + return BooleanUtils.isTrue(external) ? listExternalPolicies(zoneId) : listInternalPolicies(zoneId); + } } @Override @@ -237,7 +277,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { cmdList.add(ListBackupProvidersCmd.class); cmdList.add(ListBackupPoliciesCmd.class); cmdList.add(ImportBackupPolicyCmd.class); - cmdList.add(AssignBackupPolicyCmd.class); + cmdList.add(AddVMToBackupPolicyCmd.class); + cmdList.add(RemoveVMFromBackupPolicy.class); cmdList.add(DeleteBackupPolicyCmd.class); cmdList.add(ListBackupsCmd.class); cmdList.add(RestoreBackupCmd.class); diff --git a/test/integration/smoke/test_backup_recovery.py b/test/integration/smoke/test_backup_recovery.py index 18191190d50..b9764346c83 100644 --- a/test/integration/smoke/test_backup_recovery.py +++ b/test/integration/smoke/test_backup_recovery.py @@ -27,6 +27,8 @@ class TestDummyBackupAndRecovery(cloudstackTestCase): @classmethod def setUpClass(cls): + # Setup + cls.testClient = super(TestDummyBackupAndRecovery, cls).getClsTestClient() cls.api_client = cls.testClient.getApiClient() cls.services = cls.testClient.getParsedTestDataConfig() @@ -46,6 +48,8 @@ class TestDummyBackupAndRecovery(cloudstackTestCase): mode=cls.services["mode"]) cls._cleanup = [cls.offering, cls.account] + # 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') cls.backup_enabled = backup_enabled_cfg[0].value @@ -56,6 +60,8 @@ class TestDummyBackupAndRecovery(cloudstackTestCase): if not cls.backup_provider == "dummy": Configurations.update(cls.api_client, 'backup.framework.provider.plugin', 'dummy', zoneid=cls.zone.id) + # Import a dummy backup policy to use on tests + cls.external_policies = BackupPolicy.listExternal(cls.api_client, cls.zone.id) cls.debug("Importing backup policy %s - %s" % (cls.external_policies[0].externalid, cls.external_policies[0].name)) cls.policy = BackupPolicy.importExisting(cls.api_client, cls.zone.id, cls.external_policies[0].externalid, @@ -93,11 +99,17 @@ class TestDummyBackupAndRecovery(cloudstackTestCase): return @attr(tags=["advanced", "backup"], required_hardware="false") - def test_ImportBackupPolicies(self): + def test_import_backup_policies(self): """ Import existing backup policies from Dummy Backup and Recovery Provider """ + # Validate the following: + # 1. Import a backup policy from the dummy provider + # 2. List internal backup policies, policy id should be listed + # 3. Delete backup policy + # 4. List internal backup policies, policy id should not be listed + 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, @@ -106,44 +118,51 @@ class TestDummyBackupAndRecovery(cloudstackTestCase): 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") self.debug("Deleting backup policy %s" % policy.id) policy.delete(self.apiclient) + 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] + self.assertEqual(len(matching_policies), 0, "Check there is not a matching policy") + @attr(tags=["advanced", "backup"], required_hardware="false") - def test_AssignVMToBackupPolicy(self): + def test_add_vm_to_backup_Policy(self): """ Assign a VM to a backup policy """ - self.debug("Assigning VM %s to backup policy %s" % (self.vm.id, self.policy.id)) + # Validate the following: + # 1. Add VM to backup policy + # 2. Verify a mapping between the VM and the backup policy exists + # 3. Remove VM from backup policy + # 4. Verify there is no mapping between the VM and the backup policy - self.policy.assignVM( - self.apiclient, - self.vm.id, - self.zone.id - ) + 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) - qresultset = self.dbclient.execute( - "select id from vm_instance where uuid='%s';" - % 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] - qresultset = self.dbclient.execute( - "select id from backup_policy where uuid='%s';" - % self.policy.id - ) + 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) - ) + 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( - map[0], - None, - "A mapping between VM and backup policy should exist on DB" - ) + 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") + + 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) + + # 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)) + + self.assertEqual(len(qresultset), 0, "The mapping between VM and backup policy should be removed from DB") diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py index c98435ed826..6087753185d 100755 --- a/tools/marvin/marvin/lib/base.py +++ b/tools/marvin/marvin/lib/base.py @@ -5394,6 +5394,14 @@ class BackupPolicy: cmd.description = description return BackupPolicy(apiclient.importBackupPolicy(cmd).__dict__) + @classmethod + def listInternalById(self, apiclient, id): + """List imported backup policies by id""" + + cmd = listBackupPolicies.listBackupPoliciesCmd() + cmd.id = id + return (apiclient.listBackupPolicies(cmd)) + @classmethod def listInternal(self, apiclient, zoneid): """List imported backup policies""" @@ -5418,11 +5426,20 @@ class BackupPolicy: cmd.id = self.id return (apiclient.deleteBackupPolicy(cmd)) - def assignVM(self, apiclient, vmid, zoneid): - """Assign a VM to a backup policy""" + def addVM(self, apiclient, vmid, zoneid): + """Add a VM to a backup policy""" - cmd = assignBackupPolicy.assignBackupPolicyCmd() + cmd = addVirtualMachineToBackupPolicy.addVirtualMachineToBackupPolicyCmd() cmd.backuppolicyid = self.id cmd.virtualmachineid = vmid cmd.zoneid = zoneid - return (apiclient.assignBackupPolicy(cmd)) + return (apiclient.addVirtualMachineToBackupPolicy(cmd)) + + def removeVM(self, apiclient, vmid, zoneid): + """Remove a VM from a backup policy""" + + cmd = removeVirtualMachineFromBackupPolicy.removeVirtualMachineFromBackupPolicyCmd() + cmd.backuppolicyid = self.id + cmd.virtualmachineid = vmid + cmd.zoneid = zoneid + return (apiclient.removeVirtualMachineFromBackupPolicy(cmd)) \ No newline at end of file