|
21 | 21 | import com.cloud.host.Status; |
22 | 22 | import com.cloud.host.dao.HostDao; |
23 | 23 | import com.cloud.hypervisor.Hypervisor; |
| 24 | +import com.cloud.utils.script.Script; |
24 | 25 | import com.cloud.storage.StoragePoolHostVO; |
25 | 26 | import com.cloud.storage.Volume; |
26 | 27 | import com.cloud.storage.VolumeVO; |
|
29 | 30 | import com.cloud.utils.Pair; |
30 | 31 | import com.cloud.utils.Ternary; |
31 | 32 | import com.cloud.utils.component.AdapterBase; |
| 33 | +import com.cloud.utils.db.Transaction; |
| 34 | +import com.cloud.utils.db.TransactionCallbackNoReturn; |
| 35 | +import com.cloud.utils.db.TransactionStatus; |
32 | 36 | import com.cloud.utils.exception.CloudRuntimeException; |
33 | 37 | import com.cloud.utils.ssh.SshHelper; |
34 | 38 | import com.cloud.vm.VMInstanceVO; |
35 | 39 | import com.cloud.vm.VirtualMachine; |
36 | 40 | import com.cloud.vm.dao.VMInstanceDao; |
| 41 | + |
| 42 | +import org.apache.cloudstack.api.InternalIdentity; |
37 | 43 | import org.apache.cloudstack.backup.dao.BackupDao; |
38 | 44 | import org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl; |
39 | 45 | import org.apache.cloudstack.backup.networker.NetworkerClient; |
|
44 | 50 | import org.apache.logging.log4j.LogManager; |
45 | 51 | import org.apache.xml.utils.URI; |
46 | 52 | import org.apache.cloudstack.backup.networker.api.NetworkerBackup; |
| 53 | + |
47 | 54 | import javax.inject.Inject; |
| 55 | + |
48 | 56 | import java.net.URISyntaxException; |
49 | 57 | import java.security.KeyManagementException; |
50 | 58 | import java.security.NoSuchAlgorithmException; |
|
60 | 68 | import java.util.regex.Matcher; |
61 | 69 | import java.util.regex.Pattern; |
62 | 70 | import java.util.stream.Collectors; |
63 | | -import com.cloud.utils.script.Script; |
64 | 71 |
|
65 | 72 | public class NetworkerBackupProvider extends AdapterBase implements BackupProvider, Configurable { |
66 | 73 |
|
@@ -560,6 +567,86 @@ public Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<Vir |
560 | 567 | return metrics; |
561 | 568 | } |
562 | 569 |
|
| 570 | + @Override |
| 571 | + public void syncBackups(VirtualMachine vm, Backup.Metric metric) { |
| 572 | + final Long zoneId = vm.getDataCenterId(); |
| 573 | + Transaction.execute(new TransactionCallbackNoReturn() { |
| 574 | + @Override |
| 575 | + public void doInTransactionWithoutResult(TransactionStatus status) { |
| 576 | + final List<Backup> backupsInDb = backupDao.listByVmId(null, vm.getId()); |
| 577 | + final ArrayList<String> backupsInNetworker = getClient(zoneId).getBackupsForVm(vm); |
| 578 | + final List<Long> removeList = backupsInDb.stream().map(InternalIdentity::getId).collect(Collectors.toList()); |
| 579 | + for (final String networkerBackupId : backupsInNetworker ) { |
| 580 | + Long vmBackupSize=0L; |
| 581 | + boolean backupExists = false; |
| 582 | + for (final Backup backupInDb : backupsInDb) { |
| 583 | + LOG.debug(String.format("Checking if Backup %s with external ID %s for VM %s is valid", backupsInDb, backupInDb.getName(), vm)); |
| 584 | + if ( networkerBackupId.equals(backupInDb.getExternalId()) ) { |
| 585 | + LOG.debug(String.format("Found Backup %s in both Database and Networker", backupInDb)); |
| 586 | + backupExists = true; |
| 587 | + removeList.remove(backupInDb.getId()); |
| 588 | + if (metric != null) { |
| 589 | + LOG.debug(String.format("Update backup [%s] from [size: %s, protected size: %s] to [size: %s, protected size: %s].", |
| 590 | + backupInDb, backupInDb.getSize(), backupInDb.getProtectedSize(), |
| 591 | + metric.getBackupSize(), metric.getDataSize())); |
| 592 | + ((BackupVO) backupInDb).setSize(metric.getBackupSize()); |
| 593 | + ((BackupVO) backupInDb).setProtectedSize(metric.getDataSize()); |
| 594 | + backupDao.update(backupInDb.getId(), ((BackupVO) backupInDb)); |
| 595 | + } |
| 596 | + break; |
| 597 | + } |
| 598 | + } |
| 599 | + if (backupExists) { |
| 600 | + continue; |
| 601 | + } |
| 602 | + // Technically an administrator can manually create a backup for a VM by utilizing the KVM scripts |
| 603 | + // with the proper parameters. So we will register any backups taken on the Networker side from |
| 604 | + // outside Cloudstack. If ever Networker will support KVM out of the box this functionality also will |
| 605 | + // ensure that SLA like backups will be found and registered. |
| 606 | + NetworkerBackup strayNetworkerBackup = getClient(vm.getDataCenterId()).getNetworkerBackupInfo(networkerBackupId); |
| 607 | + // Since running backups are already present in Networker Server but not completed |
| 608 | + // make sure the backup is not in progress at this time. |
| 609 | + if ( strayNetworkerBackup.getCompletionTime() != null) { |
| 610 | + BackupVO strayBackup = new BackupVO(); |
| 611 | + strayBackup.setVmId(vm.getId()); |
| 612 | + strayBackup.setExternalId(strayNetworkerBackup.getId()); |
| 613 | + strayBackup.setType(strayNetworkerBackup.getType()); |
| 614 | + SimpleDateFormat formatterDateTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); |
| 615 | + try { |
| 616 | + strayBackup.setDate(formatterDateTime.parse(strayNetworkerBackup.getSaveTime())); |
| 617 | + } catch (ParseException e) { |
| 618 | + String msg = String.format("Unable to parse date [%s].", strayNetworkerBackup.getSaveTime()); |
| 619 | + LOG.error(msg, e); |
| 620 | + throw new CloudRuntimeException(msg, e); |
| 621 | + } |
| 622 | + strayBackup.setStatus(Backup.Status.BackedUp); |
| 623 | + for ( Backup.VolumeInfo thisVMVol : vm.getBackupVolumeList()) { |
| 624 | + vmBackupSize += (thisVMVol.getSize() / 1024L /1024L); |
| 625 | + } |
| 626 | + strayBackup.setSize(vmBackupSize); |
| 627 | + strayBackup.setProtectedSize(strayNetworkerBackup.getSize().getValue() / 1024L ); |
| 628 | + strayBackup.setBackupOfferingId(vm.getBackupOfferingId()); |
| 629 | + strayBackup.setAccountId(vm.getAccountId()); |
| 630 | + strayBackup.setDomainId(vm.getDomainId()); |
| 631 | + strayBackup.setZoneId(vm.getDataCenterId()); |
| 632 | + LOG.debug(String.format("Creating a new entry in backups: [id: %s, uuid: %s, vm_id: %s, external_id: %s, type: %s, date: %s, backup_offering_id: %s, account_id: %s, " |
| 633 | + + "domain_id: %s, zone_id: %s].", strayBackup.getId(), strayBackup.getUuid(), strayBackup.getVmId(), strayBackup.getExternalId(), |
| 634 | + strayBackup.getType(), strayBackup.getDate(), strayBackup.getBackupOfferingId(), strayBackup.getAccountId(), |
| 635 | + strayBackup.getDomainId(), strayBackup.getZoneId())); |
| 636 | + backupDao.persist(strayBackup); |
| 637 | + LOG.warn("Added backup found in provider [" + strayBackup + "]"); |
| 638 | + } else { |
| 639 | + LOG.debug ("Backup is in progress, skipping addition for this run"); |
| 640 | + } |
| 641 | + } |
| 642 | + for (final Long backupIdToRemove : removeList) { |
| 643 | + LOG.warn(String.format("Removing backup with ID: [%s].", backupIdToRemove)); |
| 644 | + backupDao.remove(backupIdToRemove); |
| 645 | + } |
| 646 | + } |
| 647 | + }); |
| 648 | + } |
| 649 | + |
563 | 650 | @Override |
564 | 651 | public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm, Backup.Metric metric) { |
565 | 652 | // Technically an administrator can manually create a backup for a VM by utilizing the KVM scripts |
|
0 commit comments