diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java index 96452d5a803..080f31a4531 100644 --- a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.backup; +import java.io.IOException; import java.net.URISyntaxException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; @@ -39,7 +40,7 @@ import org.apache.cloudstack.framework.config.Configurable; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; - +import org.apache.http.client.ClientProtocolException; import org.joda.time.DateTime; import com.cloud.utils.Pair; @@ -54,19 +55,19 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide public static final String BACKUP_IDENTIFIER = "-CSBKP-"; public ConfigKey BackrollUrlConfigKey = new ConfigKey<>("Advanced", String.class, - "backup.plugin.backroll.config.url", - "http://api.backup.demo.ccc:5050/api/v1", - "Url for backroll plugin.", true, ConfigKey.Scope.Zone); + "backup.plugin.backroll.config.url", + "http://api.backup.demo.ccc:5050/api/v1", + "Url for backroll plugin.", true, ConfigKey.Scope.Zone); public ConfigKey BackrollAppNameConfigKey = new ConfigKey<>("Advanced", String.class, - "backup.plugin.backroll.config.appname", - "backroll_api", - "App Name for backroll plugin.", true, ConfigKey.Scope.Zone); + "backup.plugin.backroll.config.appname", + "backroll_api", + "App Name for backroll plugin.", true, ConfigKey.Scope.Zone); public ConfigKey BackrollPasswordConfigKey = new ConfigKey<>("Advanced", String.class, - "backup.plugin.backroll.config.password", - "VviX8dALauSyYJMqVYJqf3UyZOpO3joS", - "Password for backroll plugin.", true, ConfigKey.Scope.Zone); + "backup.plugin.backroll.config.password", + "VviX8dALauSyYJMqVYJqf3UyZOpO3joS", + "Password for backroll plugin.", true, ConfigKey.Scope.Zone); private BackrollClient backrollClient; @@ -88,12 +89,12 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide @Override public List listBackupOfferings(Long zoneId) { logger.debug("Listing backup policies on backroll B&R Plugin"); - BackrollClient client = getClient(zoneId); - String urlToRequest = client.getBackupOfferingUrl(); - if (!StringUtils.isEmpty(urlToRequest)){ - return client.getBackupOfferings(urlToRequest); + try { + BackrollClient client = getClient(zoneId); + return client.getBackupOfferings(client.getBackupOfferingUrl()); // TODO Embed URL in method ? + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to list backup offerings for zone %s.", zoneId), e); } - return new ArrayList(); } @Override @@ -104,7 +105,8 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide @Override public boolean assignVMToBackupOffering(VirtualMachine vm, BackupOffering backupOffering) { - logger.info("Creating VM backup for VM {} from backup offering {}", vm.getInstanceName(), backupOffering.getName()); + logger.info("Creating VM backup for VM {} from backup offering {}", vm.getInstanceName(), + backupOffering.getName()); ((VMInstanceVO) vm).setBackupExternalId(backupOffering.getUuid()); return true; } @@ -112,8 +114,13 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide @Override public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) { logger.debug("Restoring vm {} from backup {} on the backroll Backup Provider", vm.getUuid(), backup.getUuid()); - boolean isSuccess = getClient(vm.getDataCenterId()).restoreVMFromBackup(vm.getUuid(), getBackupName(backup)); - return isSuccess; + try { + getClient(vm.getDataCenterId()).restoreVMFromBackup(vm.getUuid(), getBackupName(backup)); + } catch (Exception e) { + throw new CloudRuntimeException( + String.format("Failed to restore backup %s to VM %s.", backup.getName(), vm.getName()), e); + } + return true; } @Override @@ -124,7 +131,8 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide return metrics; } - List vmUuids = vms.stream().filter(Objects::nonNull).map(VirtualMachine::getUuid).collect(Collectors.toList()); + List vmUuids = vms.stream().filter(Objects::nonNull).map(VirtualMachine::getUuid) + .collect(Collectors.toList()); logger.debug("Get Backup Metrics for VMs: {}.", String.join(", ", vmUuids)); for (final VirtualMachine vm : vms) { @@ -132,10 +140,14 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide continue; } - Metric metric = getClient(zoneId).getVirtualMachineMetrics(vm.getUuid()); - logger.debug("Metrics for VM [uuid: {}, name: {}] is [backup size: {}, data size: {}].", vm.getUuid(), - vm.getInstanceName(), metric.getBackupSize(), metric.getDataSize()); - metrics.put(vm, metric); + try { + Metric metric = getClient(zoneId).getVirtualMachineMetrics(vm.getUuid()); + logger.debug("Metrics for VM [uuid: {}, name: {}] is [backup size: {}, data size: {}].", vm.getUuid(), + vm.getInstanceName(), metric.getBackupSize(), metric.getDataSize()); + metrics.put(vm, metric); + } catch (Exception e) { + logger.error("Failed to get backup metrics for VM {} due to {}.", vm.getName(), e); + } } return metrics; } @@ -144,28 +156,30 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide public boolean removeVMFromBackupOffering(VirtualMachine vm) { logger.info("Removing VM ID {} from Backrool backup offering ", vm.getUuid()); - boolean isAnyProblemWhileRemovingBackups = false; + boolean everythingIsOk = true; List backupsInCs = backupDao.listByVmId(null, vm.getId()); for (Backup backup : backupsInCs) { logger.debug("Trying to remove backup with id {}", backup.getId()); - if (getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup))) { + try { + getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup)); logger.info("Backup {} deleted in Backroll for virtual machine {}", backup.getId(), vm.getName()); - if (!backupDao.remove(backup.getId())){ - isAnyProblemWhileRemovingBackups = true; + if (!backupDao.remove(backup.getId())) { + everythingIsOk = false; } logger.info("Backup {} deleted in CS for virtual machine {}", backup.getId(), vm.getName()); - } else { - isAnyProblemWhileRemovingBackups = false; + } catch (Exception e) { + logger.error("Failed to remove backup {} for VM {}.", backup.getName(), vm.getName()); + everythingIsOk = false; } } - if (isAnyProblemWhileRemovingBackups) { + if (!everythingIsOk) { logger.info("Problems occured while removing some backups for virtual machine {}", vm.getName()); } - return isAnyProblemWhileRemovingBackups; + return everythingIsOk; } @Override @@ -176,10 +190,9 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide @Override public boolean takeBackup(VirtualMachine vm) { logger.info("Starting backup for VM ID {} on backroll provider", vm.getUuid()); - final BackrollClient client = getClient(vm.getDataCenterId()); - - String idBackupTask = client.startBackupJob(vm.getUuid()); - if (!StringUtils.isEmpty(idBackupTask)) { + try { + final BackrollClient client = getClient(vm.getDataCenterId()); + String idBackupTask = client.startBackupJob(vm.getUuid()); BackupVO backup = new BackupVO(); backup.setVmId(vm.getId()); backup.setExternalId(idBackupTask); @@ -192,22 +205,32 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide backup.setAccountId(vm.getAccountId()); backup.setDomainId(vm.getDomainId()); backup.setZoneId(vm.getDataCenterId()); - return backupDao.persist(backup) != null; + assert backupDao.persist(backup) != null; + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to take a backup of VM %s.", vm.getName()), e); } - return false; + return true; } @Override public void syncBackups(VirtualMachine vm, Backup.Metric metric) { logger.info("Starting sync backup for VM ID " + vm.getUuid() + " on backroll provider"); - final BackrollClient client = getClient(vm.getDataCenterId()); + final BackrollClient client; + try { + client = getClient(vm.getDataCenterId()); + } catch (Exception e) { + throw new CloudRuntimeException( + String.format("Failed to get Backroll client while syncing backups for VM %s.", vm.getName())); + } + List backupsInDb = backupDao.listByVmId(null, vm.getId()); for (Backup backup : backupsInDb) { - if (backup.getStatus().equals(Backup.Status.BackingUp)) { - BackrollTaskStatus response = client.checkBackupTaskStatus(backup.getExternalId()); - if (response != null) { + try { + if (backup.getStatus().equals(Backup.Status.BackingUp)) { + BackrollTaskStatus response = client.checkBackupTaskStatus(backup.getExternalId()); + logger.debug("backroll backup id: {}", backup.getExternalId()); logger.debug("backroll backup status: {}", response.getState()); @@ -231,7 +254,8 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide backupToUpdate.setStatus(Backup.Status.BackedUp); backupToUpdate.setExternalId(backup.getExternalId() + "," + response.getInfo()); - BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , response.getInfo()); + BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid(), + response.getInfo()); if (backupMetrics != null) { backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size backupToUpdate.setProtectedSize(backupMetrics.getSize()); // total size @@ -244,16 +268,19 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide logger.info("Backroll mise à jour enregistrée"); backupDao.remove(backup.getId()); } - } - } else if (backup.getStatus().equals(Backup.Status.BackedUp) && backup.getSize().equals(0L)) { - String backupId = backup.getExternalId().contains(",") ? backup.getExternalId().split(",")[1] : backup.getExternalId(); - BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , backupId); - if (backupMetrics != null) { + + } else if (backup.getStatus().equals(Backup.Status.BackedUp) && backup.getSize().equals(0L)) { + String backupId = backup.getExternalId().contains(",") ? backup.getExternalId().split(",")[1] + : backup.getExternalId(); + + BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid(), backupId); BackupVO backupToUpdate = ((BackupVO) backup); backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size backupToUpdate.setProtectedSize(backupMetrics.getSize()); // total size backupDao.persist(backupToUpdate); } + } catch (Exception e) { + logger.error("Failed to sync backup {}.", backup.getName()); } } @@ -264,9 +291,9 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide // insert new backroll backup in CS for (BackrollVmBackup backupInBackroll : backupsFromBackroll) { Backup backupToFind = backupsInDb.stream() - .filter(backupInDb -> backupInDb.getExternalId().contains(backupInBackroll.getName())) - .findAny() - .orElse(null); + .filter(backupInDb -> backupInDb.getExternalId().contains(backupInBackroll.getName())) + .findAny() + .orElse(null); if (backupToFind == null) { BackupVO backupToInsert = new BackupVO(); @@ -296,11 +323,12 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide // delete deleted backroll backup in CS backupsInDb = backupDao.listByVmId(null, vm.getId()); for (Backup backup : backupsInDb) { - String backupName = backup.getExternalId().contains(",") ? backup.getExternalId().split(",")[1] : backup.getExternalId(); + String backupName = backup.getExternalId().contains(",") ? backup.getExternalId().split(",")[1] + : backup.getExternalId(); BackrollVmBackup backupToFind = backupsFromBackroll.stream() - .filter(backupInBackroll -> backupInBackroll.getName().contains(backupName)) - .findAny() - .orElse(null); + .filter(backupInBackroll -> backupInBackroll.getName().contains(backupName)) + .findAny() + .orElse(null); if (backupToFind == null) { BackupVO backupToUpdate = ((BackupVO) backup); @@ -319,10 +347,10 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[]{ - BackrollUrlConfigKey, - BackrollAppNameConfigKey, - BackrollPasswordConfigKey + return new ConfigKey[] { + BackrollUrlConfigKey, + BackrollAppNameConfigKey, + BackrollPasswordConfigKey }; } @@ -330,21 +358,24 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide public boolean deleteBackup(Backup backup, boolean forced) { logger.info("backroll delete backup id: {}", backup.getExternalId()); if (backup.getStatus().equals(Backup.Status.BackingUp)) { - throw new CloudRuntimeException("You can't delete a backup while it still BackingUp"); + throw new CloudRuntimeException("You can't delete a backup while it still backing up."); } else { logger.debug("backroll - try delete backup"); VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId()); - if (backup.getStatus().equals(Backup.Status.Removed) || backup.getStatus().equals(Backup.Status.Failed)){ + if (backup.getStatus().equals(Backup.Status.Removed) || backup.getStatus().equals(Backup.Status.Failed)) { return deleteBackupInDb(backup); - } else { - if (getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup))) { - logger.debug("Backup deletion for backup {} complete on backroll side.", backup.getUuid()); - return deleteBackupInDb(backup); - } } + + try { + getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup)); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to delete backup %s", backup.getName())); + } + + logger.debug("Backup deletion for backup {} complete on backroll side.", backup.getUuid()); + return deleteBackupInDb(backup); } - return false; } private boolean deleteBackupInDb(Backup backup) { @@ -357,12 +388,14 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide return false; } - protected BackrollClient getClient(final Long zoneId) { + protected BackrollClient getClient(final Long zoneId) throws ClientProtocolException, IOException { logger.debug("Backroll Provider GetClient with zone id {}", zoneId); try { if (backrollClient == null) { logger.debug("backroll client null - instanciation of new one "); - backrollClient = new BackrollClient(BackrollUrlConfigKey.valueIn(zoneId), BackrollAppNameConfigKey.valueIn(zoneId), BackrollPasswordConfigKey.valueIn(zoneId), true, 300, 600); + backrollClient = new BackrollClient(BackrollUrlConfigKey.valueIn(zoneId), + BackrollAppNameConfigKey.valueIn(zoneId), BackrollPasswordConfigKey.valueIn(zoneId), true, 300, + 600); } return backrollClient; } catch (URISyntaxException e) { @@ -378,8 +411,10 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide } @Override - public Pair restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid, Pair vmNameAndState) { - logger.debug("Restoring volume {} from backup {} on the Backroll Backup Provider", volumeUuid, backup.getUuid()); + public Pair restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, + String dataStoreUuid, Pair vmNameAndState) { + logger.debug("Restoring volume {} from backup {} on the Backroll Backup Provider", volumeUuid, + backup.getUuid()); throw new CloudRuntimeException("Backroll plugin does not support this feature"); } } diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java index e7021d4276b..cfdcf566646 100644 --- a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java @@ -62,6 +62,7 @@ import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.ParseException; +import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpDelete; @@ -106,7 +107,8 @@ public class BackrollClient { public BackrollClient(final String url, final String appname, final String password, final boolean validateCertificate, final int timeout, final int restoreTimeout) - throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { + throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException, ClientProtocolException, + IOException { this.apiURI = new URI(url); this.restoreTimeout = restoreTimeout; this.appname = appname; @@ -152,105 +154,79 @@ public class BackrollClient { return null; } - public String getBackupOfferingUrl() { + public String getBackupOfferingUrl() + throws ClientProtocolException, IOException, ParseException, NotOkBodyException { logger.info("Trying to list backroll backup policies"); loginIfAuthenticationFailed(); - try { - return this.parse(okBody(get("/backup_policies"))).location.replace("/api/v1", - ""); - } catch (final Exception e) { - logger.error("Failed to list Backroll jobs due to: {}", e.getMessage()); - } - return null; + return this.parse(okBody(get("/backup_policies"))).location.replace("/api/v1", + ""); } - public List getBackupOfferings(String idTask) { + public List getBackupOfferings(String idTask) + throws ParseException, NotOkBodyException, ClientProtocolException, IOException, InterruptedException { logger.info("Trying to list backroll backup policies"); loginIfAuthenticationFailed(); - try { - BackupPoliciesResponse backupPoliciesResponse = waitGet(idTask); + BackupPoliciesResponse backupPoliciesResponse = waitGet(idTask); - final List policies = new ArrayList<>(); - for (final BackrollBackupPolicyResponse policy : backupPoliciesResponse.backupPolicies) { - policies.add(new BackrollOffering(policy.name, policy.id)); - } - return policies; - } catch (final IOException | InterruptedException e) { - logger.error("Failed to list Backroll jobs due to: {}", e.getMessage()); + final List policies = new ArrayList<>(); + for (final BackrollBackupPolicyResponse policy : backupPoliciesResponse.backupPolicies) { + policies.add(new BackrollOffering(policy.name, policy.id)); } - return new ArrayList(); + return policies; } - public boolean restoreVMFromBackup(final String vmId, final String backupName) { + public void restoreVMFromBackup(final String vmId, final String backupName) throws Exception { logger.info("Start restore backup with backroll with backup {} for vm {}", backupName, vmId); loginIfAuthenticationFailed(); - try { - JSONObject jsonBody = new JSONObject(); - try { - jsonBody.put("virtual_machine_id", vmId); - jsonBody.put("backup_name", backupName); - jsonBody.put("storage", ""); - jsonBody.put("mode", "single"); + JSONObject jsonBody = new JSONObject(); + jsonBody.put("virtual_machine_id", vmId); + jsonBody.put("backup_name", backupName); + jsonBody.put("storage", ""); + jsonBody.put("mode", "single"); - } catch (JSONException e) { - logger.error("Backroll Error: {}", e.getMessage()); - } + String urlToRequest = this + .parse(okBody( + post(String.format("/tasks/restore/%s", vmId), jsonBody))).location + .replace("/api/v1", ""); - String urlToRequest = this - .parse(okBody( - post(String.format("/tasks/restore/%s", vmId), jsonBody))).location - .replace("/api/v1", ""); + TaskStateResponse response = waitGet(urlToRequest); + logger.debug("RESTORE {}", response.state); - TaskStateResponse response = waitGet(urlToRequest); - logger.debug("RESTORE {}", response.state); - return response.state.equals(TaskState.SUCCESS); - } catch (final NotOkBodyException e) { - return false; - } catch (final IOException | InterruptedException e) { - logger.error("Ouch! Failed to restore VM with Backroll due to: {}", e.getMessage()); - throw new CloudRuntimeException("Ouch! Failed to restore VM with Backroll due to: {}" + e.getMessage()); + if (!response.state.equals(TaskState.SUCCESS)) { + throw new Exception("Backroll task failed."); } } - public BackrollTaskStatus checkBackupTaskStatus(String taskId) { + public BackrollTaskStatus checkBackupTaskStatus(String taskId) + throws ParseException, IOException, NotOkBodyException { logger.info("Trying to get backup status for Backroll task: {}", taskId); loginIfAuthenticationFailed(); - try { - BackrollTaskStatus status = new BackrollTaskStatus(); + BackrollTaskStatus status = new BackrollTaskStatus(); - String body = okBody(get("/status/" + taskId)); + String body = okBody(get("/status/" + taskId)); - if (body.contains(TaskState.FAILURE) || body.contains(TaskState.PENDING)) { - BackrollBackupStatusResponse backupStatusRequestResponse = parse(body); - status.setState(backupStatusRequestResponse.state); - } else { - BackrollBackupStatusSuccessResponse backupStatusSuccessRequestResponse = parse(body); - status.setState(backupStatusSuccessRequestResponse.state); - status.setInfo(backupStatusSuccessRequestResponse.info); - } - - return status; - - } catch (final NotOkBodyException e) { - // throw new CloudRuntimeException("Failed to retrieve backups status for this - // VM via Backroll"); - logger.error("Failed to retrieve backups status for this VM via Backroll"); - - } catch (final IOException e) { - logger.error("Failed to check backups status due to: {}", e.getMessage()); + if (body.contains(TaskState.FAILURE) || body.contains(TaskState.PENDING)) { + BackrollBackupStatusResponse backupStatusRequestResponse = parse(body); + status.setState(backupStatusRequestResponse.state); + } else { + BackrollBackupStatusSuccessResponse backupStatusSuccessRequestResponse = parse(body); + status.setState(backupStatusSuccessRequestResponse.state); + status.setInfo(backupStatusSuccessRequestResponse.info); } - return null; + + return status; } - public boolean deleteBackup(final String vmId, final String backupName) { + public boolean deleteBackup(final String vmId, final String backupName) + throws ClientProtocolException, IOException { logger.info("Trying to delete backup {} for vm {} using Backroll", vmId, backupName); loginIfAuthenticationFailed(); @@ -271,7 +247,7 @@ public class BackrollClient { return false; } - public Metric getVirtualMachineMetrics(final String vmId) { + public Metric getVirtualMachineMetrics(final String vmId) throws ClientProtocolException, IOException { logger.info("Trying to retrieve virtual machine metric from Backroll for vm {}", vmId); loginIfAuthenticationFailed(); @@ -286,7 +262,7 @@ public class BackrollClient { BackrollVmMetricsResponse vmMetricsResponse = waitGet(urlToRequest); - if (vmMetricsResponse != null && vmMetricsResponse.state.equals(TaskState.SUCCESS)) { + if (vmMetricsResponse.state.equals(TaskState.SUCCESS)) { logger.debug("SUCCESS ok"); CacheStats stats = null; try { @@ -305,28 +281,23 @@ public class BackrollClient { return metric; } - public BackrollBackupMetrics getBackupMetrics(String vmId, String backupId) { + public BackrollBackupMetrics getBackupMetrics(String vmId, String backupId) throws JsonMappingException, + JsonProcessingException, ParseException, IOException, NotOkBodyException, InterruptedException { logger.info("Trying to get backup metrics for VM: {}, and backup: {}", vmId, backupId); loginIfAuthenticationFailed(); - try { + String urlToRequest = this.parse(okBody(get( + String.format("/virtualmachines/%s/backups/%s", vmId, backupId)))).location.replace("/api/v1", ""); + logger.debug(urlToRequest); - String urlToRequest = this.parse(okBody(get( - String.format("/virtualmachines/%s/backups/%s", vmId, backupId)))).location.replace("/api/v1", ""); - logger.debug(urlToRequest); - - BackrollBackupMetricsResponse metrics = waitGet(urlToRequest); - if (metrics.info != null) { - return new BackrollBackupMetrics(Long.parseLong(metrics.info.originalSize), - Long.parseLong(metrics.info.deduplicatedSize)); - } - } catch (final NotOkBodyException e) { - throw new CloudRuntimeException("Failed to retrieve backups status for this VM via Backroll"); - } catch (final IOException | InterruptedException e) { - logger.error("Failed to check backups status due to: {}", e.getMessage()); + BackrollBackupMetricsResponse metrics = waitGet(urlToRequest); + if (metrics.info != null) { + return new BackrollBackupMetrics(Long.parseLong(metrics.info.originalSize), + Long.parseLong(metrics.info.deduplicatedSize)); } - return null; + + throw new CloudRuntimeException("Backup %s of VM %s has null info in its metrics."); } public List getAllBackupsfromVirtualMachine(String vmId) { @@ -380,7 +351,8 @@ public class BackrollClient { final HttpResponse response = httpClient.execute(request); - logger.debug("Response received in POST request with body {} is: {} for URL {}.", xml, response.toString(), url); + logger.debug("Response received in POST request with body {} is: {} for URL {}.", xml, response.toString(), + url); return response; } @@ -411,7 +383,17 @@ public class BackrollClient { || response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED; } - private class NotOkBodyException extends Exception { + public class NotOkBodyException extends Exception { + private HttpResponse response; + + public NotOkBodyException(HttpResponse response) { + super(String.format("HTTP response is not ok: %s", response)); + this.response = response; + } + + public HttpResponse getResponse() { + return this.response; + } } private String okBody(final HttpResponse response) @@ -426,7 +408,7 @@ public class BackrollClient { EntityUtils.consumeQuietly(bodyEntity); } default: - throw new NotOkBodyException(); + throw new NotOkBodyException(response); } } @@ -436,24 +418,23 @@ public class BackrollClient { }); } - private T waitGet(String url) - throws IOException, InterruptedException { - // int threshold = 30; // 5 minutes - int maxAttempts = 12; // 2 minutes + private T waitGet(String url) throws InterruptedException, ParseException, IOException, NotOkBodyException { + int waitingTimeMinutes = 2; + int refreshingPeriodSeconds = 10; - for (int attempt = 1; attempt <= maxAttempts; attempt++) { - try { - String body = okBody(get(url)); - if (!body.contains(TaskState.PENDING)) { - return parse(body); - } - } catch (final NotOkBodyException e) { - throw new CloudRuntimeException("An error occured with Backroll"); + int waitMillis = waitingTimeMinutes * 60000; + + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() - start < waitMillis) { + String body = okBody(get(url)); + if (!body.contains(TaskState.PENDING)) { + return parse(body); + } else { + TimeUnit.SECONDS + .sleep(refreshingPeriodSeconds); } - TimeUnit.SECONDS.sleep(10); } - - return null; + throw new CloudRuntimeException(String.format("Unable to fetch %s.")); } private boolean isAuthenticated() { @@ -468,13 +449,13 @@ public class BackrollClient { return result; } - private void loginIfAuthenticationFailed() { + private void loginIfAuthenticationFailed() throws ClientProtocolException, IOException { if (!isAuthenticated()) { login(appname, password); } } - private void login(final String appname, final String appsecret) { + private void login(final String appname, final String appsecret) throws ClientProtocolException, IOException { logger.debug("Backroll client - start login"); final HttpPost request = new HttpPost(apiURI.toString() + "/login"); @@ -483,60 +464,48 @@ public class BackrollClient { JSONObject jsonBody = new JSONObject(); StringEntity params; + jsonBody.put("app_id", appname); + jsonBody.put("app_secret", appsecret); + params = new StringEntity(jsonBody.toString()); + request.setEntity(params); + + final HttpResponse response = httpClient.execute(request); try { - jsonBody.put("app_id", appname); - jsonBody.put("app_secret", appsecret); - params = new StringEntity(jsonBody.toString()); - request.setEntity(params); + LoginApiResponse loginResponse = parse(okBody(response)); + backrollToken = loginResponse.accessToken; + logger.debug("Backroll client - Token : {}", backrollToken); - final HttpResponse response = httpClient.execute(request); - try { - LoginApiResponse loginResponse = parse(okBody(response)); - backrollToken = loginResponse.accessToken; - logger.debug("Backroll client - Token : {}", backrollToken); - - if (StringUtils.isEmpty(loginResponse.accessToken)) { - throw new CloudRuntimeException("Backroll token is not available to perform API requests"); - } - } catch (final NotOkBodyException e) { - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { - throw new CloudRuntimeException( - "Failed to create and authenticate Backroll client, please check the settings."); - } else { - throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, - "Backroll API call unauthorized, please ask your administrator to fix integration issues."); - } + if (StringUtils.isEmpty(loginResponse.accessToken)) { + throw new CloudRuntimeException("Backroll token is not available to perform API requests"); + } + } catch (final NotOkBodyException e) { + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { + throw new CloudRuntimeException( + "Failed to create and authenticate Backroll client, please check the settings."); + } else { + throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, + "Backroll API call unauthorized, please ask your administrator to fix integration issues."); } - } catch (final IOException e) { - throw new CloudRuntimeException("Failed to authenticate Backroll API service due to:" + e.getMessage()); - } catch (JSONException e) { - e.printStackTrace(); } + logger.debug("Backroll client - end login"); } - private List getBackrollBackups(final String vmId) { - try { - logger.info("start to list Backroll backups for vm {}", vmId); - String urlToRequest = this - .parse(okBody(get("/virtualmachines/" + vmId + "/backups"))).location - .replace("/api/v1", ""); - logger.debug(urlToRequest); - BackrollBackupsFromVMResponse backrollBackupsFromVMResponse = waitGet(urlToRequest); + private List getBackrollBackups(final String vmId) throws JsonMappingException, + JsonProcessingException, ParseException, IOException, NotOkBodyException, InterruptedException { - final List backups = new ArrayList<>(); - for (final BackrollArchiveResponse archive : backrollBackupsFromVMResponse.archives.archives) { - backups.add(new BackrollBackup(archive.name)); - logger.debug(archive.name); - } - return backups; - } catch (final NotOkBodyException e) { - throw new CloudRuntimeException("Failed to retrieve backups for this VM via Backroll"); - } catch (final IOException e) { - logger.error("Failed to list backup form vm with Backroll due to: {}", e); - } catch (InterruptedException e) { - logger.error("Backroll Error: {}", e); + logger.info("start to list Backroll backups for vm {}", vmId); + String urlToRequest = this + .parse(okBody(get("/virtualmachines/" + vmId + "/backups"))).location + .replace("/api/v1", ""); + logger.debug(urlToRequest); + BackrollBackupsFromVMResponse backrollBackupsFromVMResponse = waitGet(urlToRequest); + + final List backups = new ArrayList<>(); + for (final BackrollArchiveResponse archive : backrollBackupsFromVMResponse.archives.archives) { + backups.add(new BackrollBackup(archive.name)); + logger.debug(archive.name); } - return new ArrayList(); + return backups; } }