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..a245a3f8be6 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.ParseException; import org.joda.time.DateTime; import com.cloud.utils.Pair; @@ -60,7 +61,7 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide public ConfigKey BackrollAppNameConfigKey = new ConfigKey<>("Advanced", String.class, "backup.plugin.backroll.config.appname", - "backroll_api", + "backroll-api", "App Name for backroll plugin.", true, ConfigKey.Scope.Zone); public ConfigKey BackrollPasswordConfigKey = new ConfigKey<>("Advanced", String.class, @@ -89,9 +90,14 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide 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{ + String urlToRequest = client.getBackupOfferingUrl(); + if (!StringUtils.isEmpty(urlToRequest)){ + return client.getBackupOfferings(urlToRequest); + + } + } catch (KeyManagementException | ParseException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to load backup offerings"); } return new ArrayList(); } @@ -112,7 +118,12 @@ 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)); + boolean isSuccess; + try { + isSuccess = getClient(vm.getDataCenterId()).restoreVMFromBackup(vm.getUuid(), getBackupName(backup)); + } catch (KeyManagementException | ParseException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to restore VM from Backrup"); + } return isSuccess; } @@ -132,7 +143,12 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide continue; } - Metric metric = getClient(zoneId).getVirtualMachineMetrics(vm.getUuid()); + Metric metric; + try { + metric = getClient(zoneId).getVirtualMachineMetrics(vm.getUuid()); + } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to retrieve backup metrics"); + } logger.debug("Metrics for VM [uuid: {}, name: {}] is [backup size: {}, data size: {}].", vm.getUuid(), vm.getInstanceName(), metric.getBackupSize(), metric.getDataSize()); metrics.put(vm, metric); @@ -151,14 +167,18 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide for (Backup backup : backupsInCs) { logger.debug("Trying to remove backup with id {}", backup.getId()); - if (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; + try { + if (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; + } + logger.info("Backup {} deleted in CS for virtual machine {}", backup.getId(), vm.getName()); + } else { + isAnyProblemWhileRemovingBackups = false; } - logger.info("Backup {} deleted in CS for virtual machine {}", backup.getId(), vm.getName()); - } else { - isAnyProblemWhileRemovingBackups = false; + } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to remove VM from backup offering"); } } @@ -178,7 +198,12 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide logger.info("Starting backup for VM ID {} on backroll provider", vm.getUuid()); final BackrollClient client = getClient(vm.getDataCenterId()); - String idBackupTask = client.startBackupJob(vm.getUuid()); + String idBackupTask; + try { + idBackupTask = client.startBackupJob(vm.getUuid()); + } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to take backup"); + } if (!StringUtils.isEmpty(idBackupTask)) { BackupVO backup = new BackupVO(); backup.setVmId(vm.getId()); @@ -206,7 +231,13 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide for (Backup backup : backupsInDb) { if (backup.getStatus().equals(Backup.Status.BackingUp)) { - BackrollTaskStatus response = client.checkBackupTaskStatus(backup.getExternalId()); + BackrollTaskStatus response; + try { + response = client.checkBackupTaskStatus(backup.getExternalId()); + } catch (KeyManagementException | ParseException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to sync backups"); + } + if (response != null) { logger.debug("backroll backup id: {}", backup.getExternalId()); logger.debug("backroll backup status: {}", response.getState()); @@ -231,7 +262,13 @@ 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 = null; + try { + backupMetrics = client.getBackupMetrics(vm.getUuid() , response.getInfo()); + } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to get backup metrics"); + } + if (backupMetrics != null) { backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size backupToUpdate.setProtectedSize(backupMetrics.getSize()); // total size @@ -247,7 +284,13 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide } } 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); + BackrollBackupMetrics backupMetrics; + try { + backupMetrics = client.getBackupMetrics(vm.getUuid() , backupId); + } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to get backup metrics"); + } + if (backupMetrics != null) { BackupVO backupToUpdate = ((BackupVO) backup); backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size @@ -338,9 +381,13 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide 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 { + if (getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup))) { + logger.debug("Backup deletion for backup {} complete on backroll side.", backup.getUuid()); + return deleteBackupInDb(backup); + } + } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { + throw new CloudRuntimeException("Failed to delete backup"); } } } 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..345777ff06a 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,8 +62,8 @@ 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.HttpClient; import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; @@ -71,6 +71,7 @@ import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; @@ -93,15 +94,15 @@ public class BackrollClient { private Logger logger = LogManager.getLogger(BackrollClient.class); - private int restoreTimeout; - private final URI apiURI; - private final HttpClient httpClient; - private String backrollToken = null; private String appname = null; private String password = null; + private boolean validateCertificate = false; + private RequestConfig config = null; + + private int restoreTimeout; public BackrollClient(final String url, final String appname, final String password, final boolean validateCertificate, final int timeout, @@ -112,83 +113,92 @@ public class BackrollClient { this.appname = appname; this.password = password; - final RequestConfig config = RequestConfig.custom() - .setConnectTimeout(timeout * 1000) - .setConnectionRequestTimeout(timeout * 1000) - .setSocketTimeout(timeout * 1000) + this.config = RequestConfig.custom() + .setConnectTimeout(timeout * 1000) + .setConnectionRequestTimeout(timeout * 1000) + .setSocketTimeout(timeout * 1000) + .build(); + } + + private CloseableHttpClient createHttpClient() throws KeyManagementException, NoSuchAlgorithmException { + if(!validateCertificate) { + SSLContext sslContext = SSLUtils.getSSLContext(); + sslContext.init(null, new X509TrustManager[] { new TrustAllManager() }, new SecureRandom()); + final SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + return HttpClientBuilder.create() + .setDefaultRequestConfig(config) + .setSSLSocketFactory(factory) .build(); - - if (!validateCertificate) { - final SSLContext sslcontext = SSLUtils.getSSLContext(); - sslcontext.init(null, new X509TrustManager[] { new TrustAllManager() }, new SecureRandom()); - final SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, - NoopHostnameVerifier.INSTANCE); - this.httpClient = HttpClientBuilder.create() - .setDefaultRequestConfig(config) - .setSSLSocketFactory(factory) - .build(); } else { - this.httpClient = HttpClientBuilder.create() - .setDefaultRequestConfig(config) - .build(); - } - - if (StringUtils.isEmpty(backrollToken) || !isAuthenticated()) { - login(appname, password); + return HttpClientBuilder.create() + .setDefaultRequestConfig(config) + .build(); } } - public String startBackupJob(final String jobId) { + private void closeConnection(CloseableHttpResponse closeableHttpResponse) throws IOException { + closeableHttpResponse.close(); + } + + public String startBackupJob(final String jobId) throws KeyManagementException, NoSuchAlgorithmException, IOException { logger.info("Trying to start backup for Backroll job: {}", jobId); + String backupJob = ""; + + loginIfAuthenticationFailed(); try { - loginIfAuthenticationFailed(); - return this.parse(okBody( - post(String.format("/tasks/singlebackup/%s", jobId), null))).location - .replace("/api/v1/status/", ""); + CloseableHttpResponse response = post(String.format("/tasks/singlebackup/%s", jobId), null); + String result = okBody(response); + BackrollTaskRequestResponse requestResponse = parse(result); + response.close(); + backupJob = requestResponse.location.replace("/api/v1/status/", ""); } catch (final Exception e) { logger.error("Failed to start Backroll backup job due to: {}", e.getMessage()); } - return null; + return StringUtils.isEmpty(backupJob) ? null : backupJob; } - public String getBackupOfferingUrl() { + public String getBackupOfferingUrl() throws KeyManagementException, NoSuchAlgorithmException, IOException { logger.info("Trying to list backroll backup policies"); loginIfAuthenticationFailed(); + String url = ""; try { - return this.parse(okBody(get("/backup_policies"))).location.replace("/api/v1", - ""); + CloseableHttpResponse response = get("/backup_policies"); + String result = okBody(response); + BackrollTaskRequestResponse requestResponse = parse(result); + response.close(); + url = requestResponse.location.replace("/api/v1", ""); } catch (final Exception e) { logger.error("Failed to list Backroll jobs due to: {}", e.getMessage()); } - return null; + return StringUtils.isEmpty(url) ? null : url; } - public List getBackupOfferings(String idTask) { + public List getBackupOfferings(String idTask) throws KeyManagementException, ParseException, NoSuchAlgorithmException, IOException { logger.info("Trying to list backroll backup policies"); loginIfAuthenticationFailed(); + final List policies = new ArrayList<>(); try { 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()); } - return new ArrayList(); + return policies; } - public boolean restoreVMFromBackup(final String vmId, final String backupName) { + public boolean restoreVMFromBackup(final String vmId, final String backupName) throws KeyManagementException, ParseException, NoSuchAlgorithmException, IOException { logger.info("Start restore backup with backroll with backup {} for vm {}", backupName, vmId); loginIfAuthenticationFailed(); + boolean isRestoreOk = false; try { JSONObject jsonBody = new JSONObject(); @@ -202,29 +212,31 @@ public class BackrollClient { logger.error("Backroll Error: {}", e.getMessage()); } - 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); - return response.state.equals(TaskState.SUCCESS); + CloseableHttpResponse response = post(String.format("/tasks/restore/%s", vmId), jsonBody); + String result = okBody(response); + BackrollTaskRequestResponse requestResponse = parse(result); + response.close(); + String urlToRequest = requestResponse.location.replace("/api/v1", ""); + TaskStateResponse taskResponse = waitGet(urlToRequest); + logger.debug("RESTORE {}", taskResponse.state); + isRestoreOk = taskResponse.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()); } + return isRestoreOk; } - public BackrollTaskStatus checkBackupTaskStatus(String taskId) { + public BackrollTaskStatus checkBackupTaskStatus(String taskId) throws KeyManagementException, ParseException, NoSuchAlgorithmException, IOException { logger.info("Trying to get backup status for Backroll task: {}", taskId); loginIfAuthenticationFailed(); + BackrollTaskStatus status = new BackrollTaskStatus(); + try { - BackrollTaskStatus status = new BackrollTaskStatus(); String body = okBody(get("/status/" + taskId)); @@ -237,8 +249,6 @@ public class BackrollClient { status.setInfo(backupStatusSuccessRequestResponse.info); } - return status; - } catch (final NotOkBodyException e) { // throw new CloudRuntimeException("Failed to retrieve backups status for this // VM via Backroll"); @@ -247,31 +257,37 @@ public class BackrollClient { } catch (final IOException e) { logger.error("Failed to check backups status due to: {}", e.getMessage()); } - return null; + return StringUtils.isEmpty(status.getState()) ? null : status; } - public boolean deleteBackup(final String vmId, final String backupName) { + public boolean deleteBackup(final String vmId, final String backupName) throws KeyManagementException, NoSuchAlgorithmException, IOException { logger.info("Trying to delete backup {} for vm {} using Backroll", vmId, backupName); loginIfAuthenticationFailed(); + boolean isBackupDeleted = false; + try { - String urlToRequest = this.parse(okBody(delete( - String.format("/virtualmachines/%s/backups/%s", vmId, backupName)))).location - .replace("/api/v1", ""); + + CloseableHttpResponse response = delete(String.format("/virtualmachines/%s/backups/%s", vmId, backupName)); + String result = okBody(response); + BackrollTaskRequestResponse requestResponse = parse(result); + response.close(); + String urlToRequest = requestResponse.location.replace("/api/v1", ""); BackrollBackupsFromVMResponse backrollBackupsFromVMResponse = waitGet(urlToRequest); logger.debug(backrollBackupsFromVMResponse.state); - return backrollBackupsFromVMResponse.state.equals(TaskState.SUCCESS); + isBackupDeleted = backrollBackupsFromVMResponse.state.equals(TaskState.SUCCESS); } catch (final NotOkBodyException e) { - return false; + isBackupDeleted = false; } catch (final Exception e) { + isBackupDeleted = false; logger.error("Failed to delete backup using Backroll due to: {}", e.getMessage()); } - return false; + return isBackupDeleted; } - public Metric getVirtualMachineMetrics(final String vmId) { + public Metric getVirtualMachineMetrics(final String vmId) throws KeyManagementException, NoSuchAlgorithmException, IOException { logger.info("Trying to retrieve virtual machine metric from Backroll for vm {}", vmId); loginIfAuthenticationFailed(); @@ -280,9 +296,11 @@ public class BackrollClient { try { - String urlToRequest = this.parse(okBody( - get(String.format("/virtualmachines/%s/repository", vmId)))).location.replace("/api/v1", ""); - logger.debug(urlToRequest); + CloseableHttpResponse response = get(String.format("/virtualmachines/%s/repository", vmId)); + String result = okBody(response); + BackrollTaskRequestResponse requestResponse = parse(result); + response.close(); + String urlToRequest = requestResponse.location.replace("/api/v1", ""); BackrollVmMetricsResponse vmMetricsResponse = waitGet(urlToRequest); @@ -295,7 +313,7 @@ public class BackrollClient { } if (stats != null) { long size = Long.parseLong(stats.totalSize); - return new Metric(size, size); + metric = new Metric(size, size); } } } catch (final Exception e) { @@ -305,28 +323,34 @@ public class BackrollClient { return metric; } - public BackrollBackupMetrics getBackupMetrics(String vmId, String backupId) { + public BackrollBackupMetrics getBackupMetrics(String vmId, String backupId) throws KeyManagementException, NoSuchAlgorithmException, IOException { logger.info("Trying to get backup metrics for VM: {}, and backup: {}", vmId, backupId); loginIfAuthenticationFailed(); + BackrollBackupMetrics metrics = null; + try { - String urlToRequest = this.parse(okBody(get( - String.format("/virtualmachines/%s/backups/%s", vmId, backupId)))).location.replace("/api/v1", ""); + CloseableHttpResponse response = get(String.format("/virtualmachines/%s/backups/%s", vmId, backupId)); + String result = okBody(response); + BackrollTaskRequestResponse requestResponse = parse(result); + response.close(); + String urlToRequest = requestResponse.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)); + BackrollBackupMetricsResponse metricsResponse = waitGet(urlToRequest); + if (metricsResponse.info != null) { + metrics = new BackrollBackupMetrics(Long.parseLong(metricsResponse.info.originalSize), + Long.parseLong(metricsResponse.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()); } - return null; + return metrics; } public List getAllBackupsfromVirtualMachine(String vmId) { @@ -336,17 +360,19 @@ public class BackrollClient { try { - String urlToRequest = this - .parse(okBody( - get(String.format("/virtualmachines/%s/backups", vmId)))).location - .replace("/api/v1", ""); + CloseableHttpResponse response = get(String.format("/virtualmachines/%s/backups", vmId)); + String result = okBody(response); + BackrollTaskRequestResponse requestResponse = parse(result); + response.close(); + String urlToRequest = requestResponse.location.replace("/api/v1", ""); + logger.debug(urlToRequest); - VirtualMachineBackupsResponse response = waitGet(urlToRequest); + VirtualMachineBackupsResponse virtualMachineBackupsResponse = waitGet(urlToRequest); - if (response.state.equals(TaskState.SUCCESS)) { - if (response.info.archives.size() > 0) { - for (BackupInfos infos : response.info.archives) { + if (virtualMachineBackupsResponse.state.equals(TaskState.SUCCESS)) { + if (virtualMachineBackupsResponse.info.archives.size() > 0) { + for (BackupInfos infos : virtualMachineBackupsResponse.info.archives) { var dateStart = new DateTime(infos.start); backups.add(new BackrollVmBackup(infos.id, infos.name, dateStart.toDate())); } @@ -356,11 +382,12 @@ public class BackrollClient { } catch (Exception e) { e.printStackTrace(); } - return backups; } - private HttpResponse post(final String path, final JSONObject json) throws IOException { + private CloseableHttpResponse post(final String path, final JSONObject json) throws IOException, KeyManagementException, NoSuchAlgorithmException { + CloseableHttpClient httpClient = createHttpClient(); + String xml = null; StringEntity params = null; if (json != null) { @@ -378,30 +405,35 @@ public class BackrollClient { request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + backrollToken); request.setHeader("Content-type", "application/json"); - final HttpResponse response = httpClient.execute(request); + final CloseableHttpResponse response = httpClient.execute(request); logger.debug("Response received in POST request with body {} is: {} for URL {}.", xml, response.toString(), url); return response; } - protected HttpResponse get(final String path) throws IOException { + protected CloseableHttpResponse get(String path) throws IOException, KeyManagementException, NoSuchAlgorithmException { + CloseableHttpClient httpClient = createHttpClient(); + String url = apiURI.toString() + path; logger.debug("Backroll URL {}", url); - final HttpGet request = new HttpGet(url); + + HttpGet request = new HttpGet(url); request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + backrollToken); request.setHeader("Content-type", "application/json"); - final HttpResponse response = httpClient.execute(request); + CloseableHttpResponse response = httpClient.execute(request); logger.debug("Response received in GET request is: {} for URL: {}.", response.toString(), url); return response; } - protected HttpResponse delete(final String path) throws IOException { + protected CloseableHttpResponse delete(String path) throws IOException, KeyManagementException, NoSuchAlgorithmException { + CloseableHttpClient httpClient = createHttpClient(); + String url = apiURI.toString() + path; final HttpDelete request = new HttpDelete(url); request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + backrollToken); request.setHeader("Content-type", "application/json"); - final HttpResponse response = httpClient.execute(request); + final CloseableHttpResponse response = httpClient.execute(request); logger.debug("Response received in GET request is: {} for URL: {}.", response.toString(), url); return response; } @@ -414,18 +446,23 @@ public class BackrollClient { private class NotOkBodyException extends Exception { } - private String okBody(final HttpResponse response) + private String okBody(final CloseableHttpResponse response) throws ParseException, IOException, NotOkBodyException { + String result = ""; switch (response.getStatusLine().getStatusCode()) { case HttpStatus.SC_OK: case HttpStatus.SC_ACCEPTED: HttpEntity bodyEntity = response.getEntity(); try { - return EntityUtils.toString(bodyEntity); + result = EntityUtils.toString(bodyEntity); + EntityUtils.consumeQuietly(bodyEntity); + closeConnection(response); + return result; } finally { EntityUtils.consumeQuietly(bodyEntity); } default: + closeConnection(response); throw new NotOkBodyException(); } } @@ -437,7 +474,7 @@ public class BackrollClient { } private T waitGet(String url) - throws IOException, InterruptedException { + throws IOException, InterruptedException, KeyManagementException, ParseException, NoSuchAlgorithmException { // int threshold = 30; // 5 minutes int maxAttempts = 12; // 2 minutes @@ -456,28 +493,90 @@ public class BackrollClient { return null; } - private boolean isAuthenticated() { + private boolean isAuthenticated() throws KeyManagementException, NoSuchAlgorithmException { boolean result = false; + + if(StringUtils.isEmpty(backrollToken)) { + return result; + } + try { - final HttpResponse response = post("/auth", null); + CloseableHttpResponse response = post("/auth", null); result = isResponseAuthorized(response); EntityUtils.consumeQuietly(response.getEntity()); + closeConnection(response); } catch (IOException e) { logger.error("Failed to authenticate to Backroll due to: {}", e.getMessage()); } return result; } - private void loginIfAuthenticationFailed() { + private void loginIfAuthenticationFailed() throws KeyManagementException, NoSuchAlgorithmException, IOException { if (!isAuthenticated()) { login(appname, password); } } - private void login(final String appname, final String appsecret) { - logger.debug("Backroll client - start login"); - final HttpPost request = new HttpPost(apiURI.toString() + "/login"); + // private void login(final String appname, final String appsecret) throws IOException, KeyManagementException, NoSuchAlgorithmException { + // logger.info("Backroll client - start login"); + // CloseableHttpClient httpClient = createHttpClient(); + // CloseableHttpResponse response = null; + // final HttpPost request = new HttpPost(apiURI.toString() + "/login"); + // request.addHeader("content-type", "application/json"); + // JSONObject jsonBody = new JSONObject(); + // StringEntity params; + + // try { + // jsonBody.put("app_id", appname); + // jsonBody.put("app_secret", appsecret); + // params = new StringEntity(jsonBody.toString()); + // request.setEntity(params); + + // response = httpClient.execute(request); + + // try { + // HttpEntity body = response.getEntity(); + // String bodyStr = EntityUtils.toString(body); + + // LoginApiResponse loginResponse = new ObjectMapper().readValue(bodyStr, LoginApiResponse.class); + // backrollToken = loginResponse.accessToken; + // logger.debug(String.format("Backroll client - Token : %s", backrollToken)); + + // EntityUtils.consumeQuietly(response.getEntity()); + + // if (StringUtils.isEmpty(loginResponse.accessToken)) { + // throw new CloudRuntimeException("Backroll token is not available to perform API requests"); + // } + // } catch (final Exception e) { + // EntityUtils.consumeQuietly(response.getEntity()); + // 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(); + // } + // finally { + // closeConnection(response); + // } + // logger.info("Backroll client - end login"); + // } + + private void login(final String appname, final String appsecret) throws IOException, KeyManagementException, NoSuchAlgorithmException { + logger.debug("Backroll client - start login"); + + CloseableHttpClient httpClient = createHttpClient(); + CloseableHttpResponse response = null; + + final HttpPost request = new HttpPost(apiURI.toString() + "/login"); request.addHeader("content-type", "application/json"); JSONObject jsonBody = new JSONObject(); @@ -489,9 +588,13 @@ public class BackrollClient { params = new StringEntity(jsonBody.toString()); request.setEntity(params); - final HttpResponse response = httpClient.execute(request); + response = httpClient.execute(request); try { - LoginApiResponse loginResponse = parse(okBody(response)); + String toto = okBody(response); + ObjectMapper objectMapper = new ObjectMapper(); + logger.info("BACKROLL: " + toto); + LoginApiResponse loginResponse = objectMapper.readValue(toto, LoginApiResponse.class); + logger.info("ok"); backrollToken = loginResponse.accessToken; logger.debug("Backroll client - Token : {}", backrollToken); @@ -512,15 +615,22 @@ public class BackrollClient { } catch (JSONException e) { e.printStackTrace(); } + finally { + closeConnection(response); + } logger.debug("Backroll client - end login"); } - private List getBackrollBackups(final String vmId) { + private List getBackrollBackups(final String vmId) throws KeyManagementException, ParseException, NoSuchAlgorithmException { try { logger.info("start to list Backroll backups for vm {}", vmId); - String urlToRequest = this - .parse(okBody(get("/virtualmachines/" + vmId + "/backups"))).location - .replace("/api/v1", ""); + + CloseableHttpResponse response = get("/virtualmachines/" + vmId + "/backups"); + String result = okBody(response); + BackrollTaskRequestResponse requestResponse = parse(result); + response.close(); + String urlToRequest = requestResponse.location.replace("/api/v1", ""); + logger.debug(urlToRequest); BackrollBackupsFromVMResponse backrollBackupsFromVMResponse = waitGet(urlToRequest); @@ -539,4 +649,4 @@ public class BackrollClient { } return new ArrayList(); } -} +} \ No newline at end of file diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/TaskState.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/TaskState.java index e934b2ba621..a9abd43fd8b 100644 --- a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/TaskState.java +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/TaskState.java @@ -1,3 +1,19 @@ +// 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.backroll.model.response; public class TaskState {