diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseBackupListCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseBackupListCmd.java index b4b5704056d..42f4a21639e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/BaseBackupListCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/BaseBackupListCmd.java @@ -18,8 +18,10 @@ package org.apache.cloudstack.api; import org.apache.cloudstack.api.response.BackupPolicyResponse; +import org.apache.cloudstack.api.response.BackupPolicyVMMapResponse; import org.apache.cloudstack.api.response.BackupResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.backup.BackupPolicyVMMap; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.backup.Backup; import org.apache.cloudstack.backup.BackupPolicy; @@ -59,6 +61,21 @@ public abstract class BaseBackupListCmd extends BaseListCmd { setResponseObject(response); } + protected void setupResponseBackupPolicyVMMappings(final List mappings) { + final ListResponse response = new ListResponse<>(); + final List responses = new ArrayList<>(); + for (BackupPolicyVMMap map : mappings) { + if (map == null) { + continue; + } + BackupPolicyVMMapResponse resp = _responseGenerator.createBackupPolicyVMMappingResponse(map); + responses.add(resp); + } + response.setResponses(responses); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + @Override public long getEntityOwnerId() { return CallContext.current().getCallingAccount().getId(); diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java index 5640da3d527..db702e5713a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java @@ -35,6 +35,7 @@ import org.apache.cloudstack.api.response.AutoScalePolicyResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse; import org.apache.cloudstack.api.response.BackupPolicyResponse; +import org.apache.cloudstack.api.response.BackupPolicyVMMapResponse; import org.apache.cloudstack.api.response.BackupResponse; import org.apache.cloudstack.api.response.CapacityResponse; import org.apache.cloudstack.api.response.ClusterResponse; @@ -119,6 +120,7 @@ import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.backup.BackupPolicy; +import org.apache.cloudstack.backup.BackupPolicyVMMap; import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.backup.Backup; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule; @@ -470,4 +472,6 @@ public interface ResponseGenerator { BackupResponse createBackupResponse(Backup backup); BackupPolicyResponse createBackupPolicyResponse(BackupPolicy policy); + + BackupPolicyVMMapResponse createBackupPolicyVMMappingResponse(BackupPolicyVMMap map); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/DeleteBackupPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/DeleteBackupPolicyCmd.java index bdbb583a64c..ff662646498 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/DeleteBackupPolicyCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/backup/DeleteBackupPolicyCmd.java @@ -51,7 +51,7 @@ public class DeleteBackupPolicyCmd extends BaseCmd { //////////////// API parameters ///////////////////// //////////////////////////////////////////////////// - @Parameter(name = ApiConstants.ID, + @Parameter(name = ApiConstants.BACKUP_POLICY_ID, type = CommandType.UUID, entityType = BackupPolicyResponse.class, required = true, 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 78ef2165ade..49278d801f5 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,7 +54,7 @@ public class ListBackupPoliciesCmd extends BaseBackupListCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, entityType = BackupPolicyResponse.class, + @Parameter(name = ApiConstants.BACKUP_POLICY_ID, type = BaseCmd.CommandType.UUID, entityType = BackupPolicyResponse.class, description = "The backup policy ID") private Long policyId; @@ -93,6 +93,7 @@ public class ListBackupPoliciesCmd extends BaseBackupListCmd { @Override public void execute() throws ResourceUnavailableException, ServerApiException, ConcurrentOperationException { + validateParameters(); try { List backupPolicies = backupManager.listBackupPolicies(zoneId, external, policyId); setupResponseBackupPolicyList(backupPolicies); @@ -102,4 +103,10 @@ public class ListBackupPoliciesCmd extends BaseBackupListCmd { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); } } + + private void validateParameters() { + if (zoneId == null && policyId == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please provide a zone id or a policy id"); + } + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupPoliciesVMsMappingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupPoliciesVMsMappingsCmd.java new file mode 100644 index 00000000000..e23c4eaf4b2 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupPoliciesVMsMappingsCmd.java @@ -0,0 +1,87 @@ +// 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 com.cloud.utils.exception.CloudRuntimeException; +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.BaseBackupListCmd; +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.ZoneResponse; +import org.apache.cloudstack.backup.BackupManager; +import org.apache.cloudstack.backup.BackupPolicyVMMap; + +import javax.inject.Inject; +import java.util.List; + +@APICommand(name = ListBackupPoliciesVMsMappingsCmd.APINAME, + description = "Lists VMs mapped to a backup policy", + responseObject = BackupPolicyResponse.class, since = "4.12.0", + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) +public class ListBackupPoliciesVMsMappingsCmd extends BaseBackupListCmd { + public static final String APINAME = "listBackupPoliciesVirtualMachineMappings"; + + @Inject + BackupManager backupManager; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.BACKUP_POLICY_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") + private Long zoneId; + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + List mappings = backupManager.listBackupPolicyVMMappings(zoneId, policyId); + setupResponseBackupPolicyVMMappings(mappings); + } catch (CloudRuntimeException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + private void validateParameters() { + if (zoneId == null && policyId == null) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please provide a zone id or a policy id"); + } + } + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + RESPONSE_SUFFIX; + } +} 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/RemoveVMFromBackupPolicyCmd.java similarity index 97% rename from api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicy.java rename to api/src/main/java/org/apache/cloudstack/api/command/user/backup/RemoveVMFromBackupPolicyCmd.java index f9136e6cca3..d4c3ecd2dd2 100644 --- 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/RemoveVMFromBackupPolicyCmd.java @@ -38,11 +38,11 @@ import org.apache.cloudstack.context.CallContext; import javax.inject.Inject; -@APICommand(name = RemoveVMFromBackupPolicy.APINAME, +@APICommand(name = RemoveVMFromBackupPolicyCmd.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 class RemoveVMFromBackupPolicyCmd extends BaseCmd { public static final String APINAME = "removeVirtualMachineFromBackupPolicy"; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BackupPolicyVMMapResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BackupPolicyVMMapResponse.java new file mode 100644 index 00000000000..909ed9d13f5 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/BackupPolicyVMMapResponse.java @@ -0,0 +1,65 @@ +// 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.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.backup.BackupPolicyVMMap; + +@EntityReference(value = BackupPolicyVMMap.class) +public class BackupPolicyVMMapResponse extends BaseResponse { + + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "zone id") + private String zoneId; + + @SerializedName(ApiConstants.BACKUP_POLICY_ID) + @Param(description = "backup policy id") + private String backupPolicyId; + + @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) + @Param(description = "virtual machine id") + private String vmId; + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getBackupPolicyId() { + return backupPolicyId; + } + + public void setBackupPolicyId(String backupPolicyId) { + this.backupPolicyId = backupPolicyId; + } + + public String getVmId() { + return vmId; + } + + public void setVmId(String vmId) { + this.vmId = vmId; + } +} 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 9b8a8eb7371..27b5a1f41fd 100644 --- a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java +++ b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java @@ -86,4 +86,9 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer * Remove a VM from a backup policy */ boolean removeVMFromBackupPolicy(Long zoneId, Long policyId, Long vmId); + + /** + * Return mappings between backup policy and VMs + */ + List listBackupPolicyVMMappings(Long zoneId, Long policyId); } diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupPolicyVMMap.java b/api/src/main/java/org/apache/cloudstack/backup/BackupPolicyVMMap.java new file mode 100644 index 00000000000..d9ecda81ba5 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/backup/BackupPolicyVMMap.java @@ -0,0 +1,10 @@ +package org.apache.cloudstack.backup; + +import org.apache.cloudstack.api.InternalIdentity; + +public interface BackupPolicyVMMap extends InternalIdentity { + + long getPolicyId(); + long getVmId(); + long getZoneId(); +} 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 48f9a4ca42f..c6c7e1d6a59 100644 --- a/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java +++ b/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.backup; import com.cloud.agent.api.to.VolumeTO; +import com.cloud.vm.VirtualMachine; import java.util.List; @@ -38,12 +39,12 @@ public interface BackupProvider { * Assign VM to backup policy * @return true if VM is successfully assigned, false if not */ - boolean addVMToBackupPolicy(String vmUuid, String policyUuid); + boolean addVMToBackupPolicy(Long zoneId, String policyId, VirtualMachine vm); /** * Remove a VM form a backup policy */ - boolean removeVMFromBackupPolicy(String vmUuid, String policyUuid); + boolean removeVMFromBackupPolicy(Long zoneId, String policyId, VirtualMachine vm); /** * Returns the list of existing backup policies on the provider diff --git a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupPolicyVMMapVO.java b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupPolicyVMMapVO.java index e06d153981d..c88fda52891 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupPolicyVMMapVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/backup/BackupPolicyVMMapVO.java @@ -19,8 +19,6 @@ package org.apache.cloudstack.backup; -import org.apache.cloudstack.api.InternalIdentity; - import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -30,7 +28,7 @@ import javax.persistence.Table; @Entity @Table(name = "backup_policy_vm_map") -public class BackupPolicyVMMapVO implements InternalIdentity { +public class BackupPolicyVMMapVO implements BackupPolicyVMMap { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -43,12 +41,16 @@ public class BackupPolicyVMMapVO implements InternalIdentity { @Column(name = "vm_id") private long vmId; + @Column(name = "zone_id") + private long zoneId; + public BackupPolicyVMMapVO() { } - public BackupPolicyVMMapVO(long policyId, long vmId) { + public BackupPolicyVMMapVO(long zoneId, long policyId, long vmId) { this.policyId = policyId; this.vmId = vmId; + this.zoneId = zoneId; } public long getId() { @@ -74,4 +76,12 @@ public class BackupPolicyVMMapVO implements InternalIdentity { public void setVmId(long vmId) { this.vmId = vmId; } + + public long getZoneId() { + return zoneId; + } + + public void setZoneId(long zoneId) { + this.zoneId = zoneId; + } } 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 c362804275f..94a5abf449c 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 @@ -20,6 +20,8 @@ package org.apache.cloudstack.backup.dao; import com.cloud.utils.db.GenericDao; +import org.apache.cloudstack.api.response.BackupPolicyVMMapResponse; +import org.apache.cloudstack.backup.BackupPolicyVMMap; import org.apache.cloudstack.backup.BackupPolicyVMMapVO; import java.util.List; @@ -28,5 +30,7 @@ public interface BackupPolicyVMMapDao extends GenericDao listByPolicyId(long policyId); - BackupPolicyVMMapVO findByPolicyIdAndVMId(long policyId, long vmId); + List listByPolicyIdAndVMId(long policyId, long vmId); + List listByZoneId(long zoneId); + BackupPolicyVMMapResponse newBackupPolicyVMMappingResponse(BackupPolicyVMMap map); } 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 21902ab77ef..317e7117bbf 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 @@ -19,20 +19,37 @@ package org.apache.cloudstack.backup.dao; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.VMInstanceDao; +import org.apache.cloudstack.api.response.BackupPolicyVMMapResponse; +import org.apache.cloudstack.backup.BackupPolicyVMMap; import org.apache.cloudstack.backup.BackupPolicyVMMapVO; +import org.apache.cloudstack.backup.BackupPolicyVO; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; +import javax.inject.Inject; import java.util.List; @Component public class BackupPolicyVMMapDaoImpl extends GenericDaoBase implements BackupPolicyVMMapDao { + @Inject + private VMInstanceDao vmInstanceDao; + + @Inject + private BackupPolicyDao backupPolicyDao; + + @Inject + private DataCenterDao dataCenterDao; + private SearchBuilder mapSearch; public BackupPolicyVMMapDaoImpl() { @@ -43,6 +60,7 @@ public class BackupPolicyVMMapDaoImpl extends GenericDaoBase listByPolicyIdAndVMId(long policyId, long vmId) { SearchCriteria sc = mapSearch.create(); sc.setParameters("policy_id", policyId); sc.setParameters("vm_id", vmId); - return findOneBy(sc); + return listBy(sc); + } + + @Override + public List listByZoneId(long zoneId) { + SearchCriteria sc = mapSearch.create(); + sc.setParameters("zone_id", zoneId); + return listBy(sc); + } + + @Override + public BackupPolicyVMMapResponse newBackupPolicyVMMappingResponse(BackupPolicyVMMap map) { + BackupPolicyVO policy = backupPolicyDao.findById(map.getPolicyId()); + if (policy == null) { + throw new CloudRuntimeException("Policy " + map.getPolicyId() + " does not exist"); + } + VMInstanceVO vm = vmInstanceDao.findById(map.getVmId()); + if (vm == null) { + throw new CloudRuntimeException("VM " + map.getVmId() + " does not exist"); + } + DataCenterVO zone = dataCenterDao.findById(map.getZoneId()); + if (zone == null) { + throw new CloudRuntimeException("Zone " + map.getZoneId() + " does not exist"); + } + BackupPolicyVMMapResponse response = new BackupPolicyVMMapResponse(); + response.setBackupPolicyId(policy.getUuid()); + response.setVmId(vm.getUuid()); + response.setZoneId(zone.getUuid()); + return response; } } 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 01d392ee5b1..83665ab2f36 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 @@ -44,16 +44,19 @@ CREATE TABLE IF NOT EXISTS `cloud`.`backup_policy` ( `external_id` varchar(40) NOT NULL COMMENT 'backup policy ID on provider side', `zone_id` bigint(20) unsigned NOT NULL COMMENT 'zone id', PRIMARY KEY (`id`), - UNIQUE KEY `uuid` (`uuid`) + UNIQUE KEY `uuid` (`uuid`), + CONSTRAINT `fk_backup_policy__zone_id` FOREIGN KEY (`zone_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `cloud`.`backup_policy_vm_map` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `zone_id` bigint(20) unsigned NOT NULL, `policy_id` bigint(20) unsigned NOT NULL, `vm_id` bigint(20) unsigned NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `fk_backup_policy_vm_map__policy_id` FOREIGN KEY (`policy_id`) REFERENCES `backup_policy` (`id`) ON DELETE CASCADE, - CONSTRAINT `fk_backup_policy_vm_map__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance` (`id`) ON DELETE CASCADE + CONSTRAINT `fk_backup_policy_vm_map__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_backup_policy_vm_map__zone_id` FOREIGN KEY (`zone_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `cloud`.`backup` ( 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 5e89cbffbab..df9fea7e303 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 @@ -20,6 +20,7 @@ import com.cloud.agent.api.to.VolumeTO; import com.cloud.storage.Storage; import com.cloud.storage.Volume; import com.cloud.utils.component.AdapterBase; +import com.cloud.vm.VirtualMachine; import org.apache.log4j.Logger; import java.util.Arrays; @@ -40,14 +41,14 @@ public class DummyBackupProvider extends AdapterBase implements BackupProvider { } @Override - public boolean addVMToBackupPolicy(String vmUuid, String policyUuid) { - s_logger.debug("Assigning VM " + vmUuid + " to backup policy " + policyUuid); + public boolean addVMToBackupPolicy(Long zoneId, String policyId, VirtualMachine vm) { + s_logger.debug("Assigning VM " + vm.getInstanceName() + " to backup policy " + policyId); return true; } @Override - public boolean removeVMFromBackupPolicy(String vmUuid, String policyUuid) { - s_logger.debug("Removing VM " + vmUuid + " to backup policy " + policyUuid); + public boolean removeVMFromBackupPolicy(Long zoneId, String policyId, VirtualMachine vm) { + s_logger.debug("Removing VM " + vm.getInstanceName() + " from backup policy " + policyId); return true; } 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 31ef27b7ed6..4558c581238 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 @@ -20,11 +20,10 @@ package org.apache.cloudstack.backup; import java.net.URISyntaxException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.util.HashMap; import java.util.List; -import java.util.Map; import com.cloud.agent.api.to.VolumeTO; +import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.backup.veeam.VeeamClient; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; @@ -36,8 +35,6 @@ import com.cloud.utils.exception.CloudRuntimeException; public class VeeamBackupProvider extends AdapterBase implements BackupProvider, Configurable { private static final Logger LOG = Logger.getLogger(VeeamBackupProvider.class); - private Map zoneClientMap = new HashMap(); - private ConfigKey VeeamUrl = new ConfigKey<>("Advanced", String.class, "backup.plugin.veeam.url", "http://localhost:9399/api/", @@ -62,14 +59,8 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider, private VeeamClient getClient(final Long zoneId) { try { - if (zoneClientMap.containsKey(zoneId)) { - return zoneClientMap.get(zoneId); - } else { - VeeamClient client = new VeeamClient(VeeamUrl.valueIn(zoneId), VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId), - VeeamValidateSSLSecurity.valueIn(zoneId), VeeamApiRequestTimeout.valueIn(zoneId)); - zoneClientMap.put(zoneId, client); - return client; - } + return new VeeamClient(VeeamUrl.valueIn(zoneId), VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId), + VeeamValidateSSLSecurity.valueIn(zoneId), VeeamApiRequestTimeout.valueIn(zoneId)); } catch (URISyntaxException e) { throw new CloudRuntimeException("Failed to parse Veeam API URL: " + e.getMessage()); } catch (NoSuchAlgorithmException | KeyManagementException e) { @@ -79,12 +70,15 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider, } @Override - public boolean addVMToBackupPolicy(String vmUuid, String policyUuid) { - return false; + public boolean addVMToBackupPolicy(Long zoneId, String policyId, VirtualMachine vm) { + String instanceName = vm.getInstanceName(); + //TODO: Get vcenter ip + return getClient(zoneId).assignBackupPolicyToVM(policyId, instanceName, ""); } @Override - public boolean removeVMFromBackupPolicy(String vmUuid, String policyUuid) { + public boolean removeVMFromBackupPolicy(Long zoneId, String policyId, VirtualMachine vm) { + //TODO: Remove VM from backup policy on the client return false; } @@ -95,7 +89,7 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider, @Override public boolean isBackupPolicy(String uuid) { - return false; + return true; } @Override diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java index 4011fd5d701..d07e37666b9 100644 --- a/server/src/main/java/com/cloud/api/ApiDBUtils.java +++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java @@ -40,6 +40,7 @@ import org.apache.cloudstack.api.ResponseObject.ResponseView; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.BackupPolicyResponse; +import org.apache.cloudstack.api.response.BackupPolicyVMMapResponse; import org.apache.cloudstack.api.response.BackupResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; @@ -64,8 +65,10 @@ 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.BackupPolicy; +import org.apache.cloudstack.backup.BackupPolicyVMMap; 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.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; @@ -442,6 +445,7 @@ public class ApiDBUtils { static VGPUTypesDao s_vgpuTypesDao; static BackupDao s_backupDao; static BackupPolicyDao s_backupPolicyDao; + static BackupPolicyVMMapDao s_backupPolicyVMMapDao; @Inject private ManagementServer ms; @@ -678,6 +682,8 @@ public class ApiDBUtils { private BackupDao backupDao; @Inject private BackupPolicyDao backupPolicyDao; + @Inject + private BackupPolicyVMMapDao backupPolicyVMMapDao; @PostConstruct void init() { @@ -799,6 +805,7 @@ public class ApiDBUtils { s_vgpuTypesDao = vgpuTypesDao; s_backupDao = backupDao; s_backupPolicyDao = backupPolicyDao; + s_backupPolicyVMMapDao = backupPolicyVMMapDao; } // /////////////////////////////////////////////////////////// @@ -2022,4 +2029,8 @@ public class ApiDBUtils { public static BackupPolicyResponse newBackupPolicyResponse(BackupPolicy policy) { return s_backupPolicyDao.newBackupPolicyResponse(policy); } + + public static BackupPolicyVMMapResponse newBackupPolicyVMMappingResponse(BackupPolicyVMMap map) { + return s_backupPolicyVMMapDao.newBackupPolicyVMMappingResponse(map); + } } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 16380745d3d..4686e56907a 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -200,6 +200,7 @@ import org.apache.cloudstack.api.response.AutoScalePolicyResponse; import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse; import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse; import org.apache.cloudstack.api.response.BackupPolicyResponse; +import org.apache.cloudstack.api.response.BackupPolicyVMMapResponse; import org.apache.cloudstack.api.response.BackupResponse; import org.apache.cloudstack.api.response.CapabilityResponse; import org.apache.cloudstack.api.response.CapacityResponse; @@ -292,6 +293,7 @@ import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.backup.BackupPolicy; +import org.apache.cloudstack.backup.BackupPolicyVMMap; import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; @@ -3978,4 +3980,9 @@ public class ApiResponseHelper implements ResponseGenerator { public BackupPolicyResponse createBackupPolicyResponse(BackupPolicy policy) { return ApiDBUtils.newBackupPolicyResponse(policy); } + + @Override + public BackupPolicyVMMapResponse createBackupPolicyVMMappingResponse(BackupPolicyVMMap map) { + return ApiDBUtils.newBackupPolicyVMMappingResponse(map); + } } 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 05511d22390..04b58b3c4cb 100644 --- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java @@ -39,8 +39,9 @@ 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.ListBackupPoliciesVMsMappingsCmd; 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.RemoveVMFromBackupPolicyCmd; 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; @@ -109,15 +110,14 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { if (policy == null) { throw new CloudRuntimeException("Policy " + policy + " does not exist"); } - String vmUuid = vmInstanceVO.getUuid(); BackupProvider backupProvider = getBackupProvider(zoneId); - boolean result = backupProvider.addVMToBackupPolicy(vmUuid, policy.getExternalId()); + boolean result = backupProvider.addVMToBackupPolicy(zoneId, policy.getExternalId(), vmInstanceVO); if (result) { BackupPolicyVMMapVO map = backupPolicyVMMapDao.findByVMId(virtualMachineId); if (map != null) { backupPolicyVMMapDao.expunge(map.getId()); } - map = new BackupPolicyVMMapVO(policy.getId(), virtualMachineId); + map = new BackupPolicyVMMapVO(zoneId, policy.getId(), virtualMachineId); backupPolicyVMMapDao.persist(map); LOG.debug("Successfully assigned VM " + virtualMachineId + " to backup policy " + policy.getName()); } else { @@ -137,10 +137,13 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { throw new CloudRuntimeException("VM " + vmId + " does not exist"); } BackupProvider backupProvider = getBackupProvider(zoneId); - boolean result = backupProvider.removeVMFromBackupPolicy(vm.getUuid(), policy.getExternalId()); + boolean result = backupProvider.removeVMFromBackupPolicy(zoneId, policy.getExternalId(), vm); if (result) { - BackupPolicyVMMapVO map = backupPolicyVMMapDao.findByPolicyIdAndVMId(policyId, vmId); - backupPolicyVMMapDao.expunge(map.getId()); + List map = backupPolicyVMMapDao.listByPolicyIdAndVMId(policyId, vmId); + if (map.size() > 1) { + throw new CloudRuntimeException("More than one mapping between VM " + vmId + " and policy " + policyId); + } + backupPolicyVMMapDao.expunge(map.get(0).getId()); LOG.debug("Successfully removed VM " + vmId + " from backup policy " + policy.getName()); } else { LOG.debug("Could not remove VM " + vmId + " from backup policy " + policyId); @@ -148,6 +151,13 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { return result; } + @Override + public List listBackupPolicyVMMappings(Long zoneId, Long policyId) { + return policyId == null ? + new ArrayList<>(backupPolicyVMMapDao.listByZoneId(zoneId)) : + new ArrayList<>(backupPolicyVMMapDao.listByPolicyId(policyId)); + } + @Override public List listBackups(Long vmId) { return backupDao.listByVmId(vmId); @@ -278,11 +288,12 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager { cmdList.add(ListBackupPoliciesCmd.class); cmdList.add(ImportBackupPolicyCmd.class); cmdList.add(AddVMToBackupPolicyCmd.class); - cmdList.add(RemoveVMFromBackupPolicy.class); + cmdList.add(RemoveVMFromBackupPolicyCmd.class); cmdList.add(DeleteBackupPolicyCmd.class); cmdList.add(ListBackupsCmd.class); cmdList.add(RestoreBackupCmd.class); cmdList.add(RestoreBackupVolumeCmd.class); + cmdList.add(ListBackupPoliciesVMsMappingsCmd.class); return cmdList; }