This is an automated email from the ASF dual-hosted git repository. shwstppr pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit 1c1dad977e5e6a425cc8efe4e8bd22a2bbfe92b3 Merge: eab37eca437 35a7438033a Author: Abhishek Kumar <abhishek.mr...@gmail.com> AuthorDate: Thu Mar 6 09:55:27 2025 +0530 Merge remote-tracking branch 'apache/4.20' .../user/backup/DeleteBackupScheduleCmd.java | 14 +- .../api/response/BackupRepositoryResponse.java | 12 - .../apache/cloudstack/backup/BackupManager.java | 5 +- .../com/cloud/agent/manager/AgentManagerImpl.java | 2 +- .../com/cloud/vm/VirtualMachineManagerImpl.java | 3 + packaging/el8/cloud.spec | 1 + .../cloudstack/backup/NASBackupProvider.java | 10 +- .../LibvirtGetVmIpAddressCommandWrapper.java | 167 +++++++---- .../LibvirtRestoreBackupCommandWrapper.java | 22 +- .../LibvirtGetVmIpAddressCommandWrapperTest.java | 320 +++++++++++++++++++++ .../cluster/KubernetesClusterManagerImpl.java | 14 + .../KubernetesClusterDestroyWorker.java | 4 + .../driver/StorPoolPrimaryDataStoreDriver.java | 119 ++++---- .../storage/datastore/util/StorPoolUtil.java | 6 + .../storage/motion/StorPoolDataMotionStrategy.java | 15 +- scripts/vm/hypervisor/kvm/nasbackup.sh | 68 ++++- .../java/com/cloud/alert/AlertManagerImpl.java | 160 +++++------ server/src/main/java/com/cloud/api/ApiDBUtils.java | 2 +- .../main/java/com/cloud/api/ApiResponseHelper.java | 1 - .../com/cloud/resource/ResourceManagerImpl.java | 4 +- .../cloudstack/backup/BackupManagerImpl.java | 58 ++-- setup/bindir/cloud-setup-databases.in | 2 + .../plugins/linstor/test_linstor_volumes.py | 252 +++++++++++++--- test/integration/smoke/test_purge_expunged_vms.py | 4 +- ui/public/index.html | 2 +- ui/public/locales/en.json | 7 + ui/public/locales/pt_BR.json | 1 + ui/src/config/section/config.js | 2 +- ui/src/config/section/infra/hosts.js | 20 +- ui/src/config/section/storage.js | 21 +- ui/src/locales/index.js | 2 +- ui/src/main.js | 2 +- ui/src/views/infra/ChangeHostPassword.vue | 150 ++++++++++ ui/src/views/infra/ConfigureHostOOBM.vue | 172 +++++++++++ ui/src/views/infra/HostEnableDisable.vue | 12 +- ui/src/views/infra/HostInfo.vue | 46 ++- ui/src/views/offering/AddDiskOffering.vue | 1 - ui/src/views/storage/CreateTemplate.vue | 113 ++++---- 38 files changed, 1412 insertions(+), 404 deletions(-) diff --cc server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java index 816d8fd66c4,6198806c05f..d2732eca98d --- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java @@@ -28,16 -29,10 +29,6 @@@ import java.util.Timer import java.util.TimerTask; import java.util.stream.Collectors; --import com.amazonaws.util.CollectionUtils; - import com.cloud.alert.AlertManager; - import com.cloud.configuration.Resource; - import com.cloud.exception.ResourceAllocationException; - import com.cloud.storage.Snapshot; --import com.cloud.storage.VolumeApiService; - import com.cloud.user.DomainManager; - import com.cloud.user.ResourceLimitService; --import com.cloud.utils.fsm.NoTransitionException; --import com.cloud.vm.VirtualMachineManager; import javax.inject.Inject; import javax.naming.ConfigurationException; @@@ -83,8 -76,8 +73,11 @@@ import org.apache.cloudstack.utils.refl import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; ++import com.amazonaws.util.CollectionUtils; ++import com.cloud.alert.AlertManager; import com.cloud.api.ApiDispatcher; import com.cloud.api.ApiGsonHelper; ++import com.cloud.configuration.Resource; import com.cloud.dc.DataCenter; import com.cloud.dc.dao.DataCenterDao; import com.cloud.event.ActionEvent; @@@ -94,6 -87,6 +87,7 @@@ import com.cloud.event.EventVO import com.cloud.event.UsageEventUtils; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; ++import com.cloud.exception.ResourceAllocationException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; @@@ -101,13 -94,13 +95,17 @@@ import com.cloud.hypervisor.HypervisorG import com.cloud.hypervisor.HypervisorGuruManager; import com.cloud.projects.Project; import com.cloud.storage.ScopeType; ++import com.cloud.storage.Snapshot; import com.cloud.storage.Volume; ++import com.cloud.storage.VolumeApiService; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountService; ++import com.cloud.user.DomainManager; ++import com.cloud.user.ResourceLimitService; import com.cloud.user.User; import com.cloud.utils.DateUtil; import com.cloud.utils.Pair; @@@ -126,8 -118,8 +124,10 @@@ import com.cloud.utils.db.TransactionCa import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; ++import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; ++import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; import com.google.gson.Gson; @@@ -172,12 -162,6 +172,10 @@@ public class BackupManagerImpl extends private VirtualMachineManager virtualMachineManager; @Inject private VolumeApiService volumeApiService; + @Inject - private VolumeOrchestrationService volumeOrchestrationService; - @Inject + private ResourceLimitService resourceLimitMgr; + @Inject + private AlertManager alertManager; private AsyncJobDispatcher asyncJobDispatcher; private Timer backupTimer; @@@ -514,42 -467,38 +512,59 @@@ @Override @ActionEvent(eventType = EventTypes.EVENT_VM_BACKUP_SCHEDULE_DELETE, eventDescription = "deleting VM backup schedule") - public boolean deleteBackupSchedule(Long vmId) { - final VMInstanceVO vm = findVmById(vmId); - validateForZone(vm.getDataCenterId()); - accountManager.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); + public boolean deleteBackupSchedule(DeleteBackupScheduleCmd cmd) { + Long vmId = cmd.getVmId(); + Long id = cmd.getId(); + if (Objects.isNull(vmId) && Objects.isNull(id)) { + throw new InvalidParameterValueException("Either instance ID or ID of backup schedule needs to be specified"); + } + if (Objects.nonNull(vmId)) { + final VMInstanceVO vm = findVmById(vmId); + validateForZone(vm.getDataCenterId()); + accountManager.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); + return deleteAllVMBackupSchedules(vm.getId()); + } else { + final BackupSchedule schedule = backupScheduleDao.findById(id); + if (schedule == null) { + throw new CloudRuntimeException("Could not find the requested backup schedule."); + } + return backupScheduleDao.remove(schedule.getId()); + } + } - final BackupSchedule schedule = backupScheduleDao.findByVM(vmId); - if (schedule == null) { - throw new CloudRuntimeException("VM has no backup schedule defined, no need to delete anything."); + private boolean deleteAllVMBackupSchedules(long vmId) { + List<BackupScheduleVO> vmBackupSchedules = backupScheduleDao.listByVM(vmId); + boolean success = true; + for (BackupScheduleVO vmBackupSchedule : vmBackupSchedules) { + success = success && backupScheduleDao.remove(vmBackupSchedule.getId()); } - return backupScheduleDao.remove(schedule.getId()); + return success; } + private void postCreateScheduledBackup(Backup.Type backupType, Long vmId) { + DateUtil.IntervalType intervalType = DateUtil.IntervalType.valueOf(backupType.name()); + final BackupScheduleVO schedule = backupScheduleDao.findByVMAndIntervalType(vmId, intervalType); + if (schedule == null) { + return; + } + Integer maxBackups = schedule.getMaxBackups(); + if (maxBackups == null) { + return; + } + List<BackupVO> backups = backupDao.listBackupsByVMandIntervalType(vmId, backupType); + while (backups.size() > maxBackups) { + BackupVO oldestBackup = backups.get(0); + if (deleteBackup(oldestBackup.getId(), false)) { + ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, oldestBackup.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_VM_BACKUP_DELETE, + "Successfully deleted oldest backup: " + oldestBackup.getId(), oldestBackup.getId(), ApiCommandResourceType.Backup.toString(), 0); + } + backups.remove(oldestBackup); + } + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VM_BACKUP_CREATE, eventDescription = "creating VM backup", async = true) - public boolean createBackup(final Long vmId) { + public boolean createBackup(final Long vmId, final Long scheduleId) throws ResourceAllocationException { final VMInstanceVO vm = findVmById(vmId); validateForZone(vm.getDataCenterId()); accountManager.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); diff --cc ui/public/locales/en.json index f0fc1bc1b61,0a67c67ba9a..c5adda7d743 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@@ -2638,9 -2617,14 +2638,14 @@@ "label.zonewizard.traffictype.storage": "Storage: Traffic between primary and secondary storage servers, such as Instance Templates and Snapshots.", "label.buckets": "Buckets", "label.objectstorageid": "Object Storage Pool", + "label.oobm.address": "Out-of-band management address", + "label.oobm.driver": "Out-of-band management driver", + "label.oobm.port": "Out-of-band management port", + "label.oobm.powerstate": "Out-of-band management power state", + "label.oobm.username": "Out-of-band management username", "label.bucket.update": "Update Bucket", "label.bucket.delete": "Delete Bucket", -"label.quotagb": "Quota in GB", +"label.quotagib": "Quota in GiB", "label.encryption": "Encryption", "label.versioning": "Versioning", "label.objectlocking": "Object Lock",