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_r357928028
 
 

 ##########
 File path: 
plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/VeeamBackupProvider.java
 ##########
 @@ -0,0 +1,319 @@
+// 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.net.URISyntaxException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.cloudstack.backup.dao.BackupDao;
+import org.apache.cloudstack.backup.veeam.VeeamClient;
+import org.apache.cloudstack.backup.veeam.api.Job;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.vmware.VmwareDatacenter;
+import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap;
+import com.cloud.hypervisor.vmware.dao.VmwareDatacenterDao;
+import com.cloud.hypervisor.vmware.dao.VmwareDatacenterZoneMapDao;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
+import com.cloud.utils.db.TransactionStatus;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+
+public class VeeamBackupProvider extends AdapterBase implements 
BackupProvider, Configurable {
+
+    private static final Logger LOG = 
Logger.getLogger(VeeamBackupProvider.class);
+    public static final String BACKUP_IDENTIFIER = "-CSBKP-";
+
+    public ConfigKey<String> VeeamUrl = new ConfigKey<>("Advanced", 
String.class,
+            "backup.plugin.veeam.url",
+            "http://localhost:9399/api/";,
+            "The Veeam backup and recovery URL.", true, ConfigKey.Scope.Zone);
+
+    private ConfigKey<String> VeeamUsername = new ConfigKey<>("Advanced", 
String.class,
+            "backup.plugin.veeam.username",
+            "administrator",
+            "The Veeam backup and recovery username.", true, 
ConfigKey.Scope.Zone);
+
+    private ConfigKey<String> VeeamPassword = new ConfigKey<>("Advanced", 
String.class,
+            "backup.plugin.veeam.password",
+            "P@ssword123",
+            "The Veeam backup and recovery password.", true, 
ConfigKey.Scope.Zone);
+
+    private ConfigKey<Boolean> VeeamValidateSSLSecurity = new 
ConfigKey<>("Advanced", Boolean.class, "backup.plugin.veeam.validate.ssl", 
"false",
+            "When set to true, this will validate the SSL certificate when 
connecting to https/ssl enabled Veeam API service.", true, 
ConfigKey.Scope.Zone);
+
+    private ConfigKey<Integer> VeeamApiRequestTimeout = new 
ConfigKey<>("Advanced", Integer.class, "backup.plugin.veeam.request.timeout", 
"300",
+            "The Veeam B&R API request timeout in seconds.", true, 
ConfigKey.Scope.Zone);
+
+    @Inject
+    private VmwareDatacenterZoneMapDao vmwareDatacenterZoneMapDao;
+    @Inject
+    private VmwareDatacenterDao vmwareDatacenterDao;
+    @Inject
+    private BackupDao backupDao;
+
+    private VeeamClient getClient(final Long zoneId) {
+        try {
+            return new VeeamClient(VeeamUrl.valueIn(zoneId), 
VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId),
+                VeeamValidateSSLSecurity.valueIn(zoneId), 
VeeamApiRequestTimeout.valueIn(zoneId));
+        } catch (URISyntaxException e) {
+            throw new CloudRuntimeException("Failed to parse Veeam API URL: " 
+ e.getMessage());
+        } catch (NoSuchAlgorithmException | KeyManagementException e) {
+            LOG.error("Failed to build Veeam API client due to: ", e);
+        }
+        throw new CloudRuntimeException("Failed to build Veeam API client");
+    }
+
+    public List<BackupOffering> listBackupOfferings(final Long zoneId) {
+        List<BackupOffering> policies = new ArrayList<>();
+        for (final BackupOffering policy : getClient(zoneId).listJobs()) {
+            if (!policy.getName().contains(BACKUP_IDENTIFIER)) {
+                policies.add(policy);
+            }
+        }
+        return policies;
+    }
+
+    @Override
+    public boolean isBackupOffering(final Long zoneId, final String uuid) {
+        List<BackupOffering> policies = listBackupOfferings(zoneId);
+        if (CollectionUtils.isEmpty(policies)) {
+            return false;
+        }
+        for (final BackupOffering policy : policies) {
+            if (policy.getExternalId().equals(uuid)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private VmwareDatacenter findVmwareDatacenterForVM(final VirtualMachine 
vm) {
+        if (vm == null || vm.getHypervisorType() != 
Hypervisor.HypervisorType.VMware) {
+            throw new CloudRuntimeException("The Veeam backup provider is only 
applicable for VMware VMs");
+        }
+        final VmwareDatacenterZoneMap zoneMap = 
vmwareDatacenterZoneMapDao.findByZoneId(vm.getDataCenterId());
+        if (zoneMap == null) {
+            throw new CloudRuntimeException("Failed to find a mapped VMware 
datacenter for zone id:" + vm.getDataCenterId());
+        }
+        final VmwareDatacenter vmwareDatacenter = 
vmwareDatacenterDao.findById(zoneMap.getVmwareDcId());
+        if (vmwareDatacenter == null) {
+            throw new CloudRuntimeException("Failed to find a valid VMware 
datacenter mapped for zone id:" + vm.getDataCenterId());
+        }
+        return vmwareDatacenter;
+    }
+
+    public boolean addVMToBackupOffering(final BackupOffering policy, final 
VirtualMachine vm) {
+        final VmwareDatacenter vmwareDatacenter = 
findVmwareDatacenterForVM(vm);
+        return 
getClient(vm.getDataCenterId()).removeVMFromVeeamJob(policy.getExternalId(), 
vm.getInstanceName(), vmwareDatacenter.getVcenterHost());
+    }
+
+    private String getGuestBackupName(final String instanceName, final String 
uuid) {
+        return String.format("%s%s%s", instanceName, BACKUP_IDENTIFIER, uuid);
+    }
+
+    @Override
+    public boolean assignVMToBackupOffering(final VirtualMachine vm, final 
BackupOffering backupOffering) {
+        final VeeamClient client = getClient(vm.getDataCenterId());
+        final Job parentJob = client.listJob(backupOffering.getExternalId());
+        final String clonedJobName = getGuestBackupName(vm.getInstanceName(), 
vm.getUuid());
+        if (client.cloneVeeamJob(parentJob, clonedJobName)) {
+            for (BackupOffering job : client.listJobs()) {
+                if (job.getName().equals(clonedJobName)) {
+                    final Job clonedJob = client.listJob(job.getExternalId());
+                    if (clonedJob.getScheduleConfigured() && 
!clonedJob.getScheduleEnabled()) {
+                        client.toggleJobSchedule(clonedJob.getId());
+                    }
+                    final VmwareDatacenter vmwareDC = 
findVmwareDatacenterForVM(vm);
+                    if (client.addVMToVeeamJob(job.getExternalId(), 
vm.getInstanceName(), vmwareDC.getVcenterHost())) {
+                        ((VMInstanceVO) 
vm).setBackupExternalId(job.getExternalId());
+                        return true;
+                    }
+                }
+            }
+        } else {
+            LOG.error("Failed to clone pre-defined Veeam job (backup offering) 
for backup offering ID: " + backupOffering.getExternalId());
+        }
+        return false;
+    }
+
+    @Override
+    public boolean removeVMFromBackupOffering(final VirtualMachine vm) {
+        final VeeamClient client = getClient(vm.getDataCenterId());
+        final VmwareDatacenter vmwareDC = findVmwareDatacenterForVM(vm);
+        try {
+            if (!client.removeVMFromVeeamJob(vm.getBackupExternalId(), 
vm.getInstanceName(), vmwareDC.getVcenterHost())) {
+                LOG.warn("Failed to remove VM from Veeam Job id: " + 
vm.getBackupExternalId());
+            }
+        } catch (CloudRuntimeException e) {
+            LOG.debug("VM was removed from the job so could not remove again, 
trying to delete the veeam job now.", e);
+        }
+
+        final String clonedJobName = getGuestBackupName(vm.getInstanceName(), 
vm.getUuid());
+        if (!client.deleteJobAndBackup(clonedJobName)) {
+            LOG.warn("Failed to remove Veeam job and backup for job: " + 
clonedJobName);
+            throw new CloudRuntimeException("Failed to delete Veeam B&R job 
and backup, an operation may be in progress. Please try again after some 
time.");
+        }
+        for (final Backup backup: backupDao.listByVmId(null, vm.getId())) {
 
 Review comment:
   Can this also be moved to the BackupManagerImpl on successful operation?

----------------------------------------------------------------
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

Reply via email to