Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class ApiConstants {
public static final String BACKUP_STORAGE_LIMIT = "backupstoragelimit";
public static final String BACKUP_STORAGE_TOTAL = "backupstoragetotal";
public static final String BACKUP_VM_OFFERING_REMOVED = "vmbackupofferingremoved";
public static final String BACKUP_VM_EXPUNGED = "backupvmexpunged";
public static final String BACKUP_TOTAL = "backuptotal";
public static final String BASE64_IMAGE = "base64image";
public static final String BGP_PEERS = "bgppeers";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public class BackupOfferingResponse extends BaseResponse {
@Param(description = "zone name")
private String zoneName;

@SerializedName(ApiConstants.CROSS_ZONE_INSTANCE_CREATION)
@Param(description = "the backups with this offering can be used to create Instances on all Zones", since = "4.22.0")
private Boolean crossZoneInstanceCreation;

@SerializedName(ApiConstants.CREATED)
@Param(description = "the date this backup offering was created")
private Date created;
Expand Down Expand Up @@ -97,6 +101,10 @@ public void setZoneName(String zoneName) {
this.zoneName = zoneName;
}

public void setCrossZoneInstanceCreation(Boolean crossZoneInstanceCreation) {
this.crossZoneInstanceCreation = crossZoneInstanceCreation;
}

public void setCreated(Date created) {
this.created = created;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ public class BackupResponse extends BaseResponse {
@Param(description = "The backup offering corresponding to this backup was removed from the VM", since = "4.21.0")
private Boolean vmOfferingRemoved;

@SerializedName(ApiConstants.BACKUP_VM_EXPUNGED)
@Param(description = "The VM from which the backup was taken is expunged", since = "4.22.0")
private Boolean vmExpunged;

public String getId() {
return id;
}
Expand Down Expand Up @@ -306,4 +310,8 @@ public Boolean getVmOfferingRemoved() {
public void setVmOfferingRemoved(Boolean vmOfferingRemoved) {
this.vmOfferingRemoved = vmOfferingRemoved;
}

public void setVmExpunged(Boolean vmExpunged) {
this.vmExpunged = vmExpunged;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import com.cloud.utils.db.GenericDao;

public interface BackupOfferingDao extends GenericDao<BackupOfferingVO, Long> {
BackupOfferingResponse newBackupOfferingResponse(BackupOffering policy);
BackupOfferingResponse newBackupOfferingResponse(BackupOffering policy, Boolean crossZoneInstanceCreation);
BackupOffering findByExternalId(String externalId, Long zoneId);
BackupOffering findByName(String name, Long zoneId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ protected void init() {
}

@Override
public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering) {
public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering, Boolean crossZoneInstanceCreation) {
DataCenterVO zone = dataCenterDao.findById(offering.getZoneId());

BackupOfferingResponse response = new BackupOfferingResponse();
Expand All @@ -64,6 +64,9 @@ public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering)
response.setZoneId(zone.getUuid());
response.setZoneName(zone.getName());
}
if (crossZoneInstanceCreation) {
response.setCrossZoneInstanceCreation(true);
}
response.setCreated(offering.getCreated());
response.setObjectName("backupoffering");
return response;
Expand Down
12 changes: 10 additions & 2 deletions server/src/main/java/com/cloud/api/ApiDBUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@
import org.apache.cloudstack.api.response.VpcOfferingResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.backup.BackupRepository;
import org.apache.cloudstack.backup.BackupSchedule;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
import org.apache.cloudstack.backup.dao.BackupRepositoryDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
Expand Down Expand Up @@ -493,6 +495,7 @@ public class ApiDBUtils {
static BackupDao s_backupDao;
static BackupScheduleDao s_backupScheduleDao;
static BackupOfferingDao s_backupOfferingDao;
static BackupRepositoryDao s_backupRepositoryDao;
static NicDao s_nicDao;
static ResourceManagerUtil s_resourceManagerUtil;
static SnapshotPolicyDetailsDao s_snapshotPolicyDetailsDao;
Expand Down Expand Up @@ -751,6 +754,8 @@ public class ApiDBUtils {
@Inject
private BackupOfferingDao backupOfferingDao;
@Inject
private BackupRepositoryDao backupRepositoryDao;
@Inject
private BackupScheduleDao backupScheduleDao;
@Inject
private NicDao nicDao;
Expand Down Expand Up @@ -899,6 +904,7 @@ void init() {
s_backupDao = backupDao;
s_backupScheduleDao = backupScheduleDao;
s_backupOfferingDao = backupOfferingDao;
s_backupRepositoryDao = backupRepositoryDao;
s_resourceIconDao = resourceIconDao;
s_resourceManagerUtil = resourceManagerUtil;
s_objectStoreDao = objectStoreDao;
Expand Down Expand Up @@ -2297,8 +2303,10 @@ public static BackupScheduleResponse newBackupScheduleResponse(BackupSchedule sc
return s_backupScheduleDao.newBackupScheduleResponse(schedule);
}

public static BackupOfferingResponse newBackupOfferingResponse(BackupOffering policy) {
return s_backupOfferingDao.newBackupOfferingResponse(policy);
public static BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering) {
BackupRepository repository = s_backupRepositoryDao.findByUuid(offering.getExternalId());
Boolean crossZoneInstanceCreationEnabled = repository != null ? repository.crossZoneInstanceCreationEnabled() : false;
return s_backupOfferingDao.newBackupOfferingResponse(offering, crossZoneInstanceCreationEnabled);
}

public static NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId) {
Expand Down
4 changes: 2 additions & 2 deletions server/src/main/java/com/cloud/api/ApiResponseHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -5079,8 +5079,8 @@ public BackupScheduleResponse createBackupScheduleResponse(BackupSchedule schedu
}

@Override
public BackupOfferingResponse createBackupOfferingResponse(BackupOffering policy) {
return ApiDBUtils.newBackupOfferingResponse(policy);
public BackupOfferingResponse createBackupOfferingResponse(BackupOffering offering) {
return ApiDBUtils.newBackupOfferingResponse(offering);
}

public ManagementServerResponse createManagementResponse(ManagementServerHost mgmt) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,9 @@ public Map<String, String> getBackupDetailsFromVM(VirtualMachine vm) {
ServiceOffering serviceOffering = serviceOfferingDao.findById(vm.getServiceOfferingId());
details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOffering.getUuid());
VirtualMachineTemplate template = vmTemplateDao.findById(vm.getTemplateId());
details.put(ApiConstants.TEMPLATE_ID, template.getUuid());
if (template != null) {
details.put(ApiConstants.TEMPLATE_ID, template.getUuid());
}

List<VMInstanceDetailVO> vmDetails = vmInstanceDetailsDao.listDetails(vm.getId());
HashMap<String, String> settings = new HashMap<>();
Expand Down Expand Up @@ -2140,10 +2142,15 @@ public BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails)
response.setId(backup.getUuid());
response.setName(backup.getName());
response.setDescription(backup.getDescription());
response.setVmName(vm.getHostName());
response.setVmId(vm.getUuid());
if (vm.getBackupOfferingId() == null || vm.getBackupOfferingId() != backup.getBackupOfferingId()) {
response.setVmOfferingRemoved(true);
if (vm != null) {
response.setVmName(vm.getHostName());
response.setVmId(vm.getUuid());
if (vm.getBackupOfferingId() == null || vm.getBackupOfferingId() != backup.getBackupOfferingId()) {
response.setVmOfferingRemoved(true);
}
}
if (vm == null || VirtualMachine.State.Expunging.equals(vm.getState())) {
response.setVmExpunged(true);
}
response.setExternalId(backup.getExternalId());
response.setType(backup.getType());
Expand All @@ -2159,9 +2166,11 @@ public BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails)
}
}
// ACS 4.20: For backups taken prior this release the backup.backed_volumes column would be empty hence use vm_instance.backup_volumes
String backedUpVolumes;
String backedUpVolumes = "";
if (Objects.isNull(backup.getBackedUpVolumes())) {
backedUpVolumes = new Gson().toJson(vm.getBackupVolumeList().toArray(), Backup.VolumeInfo[].class);
if (vm != null) {
backedUpVolumes = new Gson().toJson(vm.getBackupVolumeList().toArray(), Backup.VolumeInfo[].class);
}
} else {
backedUpVolumes = new Gson().toJson(backup.getBackedUpVolumes().toArray(), Backup.VolumeInfo[].class);
}
Expand Down
31 changes: 10 additions & 21 deletions ui/src/views/storage/CreateVMFromBackup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<a-form-item :label="$t('label.name.optional')" name="name">
<a-input v-model:value="form.name" />
</a-form-item>
<a-form-item v-if="!resource.virtualmachineid" name="preserveIpAddresses" style="margin-top: 8px">
<a-form-item v-if="resource.backupvmexpunged" name="preserveIpAddresses" style="margin-top: 8px">
<a-switch v-model:checked="form.preserveIpAddresses" />
<template #label>
<tooltip-label :title="$t('label.use.backup.ip.address')" :tooltip="$t('label.use.backup.ip.address.tooltip')"/>
Expand Down Expand Up @@ -91,16 +91,16 @@ export default {
required: true
}
},
created () {
this.fetchServiceOffering()
this.fetchBackupOffering().then(() => {
this.fetchBackupRepository()
this.loading = false
})
async created () {
await Promise.all[(
this.fetchServiceOffering(),
this.fetchBackupOffering()
)]
this.loading = false
},
methods: {
fetchServiceOffering () {
getAPI('listServiceOfferings', {
return getAPI('listServiceOfferings', {
zoneid: this.resource.zoneid,
id: this.resource.vmdetails.serviceofferingid,
listall: true
Expand All @@ -118,28 +118,17 @@ export default {
this.backupOffering = backupOfferings[0]
})
},
fetchBackupRepository () {
if (this.backupOffering.provider !== 'nas') {
return
}
getAPI('listBackupRepositories', {
id: this.backupOffering.externalid
}).then(response => {
const backupRepositories = response.listbackuprepositoriesresponse.backuprepository || []
this.backupRepository = backupRepositories[0]
})
},
populatePreFillData () {
this.vmdetails = this.resource.vmdetails
this.dataPreFill.zoneid = this.resource.zoneid
this.dataPreFill.crosszoneinstancecreation = this.backupRepository?.crosszoneinstancecreation || this.backupOffering.provider === 'dummy'
this.dataPreFill.crosszoneinstancecreation = this.backupOffering?.crosszoneinstancecreation || this.backupOffering.provider === 'dummy'
this.dataPreFill.isIso = (this.vmdetails.isiso === 'true')
this.dataPreFill.backupid = this.resource.id
this.dataPreFill.computeofferingid = this.vmdetails.serviceofferingid
this.dataPreFill.templateid = this.vmdetails.templateid
this.dataPreFill.allowtemplateisoselection = true
this.dataPreFill.isoid = this.vmdetails.templateid
this.dataPreFill.allowIpAddressesFetch = !this.resource.virtualmachineid
this.dataPreFill.allowIpAddressesFetch = this.resource.backupvmexpunged
if (this.vmdetails.nics) {
const nics = JSON.parse(this.vmdetails.nics)
this.dataPreFill.networkids = nics.map(nic => nic.networkid)
Expand Down
Loading