Skip to content
2 changes: 2 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public class ApiConstants {
public static final String BACKUP_AVAILABLE = "backupavailable";
public static final String BACKUP_ID = "backupid";
public static final String BACKUP_LIMIT = "backuplimit";
public static final String BACKUP_PATH = "backuppath";
public static final String BACKUP_PATHS = "backuppaths";
public static final String BACKUP_OFFERING_NAME = "backupofferingname";
public static final String BACKUP_OFFERING_ID = "backupofferingid";
public static final String BACKUP_OFFERING_DETAILS = "backupofferingdetails";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ public void execute() {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Backup");
}

BackupResponse response = backupManager.createBackupResponse(backup, null);
boolean isCallerRootAdmin = _accountService.isRootAdmin(CallContext.current().getCallingAccountId());

BackupResponse response = backupManager.createBackupResponse(backup, null, isCallerRootAdmin);

response.setResponseName(getCommandName());
setResponseObject(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ public String getDescription() {
public void execute() {
try {
Backup backup = kvmBackupExportService.startBackup(this);
BackupResponse response = backupManager.createBackupResponse(backup, null);
boolean isCallerRootAdmin = _accountService.isRootAdmin(CallContext.current().getCallingAccountId());
BackupResponse response = backupManager.createBackupResponse(backup, null, isCallerRootAdmin);

response.setResponseName(getCommandName());
setResponseObject(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,13 @@ public Boolean getListVmDetails() {
/////////////////////////////////////////////////////

protected void setupResponseBackupList(final List<Backup> backups, final Integer count) {
boolean isCallerRootAdmin = _accountService.isRootAdmin(CallContext.current().getCallingAccountId());
final List<BackupResponse> responses = new ArrayList<>();
for (Backup backup : backups) {
if (backup == null) {
continue;
}
BackupResponse backupResponse = backupManager.createBackupResponse(backup, this.getListVmDetails());
BackupResponse backupResponse = backupManager.createBackupResponse(backup, this.getListVmDetails(), isCallerRootAdmin);
responses.add(backupResponse);
}
final ListResponse<BackupResponse> response = new ListResponse<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.api.response.helper.BackupVolumeNameAndPath;
import org.apache.cloudstack.backup.Backup;

import com.cloud.serializer.Param;
Expand Down Expand Up @@ -99,6 +100,10 @@ public class BackupResponse extends BaseResponse {
@Param(description = "Backup offering name")
private String backupOfferingName;

@SerializedName(ApiConstants.BACKUP_PATHS)
@Param(description = "The backup paths in the secondary storage")
private Map<String, BackupVolumeNameAndPath> backupPaths;
Comment thread
erikbocks marked this conversation as resolved.
Resolved
Comment thread
erikbocks marked this conversation as resolved.
Resolved

@SerializedName(ApiConstants.ACCOUNT_ID)
@Param(description = "Account id")
private String accountId;
Expand Down Expand Up @@ -386,4 +391,12 @@ public void setHostId(String hostId) {
public String getHostId() {
return this.hostId;
}

public Map<String, BackupVolumeNameAndPath> getBackupPaths() {
return backupPaths;
}

public void setBackupPaths(Map<String, BackupVolumeNameAndPath> backupPaths) {
this.backupPaths = backupPaths;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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.helper;

import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;

public class BackupVolumeNameAndPath {
@SerializedName(ApiConstants.VOLUME_NAME)
private String volumeName;

@SerializedName(ApiConstants.BACKUP_PATH)
private String backupPath;

public BackupVolumeNameAndPath(String volumeName, String backupPath) {
this.volumeName = volumeName;
this.backupPath = backupPath;
}
Comment thread
erikbocks marked this conversation as resolved.
Resolved

public String getVolumeName() {
return volumeName;
}

public void setVolumeName(String volumeName) {
this.volumeName = volumeName;
}

public String getBackupPath() {
return backupPath;
}

public void setBackupPath(String backupPath) {
this.backupPath = backupPath;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer

BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails);

BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails, boolean isCallerRootAdmin);
Comment thread
erikbocks marked this conversation as resolved.
Resolved
Comment thread
erikbocks marked this conversation as resolved.
Resolved

Capacity getBackupStorageUsedStats(Long zoneId);

void checkAndRemoveBackupOfferingBeforeExpunge(VirtualMachine vm);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package org.apache.cloudstack.backup.dao;

import com.cloud.utils.db.GenericDao;
import org.apache.cloudstack.api.response.helper.BackupVolumeNameAndPath;
import org.apache.cloudstack.backup.InternalBackupDataStoreVO;

import java.util.List;
import java.util.Map;

public interface InternalBackupDataStoreDao extends GenericDao<InternalBackupDataStoreVO, Long> {

Expand All @@ -30,4 +32,6 @@ public interface InternalBackupDataStoreDao extends GenericDao<InternalBackupDat
void expungeByBackupId(long backupId);

void updateVolumeId(long oldVolumeId, long newVolumeId);

Map<String, BackupVolumeNameAndPath> listVolumeNamesAndBackupPaths(long backupId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,28 @@
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.UpdateBuilder;
import org.apache.cloudstack.api.response.helper.BackupVolumeNameAndPath;
import org.apache.cloudstack.backup.InternalBackupDataStoreVO;

import javax.annotation.PostConstruct;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class InternalBackupDataStoreDaoImpl extends GenericDaoBase<InternalBackupDataStoreVO, Long> implements InternalBackupDataStoreDao {

private SearchBuilder<InternalBackupDataStoreVO> backupSearch;

private static final String BACKUP_ID = "backup_id";
private static final String VOLUME_ID = "volume_id";

private static final String SELECT_SECONDARY_PATH_AND_VOLUME_NAME = "select v.name, v.uuid, ibsr.`path` from internal_backup_store_ref ibsr join volumes v on ibsr.volume_id = v.id "
+ "where ibsr.backup_id = ?";

@PostConstruct
protected void init() {
backupSearch = createSearchBuilder();
Expand Down Expand Up @@ -71,4 +80,28 @@ public void updateVolumeId(long oldVolumeId, long newVolumeId) {
UpdateBuilder ub = getUpdateBuilder(delta);
update(ub, sc, null);
}

@Override
public Map<String, BackupVolumeNameAndPath> listVolumeNamesAndBackupPaths(long backupId) {
Map<String, BackupVolumeNameAndPath> volumeIdentifierToObjectMap = new HashMap<>();
try (TransactionLegacy transactionLegacy = TransactionLegacy.currentTxn()) {
try (PreparedStatement preparedStatement = transactionLegacy.prepareStatement(SELECT_SECONDARY_PATH_AND_VOLUME_NAME)) {
preparedStatement.setLong(1, backupId);

try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
String volumeName = resultSet.getString(1);
String volumeUuid = resultSet.getString(2);
String backupPath = resultSet.getString(3);

volumeIdentifierToObjectMap.put(volumeUuid, new BackupVolumeNameAndPath(volumeName, backupPath));
}
}
}
} catch (SQLException e) {
logger.warn("Failed to find volume names and backup paths on secondary for backup [{}].", backupId, e);
}
return volumeIdentifierToObjectMap;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
import org.apache.cloudstack.backup.dao.BackupOfferingDetailsDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.backup.dao.BackupUsageMetricDao;
import org.apache.cloudstack.backup.dao.InternalBackupDataStoreDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher;
Expand Down Expand Up @@ -258,6 +259,8 @@ public class BackupManagerImpl extends ManagerBase implements BackupManager {
private DomainHelper domainHelper;
@Inject
ReservationDao reservationDao;
@Inject
private InternalBackupDataStoreDao internalBackupDataStoreDao;

private AsyncJobDispatcher asyncJobDispatcher;
private Timer backupTimer;
Expand Down Expand Up @@ -2654,12 +2657,18 @@ Map<String, String> getDetailsFromBackupDetails(Long backupId) {

@Override
public BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails) {
return createBackupResponse(backup, listVmDetails, false);
}

@Override
public BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails, boolean isCallerRootAdmin) {
VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
AccountVO account = accountDao.findByIdIncludingRemoved(backup.getAccountId());
DomainVO domain = domainDao.findByIdIncludingRemoved(backup.getDomainId());
DataCenterVO zone = dataCenterDao.findByIdIncludingRemoved(backup.getZoneId());
Long offeringId = backup.getBackupOfferingId();
BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(offeringId);
logger.trace("Got offering [{}] for backup [{}].", offering, backup);

BackupResponse response = new BackupResponse();
response.setId(backup.getUuid());
Expand Down Expand Up @@ -2693,6 +2702,7 @@ public BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails)
}
if (backup.getBackupScheduleId() != null) {
BackupScheduleVO scheduleVO = backupScheduleDao.findById(backup.getBackupScheduleId());
logger.trace("Got backup schedule [{}] for backup [{}].", scheduleVO, backup);
if (scheduleVO != null) {
response.setIntervalType(scheduleVO.getScheduleType().toString());
}
Expand Down Expand Up @@ -2735,6 +2745,10 @@ public BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails)
response.setToCheckpointId(backup.getToCheckpointId());
}

if (offering != null && KBOSS_BACKUP_PROVIDER.equals(offering.getProvider()) && isCallerRootAdmin) {
response.setBackupPaths(internalBackupDataStoreDao.listVolumeNamesAndBackupPaths(backup.getId()));
}
Comment thread
erikbocks marked this conversation as resolved.
Resolved
Comment thread
erikbocks marked this conversation as resolved.
Resolved

response.setObjectName("backup");
return response;
}
Expand Down
Loading
Loading