nvazquez commented on a change in pull request #3553: [WIP] [DO NOT MERGE] CloudStack Backup & Recovery Framework URL: https://github.com/apache/cloudstack/pull/3553#discussion_r357928200
########## File path: server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java ########## @@ -0,0 +1,1051 @@ +// 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.backup; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.Timer; +import java.util.TimerTask; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.command.admin.backup.DeleteBackupOfferingCmd; +import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd; +import org.apache.cloudstack.api.command.admin.backup.ListBackupProviderOfferingsCmd; +import org.apache.cloudstack.api.command.admin.backup.ListBackupProvidersCmd; +import org.apache.cloudstack.api.command.user.backup.AssignVirtualMachineToBackupOfferingCmd; +import org.apache.cloudstack.api.command.user.backup.CreateBackupCmd; +import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd; +import org.apache.cloudstack.api.command.user.backup.DeleteBackupCmd; +import org.apache.cloudstack.api.command.user.backup.DeleteBackupScheduleCmd; +import org.apache.cloudstack.api.command.user.backup.ListBackupOfferingsCmd; +import org.apache.cloudstack.api.command.user.backup.ListBackupScheduleCmd; +import org.apache.cloudstack.api.command.user.backup.ListBackupsCmd; +import org.apache.cloudstack.api.command.user.backup.RemoveVirtualMachineFromBackupOfferingCmd; +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.UpdateBackupScheduleCmd; +import org.apache.cloudstack.backup.dao.BackupDao; +import org.apache.cloudstack.backup.dao.BackupOfferingDao; +import org.apache.cloudstack.backup.dao.BackupScheduleDao; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher; +import org.apache.cloudstack.framework.jobs.AsyncJobManager; +import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; +import org.apache.cloudstack.poll.BackgroundPollManager; +import org.apache.cloudstack.poll.BackgroundPollTask; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; + +import com.cloud.api.ApiDispatcher; +import com.cloud.api.ApiGsonHelper; +import com.cloud.dc.DataCenter; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.event.ActionEvent; +import com.cloud.event.ActionEventUtils; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventUtils; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.hypervisor.HypervisorGuru; +import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.projects.Project; +import com.cloud.storage.ScopeType; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.usage.dao.UsageBackupDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountService; +import com.cloud.user.User; +import com.cloud.utils.DateUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.VMInstanceDao; +import com.google.common.base.Strings; +import com.google.gson.Gson; + +public class BackupManagerImpl extends ManagerBase implements BackupManager { + private static final Logger LOG = Logger.getLogger(BackupManagerImpl.class); + + @Inject + private BackupDao backupDao; + @Inject + private BackupScheduleDao backupScheduleDao; + @Inject + private BackupOfferingDao backupOfferingDao; + @Inject + private VMInstanceDao vmInstanceDao; + @Inject + private AccountService accountService; + @Inject + private AccountManager accountManager; + @Inject + private UsageBackupDao usageBackupDao; + @Inject + private VolumeDao volumeDao; + @Inject + private DataCenterDao dataCenterDao; + @Inject + private BackgroundPollManager backgroundPollManager; + @Inject + private HostDao hostDao; + @Inject + private HypervisorGuruManager hypervisorGuruManager; + @Inject + private PrimaryDataStoreDao primaryDataStoreDao; + @Inject + private DiskOfferingDao diskOfferingDao; + @Inject + private ApiDispatcher apiDispatcher; + @Inject + private AsyncJobManager asyncJobManager; + + private AsyncJobDispatcher asyncJobDispatcher; + private Timer backupTimer; + private Date currentTimestamp; + + private static Map<String, BackupProvider> backupProvidersMap = new HashMap<>(); + private List<BackupProvider> backupProviders; + + public AsyncJobDispatcher getAsyncJobDispatcher() { + return asyncJobDispatcher; + } + + public void setAsyncJobDispatcher(final AsyncJobDispatcher dispatcher) { + asyncJobDispatcher = dispatcher; + } + + @Override + public List<BackupOffering> listBackupProviderOfferings(final Long zoneId) { + if (zoneId == null || zoneId < 1) { + throw new CloudRuntimeException("Invalid zone ID passed"); + } + validateForZone(zoneId); + final Account account = CallContext.current().getCallingAccount(); + if (!accountService.isRootAdmin(account.getId())) { + throw new PermissionDeniedException("Parameter external can only be specified by a Root Admin, permission denied"); + } + final BackupProvider backupProvider = getBackupProvider(zoneId); + LOG.debug("Listing external backup offerings for the backup provider configured for zone ID " + zoneId); + return backupProvider.listBackupOfferings(zoneId); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_BACKUP_IMPORT_OFFERING, eventDescription = "importing backup offering", async = true) + public BackupOffering importBackupOffering(final ImportBackupOfferingCmd cmd) { + validateForZone(cmd.getZoneId()); + final BackupOffering existingOffering = backupOfferingDao.findByExternalId(cmd.getExternalId(), cmd.getZoneId()); + if (existingOffering != null) { + throw new CloudRuntimeException("A backup offering with external ID " + cmd.getExternalId() + " already exists"); + } + if (backupOfferingDao.findByName(cmd.getName(), cmd.getZoneId()) != null) { + throw new CloudRuntimeException("A backup offering with the same name already exists in this zone"); + } + + final BackupProvider provider = getBackupProvider(cmd.getZoneId()); + if (!provider.isBackupOffering(cmd.getZoneId(), cmd.getExternalId())) { + throw new CloudRuntimeException("Backup offering '" + cmd.getExternalId() + "' does not exist on provider " + provider.getName() + " on zone " + cmd.getZoneId()); + } + + final BackupOfferingVO offering = new BackupOfferingVO(cmd.getZoneId(), cmd.getExternalId(), provider.getName(), + cmd.getName(), cmd.getDescription(), cmd.getUserDrivenBackups()); + + final BackupOfferingVO savedOffering = backupOfferingDao.persist(offering); + if (savedOffering == null) { + throw new CloudRuntimeException("Unable to create backup offering: " + cmd.getExternalId() + ", name: " + cmd.getName()); + } + LOG.debug("Successfully created backup offering " + cmd.getName() + " mapped to backup provider offering " + cmd.getExternalId()); + return savedOffering; + } + + @Override + public Pair<List<BackupOffering>, Integer> listBackupOfferings(final ListBackupOfferingsCmd cmd) { + final Long offeringId = cmd.getOfferingId(); + final Long zoneId = cmd.getZoneId(); + final String keyword = cmd.getKeyword(); + + if (offeringId != null) { + BackupOfferingVO offering = backupOfferingDao.findById(offeringId); + if (offering == null) { + throw new CloudRuntimeException("Offering ID " + offeringId + " does not exist"); + } + return new Pair<>(Collections.singletonList(offering), 1); + } + + final Filter searchFilter = new Filter(BackupOfferingVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); + SearchBuilder<BackupOfferingVO> sb = backupOfferingDao.createSearchBuilder(); Review comment: Can this be moved to the backupOfferingDao instead? ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services