mirror of https://github.com/apache/cloudstack.git
add APIs for management of backup repositories and backing up from local stores and stopped VMs
This commit is contained in:
parent
67821d7e4f
commit
fe5c9d72de
|
|
@ -1140,6 +1140,7 @@ public class ApiConstants {
|
||||||
public static final String WEBHOOK_NAME = "webhookname";
|
public static final String WEBHOOK_NAME = "webhookname";
|
||||||
|
|
||||||
public static final String NFS_MOUNT_OPTIONS = "nfsmountopts";
|
public static final String NFS_MOUNT_OPTIONS = "nfsmountopts";
|
||||||
|
public static final String MOUNT_OPTIONS = "mountopts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.response.BackupRepositoryResponse;
|
||||||
|
import org.apache.cloudstack.backup.BackupRepository;
|
||||||
import org.apache.cloudstack.storage.object.Bucket;
|
import org.apache.cloudstack.storage.object.Bucket;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroup;
|
import org.apache.cloudstack.affinity.AffinityGroup;
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
||||||
|
|
@ -549,4 +551,6 @@ public interface ResponseGenerator {
|
||||||
ObjectStoreResponse createObjectStoreResponse(ObjectStore os);
|
ObjectStoreResponse createObjectStoreResponse(ObjectStore os);
|
||||||
|
|
||||||
BucketResponse createBucketResponse(Bucket bucket);
|
BucketResponse createBucketResponse(Bucket bucket);
|
||||||
|
|
||||||
|
BackupRepositoryResponse createBackupRepositoryResponse(BackupRepository repository);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
package org.apache.cloudstack.api.command.user.backup.repository;
|
||||||
|
|
||||||
|
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.BackupRepositoryResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
|
import org.apache.cloudstack.backup.BackupRepository;
|
||||||
|
import org.apache.cloudstack.backup.BackupRepositoryService;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@APICommand(name = "addBackupRepository",
|
||||||
|
description = "Adds a backup repository to store NAS backups",
|
||||||
|
responseObject = BackupRepositoryResponse.class, since = "4.20.0",
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||||
|
public class AddBackupRepositoryCmd extends BaseCmd {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
BackupRepositoryService backupRepositoryService;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the backup repository")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ADDRESS, type = CommandType.STRING, required = true, description = "address of the backup repository")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "type of the backup repository. Supported values: NFS" )
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, description = "backup repository provider")
|
||||||
|
private String provider;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.MOUNT_OPTIONS, type = CommandType.STRING, description = "mount options")
|
||||||
|
private String mountOptions;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ZONE_ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = ZoneResponse.class,
|
||||||
|
required = true,
|
||||||
|
description = "ID of the zone where the backup repository is to be added")
|
||||||
|
private Long zoneId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CAPACITY_BYTES, type = CommandType.LONG, description = "capacity of this backup repository")
|
||||||
|
private Long capacityBytes;
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public BackupRepositoryService getBackupRepositoryService() {
|
||||||
|
return backupRepositoryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProvider() {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMountOptions() {
|
||||||
|
return mountOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCapacityBytes() {
|
||||||
|
return capacityBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
try {
|
||||||
|
BackupRepository result = backupRepositoryService.addBackupRepository(this);
|
||||||
|
if (result != null) {
|
||||||
|
BackupRepositoryResponse response = _responseGenerator.createBackupRepositoryResponse(result);
|
||||||
|
response.setResponseName(getCommandName());
|
||||||
|
this.setResponseObject(response);
|
||||||
|
} else {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add backup repository");
|
||||||
|
}
|
||||||
|
} catch (Exception ex4) {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex4.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
return CallContext.current().getCallingAccount().getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.apache.cloudstack.api.command.user.backup.repository;
|
||||||
|
|
||||||
|
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.BackupRepositoryResponse;
|
||||||
|
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||||
|
import org.apache.cloudstack.backup.BackupRepositoryService;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@APICommand(name = "deleteBackupRepository",
|
||||||
|
description = "delete a backup repository",
|
||||||
|
responseObject = SuccessResponse.class, since = "4.20.0",
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||||
|
public class DeleteBackupRepositoryCmd extends BaseCmd {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
BackupRepositoryService backupRepositoryService;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
@Parameter(name = ApiConstants.ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = BackupRepositoryResponse.class,
|
||||||
|
required = true,
|
||||||
|
description = "ID of the backup repository to be deleted")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// Accessors //////////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
boolean result = backupRepositoryService.deleteBackupRepository(this);
|
||||||
|
if (result) {
|
||||||
|
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||||
|
this.setResponseObject(response);
|
||||||
|
} else {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete backup repository");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package org.apache.cloudstack.api.command.user.backup.repository;
|
||||||
|
|
||||||
|
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.Pair;
|
||||||
|
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.BaseListCmd;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.BackupRepositoryResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
|
import org.apache.cloudstack.backup.BackupRepository;
|
||||||
|
import org.apache.cloudstack.backup.BackupRepositoryService;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@APICommand(name = "listBackupRepositories",
|
||||||
|
description = "Lists all backup repositories",
|
||||||
|
responseObject = BackupRepositoryResponse.class, since = "4.20.0",
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||||
|
public class ListBackupRepositoriesCmd extends BaseListCmd {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
BackupRepositoryService backupRepositoryService;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the backup repository")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ZONE_ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = ZoneResponse.class,
|
||||||
|
description = "ID of the zone where the backup repository is to be added")
|
||||||
|
private Long zoneId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, description = "the backup repository provider")
|
||||||
|
private String provider;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = BackupRepositoryResponse.class, description = "ID of the backup repository")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// Accessors //////////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProvider() {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
|
||||||
|
try {
|
||||||
|
Pair<List<BackupRepository>, Integer> repositoriesPair = backupRepositoryService.listBackupRepositories(this);
|
||||||
|
List<BackupRepository> backupRepositories = repositoriesPair.first();
|
||||||
|
ListResponse<BackupRepositoryResponse> response = new ListResponse<>();
|
||||||
|
List<BackupRepositoryResponse> responses = new ArrayList<>();
|
||||||
|
for (BackupRepository repository : backupRepositories) {
|
||||||
|
responses.add(_responseGenerator.createBackupRepositoryResponse(repository));
|
||||||
|
}
|
||||||
|
response.setResponses(responses, repositoriesPair.second());
|
||||||
|
response.setResponseName(getCommandName());
|
||||||
|
setResponseObject(response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String msg = String.format("Error listing backup repositories, due to: %s", e.getMessage());
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
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 java.util.Date;
|
||||||
|
|
||||||
|
public class BackupRepositoryResponse extends BaseResponse {
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ID)
|
||||||
|
@Param(description = "the ID of the backup repository")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ZONE_ID)
|
||||||
|
@Param(description = "the Zone ID of the backup repository")
|
||||||
|
private String zoneId;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ZONE_NAME)
|
||||||
|
@Param(description = "the Zone name of the backup repository")
|
||||||
|
private String zoneName;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.NAME)
|
||||||
|
@Param(description = "the name of the backup repository")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.ADDRESS)
|
||||||
|
@Param(description = "the address / url of the backup repository")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.PROVIDER)
|
||||||
|
@Param(description = "name of the provider")
|
||||||
|
private String providerName;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.TYPE)
|
||||||
|
@Param(description = "backup type")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.MOUNT_OPTIONS)
|
||||||
|
@Param(description = "mount options for the backup repository")
|
||||||
|
private String mountOptions;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.CAPACITY_BYTES)
|
||||||
|
@Param(description = "capacity of the backup repository")
|
||||||
|
private Long capacityBytes;
|
||||||
|
|
||||||
|
@SerializedName("created")
|
||||||
|
@Param(description = "the date and time the backup repository was added")
|
||||||
|
private Date created;
|
||||||
|
|
||||||
|
public BackupRepositoryResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZoneId(String zoneId) {
|
||||||
|
this.zoneId = zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZoneName() {
|
||||||
|
return zoneName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZoneName(String zoneName) {
|
||||||
|
this.zoneName = zoneName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMountOptions() {
|
||||||
|
return mountOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMountOptions(String mountOptions) {
|
||||||
|
this.mountOptions = mountOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProviderName() {
|
||||||
|
return providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProviderName(String providerName) {
|
||||||
|
this.providerName = providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getCapacityBytes() {
|
||||||
|
return capacityBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCapacityBytes(Long capacityBytes) {
|
||||||
|
this.capacityBytes = capacityBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreated() {
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreated(Date created) {
|
||||||
|
this.created = created;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.apache.cloudstack.backup;
|
||||||
|
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.AddBackupRepositoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.DeleteBackupRepositoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.ListBackupRepositoriesCmd;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface BackupRepositoryService {
|
||||||
|
BackupRepository addBackupRepository(AddBackupRepositoryCmd cmd);
|
||||||
|
boolean deleteBackupRepository(DeleteBackupRepositoryCmd cmd);
|
||||||
|
Pair<List<BackupRepository>, Integer> listBackupRepositories(ListBackupRepositoriesCmd cmd);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -22,11 +22,14 @@ package org.apache.cloudstack.backup;
|
||||||
import com.cloud.agent.api.Command;
|
import com.cloud.agent.api.Command;
|
||||||
import com.cloud.agent.api.LogLevel;
|
import com.cloud.agent.api.LogLevel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class TakeBackupCommand extends Command {
|
public class TakeBackupCommand extends Command {
|
||||||
private String vmName;
|
private String vmName;
|
||||||
private String backupPath;
|
private String backupPath;
|
||||||
private String backupRepoType;
|
private String backupRepoType;
|
||||||
private String backupRepoAddress;
|
private String backupRepoAddress;
|
||||||
|
private List<String> volumePaths;
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
private String mountOptions;
|
private String mountOptions;
|
||||||
|
|
||||||
|
|
@ -76,6 +79,14 @@ public class TakeBackupCommand extends Command {
|
||||||
this.mountOptions = mountOptions;
|
this.mountOptions = mountOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getVolumePaths() {
|
||||||
|
return volumePaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolumePaths(List<String> volumePaths) {
|
||||||
|
this.volumePaths = volumePaths;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import com.cloud.host.HostVO;
|
||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.storage.ScopeType;
|
||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
|
|
@ -40,6 +41,8 @@ import org.apache.cloudstack.backup.dao.BackupOfferingDao;
|
||||||
import org.apache.cloudstack.backup.dao.BackupRepositoryDao;
|
import org.apache.cloudstack.backup.dao.BackupRepositoryDao;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
@ -51,9 +54,11 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class NASBackupProvider extends AdapterBase implements BackupProvider, Configurable {
|
public class NASBackupProvider extends AdapterBase implements BackupProvider, Configurable {
|
||||||
private static final Logger LOG = LogManager.getLogger(NASBackupProvider.class);
|
private static final Logger LOG = LogManager.getLogger(NASBackupProvider.class);
|
||||||
|
private static final String SHARED_VOLUME_PATH_PREFIX = "/mnt";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private BackupDao backupDao;
|
private BackupDao backupDao;
|
||||||
|
|
@ -79,6 +84,9 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
||||||
@Inject
|
@Inject
|
||||||
private VMInstanceDao vmInstanceDao;
|
private VMInstanceDao vmInstanceDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private PrimaryDataStoreDao primaryDataStoreDao;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private AgentManager agentManager;
|
private AgentManager agentManager;
|
||||||
|
|
||||||
|
|
@ -111,10 +119,16 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Host getRunningVMHypervisorHost(VirtualMachine vm) {
|
protected Host getVMHypervisorHost(VirtualMachine vm) {
|
||||||
Long hostId = vm.getHostId();
|
Long hostId = vm.getHostId();
|
||||||
|
if (hostId == null && VirtualMachine.State.Running.equals(vm.getState())) {
|
||||||
|
throw new CloudRuntimeException(String.format("Unable to find the hypervisor host for %s. Make sure the virtual machine is running", vm.getName()));
|
||||||
|
}
|
||||||
|
if (VirtualMachine.State.Stopped.equals(vm.getState())) {
|
||||||
|
hostId = vm.getLastHostId();
|
||||||
|
}
|
||||||
if (hostId == null) {
|
if (hostId == null) {
|
||||||
throw new CloudRuntimeException("Unable to find the HYPERVISOR for " + vm.getName() + ". Make sure the virtual machine is running");
|
throw new CloudRuntimeException(String.format("Unable to find the hypervisor host for stopped VM: %s."));
|
||||||
}
|
}
|
||||||
final Host host = hostDao.findById(hostId);
|
final Host host = hostDao.findById(hostId);
|
||||||
if (host == null || !Status.Up.equals(host.getStatus()) || !Hypervisor.HypervisorType.KVM.equals(host.getHypervisorType())) {
|
if (host == null || !Status.Up.equals(host.getStatus()) || !Hypervisor.HypervisorType.KVM.equals(host.getHypervisorType())) {
|
||||||
|
|
@ -125,9 +139,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean takeBackup(final VirtualMachine vm) {
|
public boolean takeBackup(final VirtualMachine vm) {
|
||||||
// TODO: currently works for only running VMs
|
final Host host = getVMHypervisorHost(vm);
|
||||||
// TODO: add support for backup of stopped VMs
|
|
||||||
final Host host = getRunningVMHypervisorHost(vm);
|
|
||||||
|
|
||||||
final BackupRepository backupRepository = backupRepositoryDao.findByBackupOfferingId(vm.getBackupOfferingId());
|
final BackupRepository backupRepository = backupRepositoryDao.findByBackupOfferingId(vm.getBackupOfferingId());
|
||||||
if (backupRepository == null) {
|
if (backupRepository == null) {
|
||||||
|
|
@ -143,6 +155,23 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
||||||
command.setBackupRepoAddress(backupRepository.getAddress());
|
command.setBackupRepoAddress(backupRepository.getAddress());
|
||||||
command.setMountOptions(backupRepository.getMountOptions());
|
command.setMountOptions(backupRepository.getMountOptions());
|
||||||
|
|
||||||
|
if (VirtualMachine.State.Shutdown.equals(vm.getState())) {
|
||||||
|
List<VolumeVO> vmVolumes = volumeDao.findByInstance(vm.getId());
|
||||||
|
List<String> volumePaths = new ArrayList<>();
|
||||||
|
for (VolumeVO volume : vmVolumes) {
|
||||||
|
StoragePoolVO storagePool = primaryDataStoreDao.findById(volume.getPoolId());
|
||||||
|
if (Objects.isNull(storagePool)) {
|
||||||
|
throw new CloudRuntimeException("Unable to find storage pool associated to the volume");
|
||||||
|
}
|
||||||
|
String volumePathPrefix = String.format("/mnt/%s", storagePool.getPath());
|
||||||
|
if (ScopeType.HOST.equals(storagePool.getScope())) {
|
||||||
|
volumePathPrefix = storagePool.getPath();
|
||||||
|
}
|
||||||
|
volumePaths.add(String.format("%s/%s", volumePathPrefix, volume.getPath()));
|
||||||
|
}
|
||||||
|
command.setVolumePaths(volumePaths);
|
||||||
|
}
|
||||||
|
|
||||||
BackupAnswer answer = null;
|
BackupAnswer answer = null;
|
||||||
try {
|
try {
|
||||||
answer = (BackupAnswer) agentManager.send(host.getId(), command);
|
answer = (BackupAnswer) agentManager.send(host.getId(), command);
|
||||||
|
|
@ -192,6 +221,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
||||||
|
|
||||||
// TODO: get KVM agent to restore VM backup
|
// TODO: get KVM agent to restore VM backup
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,9 +246,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new CloudRuntimeException("Unable to craft restored volume due to: "+e);
|
throw new CloudRuntimeException("Unable to craft restored volume due to: "+e);
|
||||||
}
|
}
|
||||||
|
// TODO: get KVM agent to copy/restore the specific volume to
|
||||||
// TODO: get KVM agent to copy/restore the specific volume to datastore
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,7 +259,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
||||||
|
|
||||||
// TODO: this can be any host in the cluster or last host
|
// TODO: this can be any host in the cluster or last host
|
||||||
final VirtualMachine vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
|
final VirtualMachine vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
|
||||||
final Host host = getRunningVMHypervisorHost(vm);
|
final Host host = getVMHypervisorHost(vm);
|
||||||
|
|
||||||
DeleteBackupCommand command = new DeleteBackupCommand(backup.getExternalId(), backupRepository.getType(),
|
DeleteBackupCommand command = new DeleteBackupCommand(backup.getExternalId(), backupRepository.getType(),
|
||||||
backupRepository.getAddress(), backupRepository.getMountOptions());
|
backupRepository.getAddress(), backupRepository.getMountOptions());
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ public class LibvirtTakeBackupCommandWrapper extends CommandWrapper<TakeBackupCo
|
||||||
final String backupRepoType = command.getBackupRepoType();
|
final String backupRepoType = command.getBackupRepoType();
|
||||||
final String backupRepoAddress = command.getBackupRepoAddress();
|
final String backupRepoAddress = command.getBackupRepoAddress();
|
||||||
final String mountOptions = command.getMountOptions();
|
final String mountOptions = command.getMountOptions();
|
||||||
|
final List<String> diskPaths = command.getVolumePaths();
|
||||||
|
|
||||||
List<String[]> commands = new ArrayList<>();
|
List<String[]> commands = new ArrayList<>();
|
||||||
commands.add(new String[]{
|
commands.add(new String[]{
|
||||||
|
|
@ -50,7 +51,8 @@ public class LibvirtTakeBackupCommandWrapper extends CommandWrapper<TakeBackupCo
|
||||||
"-t", backupRepoType,
|
"-t", backupRepoType,
|
||||||
"-s", backupRepoAddress,
|
"-s", backupRepoAddress,
|
||||||
"-m", mountOptions,
|
"-m", mountOptions,
|
||||||
"-p", backupPath
|
"-p", backupPath,
|
||||||
|
"-d", String.join(",", diskPaths)
|
||||||
});
|
});
|
||||||
|
|
||||||
Pair<Integer, String> result = Script.executePipedCommands(commands, libvirtComputingResource.getCmdsTimeout());
|
Pair<Integer, String> result = Script.executePipedCommands(commands, libvirtComputingResource.getCmdsTimeout());
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,12 @@ NAS_TYPE=""
|
||||||
NAS_ADDRESS=""
|
NAS_ADDRESS=""
|
||||||
MOUNT_OPTS=""
|
MOUNT_OPTS=""
|
||||||
BACKUP_DIR=""
|
BACKUP_DIR=""
|
||||||
|
DISK_PATHS=""
|
||||||
|
|
||||||
### Operation methods ###
|
### Operation methods ###
|
||||||
|
|
||||||
backup_vm() {
|
backup_running_vm() {
|
||||||
mount_point=$(mktemp -d -t csbackup.XXXXX)
|
mount_operation
|
||||||
dest="$mount_point/${BACKUP_DIR}"
|
|
||||||
|
|
||||||
mount -t ${NAS_TYPE} ${NAS_ADDRESS} ${mount_point} $([[ ! -z "${MOUNT_OPTS}" ]] && echo -o ${MOUNT_OPTS})
|
|
||||||
mkdir -p $dest
|
mkdir -p $dest
|
||||||
|
|
||||||
deviceId=0
|
deviceId=0
|
||||||
|
|
@ -74,11 +72,19 @@ backup_vm() {
|
||||||
rmdir $mount_point
|
rmdir $mount_point
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_backup() {
|
backup_stopped_vm() {
|
||||||
mount_point=$(mktemp -d -t csbackup.XXXXX)
|
mount_operation
|
||||||
dest="$mount_point/${BACKUP_DIR}"
|
mkdir -p $dest
|
||||||
|
|
||||||
mount -t ${NAS_TYPE} ${NAS_ADDRESS} ${mount_point} $([[ ! -z "${MOUNT_OPTS}" ]] && echo -o ${MOUNT_OPTS})
|
IFS=","
|
||||||
|
|
||||||
|
for disk in $DISK_PATHS; do
|
||||||
|
rsync -az $disk $dest
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_backup() {
|
||||||
|
mount_operation
|
||||||
|
|
||||||
rm -frv $dest
|
rm -frv $dest
|
||||||
sync
|
sync
|
||||||
|
|
@ -87,6 +93,13 @@ delete_backup() {
|
||||||
rmdir $mount_point
|
rmdir $mount_point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mount_operation() {
|
||||||
|
mount_point=$(mktemp -d -t csbackup.XXXXX)
|
||||||
|
dest="$mount_point/${BACKUP_DIR}"
|
||||||
|
|
||||||
|
mount -t ${NAS_TYPE} ${NAS_ADDRESS} ${mount_point} $([[ ! -z "${MOUNT_OPTS}" ]] && echo -o ${MOUNT_OPTS})
|
||||||
|
}
|
||||||
|
|
||||||
function usage {
|
function usage {
|
||||||
echo ""
|
echo ""
|
||||||
echo "Usage: $0 -b <domain> -s <NAS storage mount path> -p <backup dest path>"
|
echo "Usage: $0 -b <domain> -s <NAS storage mount path> -p <backup dest path>"
|
||||||
|
|
@ -126,6 +139,11 @@ while [[ $# -gt 0 ]]; do
|
||||||
shift
|
shift
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
-d|--diskpaths)
|
||||||
|
DISK_PATHS="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
usage
|
usage
|
||||||
shift
|
shift
|
||||||
|
|
@ -138,7 +156,12 @@ while [[ $# -gt 0 ]]; do
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$OP" = "backup" ]; then
|
if [ "$OP" = "backup" ]; then
|
||||||
backup_vm
|
STATE=$(virsh -c qemu:///system list | grep $VM | awk '{print $3}')
|
||||||
|
if [ "$STATE" = "running" ]; then
|
||||||
|
backup_running_vm
|
||||||
|
else
|
||||||
|
backup_stopped_vm
|
||||||
|
fi
|
||||||
elif [ "$OP" = "delete" ]; then
|
elif [ "$OP" = "delete" ]; then
|
||||||
delete_backup
|
delete_backup
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
|
||||||
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
||||||
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
|
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
||||||
|
import org.apache.cloudstack.api.response.BackupRepositoryResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupResponse;
|
import org.apache.cloudstack.api.response.BackupResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupScheduleResponse;
|
import org.apache.cloudstack.api.response.BackupScheduleResponse;
|
||||||
import org.apache.cloudstack.api.response.BucketResponse;
|
import org.apache.cloudstack.api.response.BucketResponse;
|
||||||
|
|
@ -184,8 +185,10 @@ import org.apache.cloudstack.api.response.VpnUsersResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.backup.Backup;
|
import org.apache.cloudstack.backup.Backup;
|
||||||
import org.apache.cloudstack.backup.BackupOffering;
|
import org.apache.cloudstack.backup.BackupOffering;
|
||||||
|
import org.apache.cloudstack.backup.BackupRepository;
|
||||||
import org.apache.cloudstack.backup.BackupSchedule;
|
import org.apache.cloudstack.backup.BackupSchedule;
|
||||||
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
|
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
|
||||||
|
import org.apache.cloudstack.backup.dao.BackupRepositoryDao;
|
||||||
import org.apache.cloudstack.config.Configuration;
|
import org.apache.cloudstack.config.Configuration;
|
||||||
import org.apache.cloudstack.config.ConfigurationGroup;
|
import org.apache.cloudstack.config.ConfigurationGroup;
|
||||||
import org.apache.cloudstack.config.ConfigurationSubGroup;
|
import org.apache.cloudstack.config.ConfigurationSubGroup;
|
||||||
|
|
@ -487,6 +490,8 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||||
UserDataDao userDataDao;
|
UserDataDao userDataDao;
|
||||||
@Inject
|
@Inject
|
||||||
VlanDetailsDao vlanDetailsDao;
|
VlanDetailsDao vlanDetailsDao;
|
||||||
|
@Inject
|
||||||
|
BackupRepositoryDao backupRepositoryDao;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ObjectStoreDao _objectStoreDao;
|
ObjectStoreDao _objectStoreDao;
|
||||||
|
|
@ -5281,4 +5286,23 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||||
populateAccount(bucketResponse, bucket.getAccountId());
|
populateAccount(bucketResponse, bucket.getAccountId());
|
||||||
return bucketResponse;
|
return bucketResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BackupRepositoryResponse createBackupRepositoryResponse(BackupRepository backupRepository) {
|
||||||
|
BackupRepositoryResponse response = new BackupRepositoryResponse();
|
||||||
|
response.setName(backupRepository.getName());
|
||||||
|
response.setId(backupRepository.getUuid());
|
||||||
|
response.setCreated(backupRepository.getCreated());
|
||||||
|
response.setAddress(backupRepository.getAddress());
|
||||||
|
response.setProviderName(backupRepository.getProvider());
|
||||||
|
response.setType(backupRepository.getType());
|
||||||
|
response.setMountOptions(backupRepository.getMountOptions());
|
||||||
|
response.setCapacityBytes(backupRepository.getCapacityBytes());
|
||||||
|
DataCenter zone = ApiDBUtils.findZoneById(backupRepository.getZoneId());
|
||||||
|
if (zone != null) {
|
||||||
|
response.setZoneId(zone.getUuid());
|
||||||
|
response.setZoneName(zone.getName());
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,9 @@ import org.apache.cloudstack.api.command.user.backup.RemoveVirtualMachineFromBac
|
||||||
import org.apache.cloudstack.api.command.user.backup.RestoreBackupCmd;
|
import org.apache.cloudstack.api.command.user.backup.RestoreBackupCmd;
|
||||||
import org.apache.cloudstack.api.command.user.backup.RestoreVolumeFromBackupAndAttachToVMCmd;
|
import org.apache.cloudstack.api.command.user.backup.RestoreVolumeFromBackupAndAttachToVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.backup.UpdateBackupScheduleCmd;
|
import org.apache.cloudstack.api.command.user.backup.UpdateBackupScheduleCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.AddBackupRepositoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.DeleteBackupRepositoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.ListBackupRepositoriesCmd;
|
||||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||||
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
|
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
|
||||||
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
|
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
|
||||||
|
|
@ -945,6 +948,9 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
|
||||||
cmdList.add(RestoreBackupCmd.class);
|
cmdList.add(RestoreBackupCmd.class);
|
||||||
cmdList.add(DeleteBackupCmd.class);
|
cmdList.add(DeleteBackupCmd.class);
|
||||||
cmdList.add(RestoreVolumeFromBackupAndAttachToVMCmd.class);
|
cmdList.add(RestoreVolumeFromBackupAndAttachToVMCmd.class);
|
||||||
|
cmdList.add(AddBackupRepositoryCmd.class);
|
||||||
|
cmdList.add(DeleteBackupRepositoryCmd.class);
|
||||||
|
cmdList.add(ListBackupRepositoriesCmd.class);
|
||||||
return cmdList;
|
return cmdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
package org.apache.cloudstack.backup;
|
||||||
|
|
||||||
|
import com.cloud.user.AccountManager;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.component.ManagerBase;
|
||||||
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.AddBackupRepositoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.DeleteBackupRepositoryCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.repository.ListBackupRepositoriesCmd;
|
||||||
|
import org.apache.cloudstack.backup.dao.BackupRepositoryDao;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class BackupRepositoryServiceImpl extends ManagerBase implements BackupRepositoryService {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BackupRepositoryDao repositoryDao;
|
||||||
|
@Inject
|
||||||
|
private AccountManager accountManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BackupRepository addBackupRepository(AddBackupRepositoryCmd cmd) {
|
||||||
|
BackupRepositoryVO repository = new BackupRepositoryVO(cmd.getZoneId(), cmd.getProvider(), cmd.getName(),
|
||||||
|
cmd.getType(), cmd.getAddress(), cmd.getMountOptions(), cmd.getCapacityBytes());
|
||||||
|
repositoryDao.persist(repository);
|
||||||
|
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteBackupRepository(DeleteBackupRepositoryCmd cmd) {
|
||||||
|
BackupRepositoryVO backupRepositoryVO = repositoryDao.findById(cmd.getId());
|
||||||
|
if (Objects.isNull(backupRepositoryVO)) {
|
||||||
|
logger.debug("Backup repository appears to already be deleted");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
repositoryDao.remove(backupRepositoryVO.getId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<List<BackupRepository>, Integer> listBackupRepositories(ListBackupRepositoriesCmd cmd) {
|
||||||
|
Long zoneId = accountManager.checkAccessAndSpecifyAuthority(CallContext.current().getCallingAccount(), cmd.getZoneId());
|
||||||
|
Long id = cmd.getId();
|
||||||
|
String name = cmd.getName();
|
||||||
|
String provider = cmd.getProvider();
|
||||||
|
String keyword = cmd.getKeyword();
|
||||||
|
|
||||||
|
SearchBuilder<BackupRepositoryVO> sb = repositoryDao.createSearchBuilder();
|
||||||
|
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
|
||||||
|
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
|
||||||
|
sb.and("zoneId", sb.entity().getZoneId(), SearchCriteria.Op.EQ);
|
||||||
|
sb.and("provider", sb.entity().getProvider(), SearchCriteria.Op.EQ);
|
||||||
|
|
||||||
|
SearchCriteria<BackupRepositoryVO> sc = sb.create();
|
||||||
|
if (keyword != null) {
|
||||||
|
SearchCriteria<BackupRepositoryVO> ssc = repositoryDao.createSearchCriteria();
|
||||||
|
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
|
||||||
|
ssc.addOr("provider", SearchCriteria.Op.LIKE, "%" + keyword + "%");
|
||||||
|
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(id)) {
|
||||||
|
sc.setParameters("id", id);
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(name)) {
|
||||||
|
sc.setParameters("name", name);
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(zoneId)) {
|
||||||
|
sc.setParameters("zoneId", zoneId);
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(provider)) {
|
||||||
|
sc.setParameters("provider", provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
// search Store details by ids
|
||||||
|
Pair<List<BackupRepositoryVO>, Integer> repositoryVOPair = repositoryDao.searchAndCount(sc, null);
|
||||||
|
return new Pair<>(new ArrayList<>(repositoryVOPair.first()), repositoryVOPair.second());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -338,6 +338,8 @@
|
||||||
<property name="asyncJobDispatcher" ref="ApiAsyncJobDispatcher" />
|
<property name="asyncJobDispatcher" ref="ApiAsyncJobDispatcher" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="backupRepositoryService" class="org.apache.cloudstack.backup.BackupRepositoryServiceImpl" />
|
||||||
|
|
||||||
<bean id="storageLayer" class="com.cloud.storage.JavaStorageLayer" />
|
<bean id="storageLayer" class="com.cloud.storage.JavaStorageLayer" />
|
||||||
|
|
||||||
<bean id="nfsMountManager" class="org.apache.cloudstack.storage.NfsMountManagerImpl" >
|
<bean id="nfsMountManager" class="org.apache.cloudstack.storage.NfsMountManagerImpl" >
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ except ImportError:
|
||||||
raise RuntimeError("python setuptools is required to build Marvin")
|
raise RuntimeError("python setuptools is required to build Marvin")
|
||||||
|
|
||||||
|
|
||||||
VERSION = "4.20.0.0-SNAPSHOT"
|
VERSION = "4.20.0.0"
|
||||||
|
|
||||||
setup(name="Marvin",
|
setup(name="Marvin",
|
||||||
version=VERSION,
|
version=VERSION,
|
||||||
|
|
|
||||||
|
|
@ -402,6 +402,7 @@
|
||||||
"label.backup.restore": "Restore Instance backup",
|
"label.backup.restore": "Restore Instance backup",
|
||||||
"label.backupofferingid": "Backup offering",
|
"label.backupofferingid": "Backup offering",
|
||||||
"label.backupofferingname": "Backup offering",
|
"label.backupofferingname": "Backup offering",
|
||||||
|
"label.backup.repository.add": "Add backup repository",
|
||||||
"label.balance": "Balance",
|
"label.balance": "Balance",
|
||||||
"label.bandwidth": "Bandwidth",
|
"label.bandwidth": "Bandwidth",
|
||||||
"label.baremetal.dhcp.devices": "Bare metal DHCP devices",
|
"label.baremetal.dhcp.devices": "Bare metal DHCP devices",
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,16 @@ export default {
|
||||||
label: 'label.backup.repository.add',
|
label: 'label.backup.repository.add',
|
||||||
listView: true,
|
listView: true,
|
||||||
args: [
|
args: [
|
||||||
'name', 'provider', 'address', 'opts', 'zoneid'
|
'name', 'provider', 'address', 'type', 'mountopts', 'zoneid'
|
||||||
]
|
],
|
||||||
|
mapping: {
|
||||||
|
type: {
|
||||||
|
value: (record) => { return 'nfs' }
|
||||||
|
},
|
||||||
|
provider: {
|
||||||
|
value: (record) => { return 'nas' }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1169,6 +1169,7 @@ export default {
|
||||||
|
|
||||||
this.showAction = true
|
this.showAction = true
|
||||||
const listIconForFillValues = ['copy-outlined', 'CopyOutlined', 'edit-outlined', 'EditOutlined', 'share-alt-outlined', 'ShareAltOutlined']
|
const listIconForFillValues = ['copy-outlined', 'CopyOutlined', 'edit-outlined', 'EditOutlined', 'share-alt-outlined', 'ShareAltOutlined']
|
||||||
|
console.log(this.currentAction.paramFields)
|
||||||
for (const param of this.currentAction.paramFields) {
|
for (const param of this.currentAction.paramFields) {
|
||||||
if (param.type === 'list' && ['tags', 'hosttags', 'storagetags', 'files'].includes(param.name)) {
|
if (param.type === 'list' && ['tags', 'hosttags', 'storagetags', 'files'].includes(param.name)) {
|
||||||
param.type = 'string'
|
param.type = 'string'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue