mirror of https://github.com/apache/cloudstack.git
Merge 10b2a779d7 into b7d4df0a11
This commit is contained in:
commit
7cf2e379c7
|
|
@ -607,6 +607,11 @@
|
|||
<artifactId>cloud-plugin-integrations-prometheus-exporter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-plugin-backup-backroll</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-plugin-backup-dummy</artifactId>
|
||||
|
|
@ -1143,6 +1148,11 @@
|
|||
<artifactId>cloud-plugin-backup-veeam</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-plugin-backup-backroll</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="DefaultConfigResources" class="com.yourcompany.YourConfigClass">
|
||||
<!-- properties of the bean -->
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.xsd"
|
||||
>
|
||||
|
||||
<context:annotation-config />
|
||||
|
||||
<!-- Import additional configuration -->
|
||||
<import resource="classpath:default-config-resources.xml"/>
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
|
||||
<property name="order" value="100" />
|
||||
<property name="ignoreResourceNotFound" value="true" />
|
||||
<property name="ignoreUnresolvablePlaceholders" value="true" />
|
||||
<property name="locations" ref="DefaultConfigResources" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>cloud-plugin-backup-backroll</artifactId>
|
||||
<name>Apache CloudStack Plugin - BackRoll Backup and Recovery Plugin by DIMSI</name>
|
||||
<parent>
|
||||
<artifactId>cloudstack-plugins</artifactId>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<version>4.22.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-utils</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock-standalone</artifactId>
|
||||
<version>${cs.wiremock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
// 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.io.IOException;
|
||||
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.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
||||
import org.apache.cloudstack.backup.Backup.Metric;
|
||||
import org.apache.cloudstack.backup.Backup.RestorePoint;
|
||||
import org.apache.cloudstack.backup.backroll.BackrollClient;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollTaskStatus;
|
||||
import org.apache.cloudstack.backup.backroll.utils.BackrollApiException;
|
||||
import org.apache.cloudstack.backup.backroll.utils.BackrollHttpClientProvider;
|
||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
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.apache.logging.log4j.Logger;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.AdapterBase;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
public class BackrollBackupProvider extends AdapterBase implements BackupProvider, Configurable {
|
||||
|
||||
public static final String BACKUP_IDENTIFIER = "-CSBKP-";
|
||||
|
||||
public ConfigKey<String> 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);
|
||||
|
||||
public ConfigKey<String> BackrollAppNameConfigKey = new ConfigKey<>("Advanced", String.class,
|
||||
"backup.plugin.backroll.config.appname",
|
||||
"backroll-api",
|
||||
"App Name for backroll plugin.", true, ConfigKey.Scope.Zone);
|
||||
|
||||
public ConfigKey<String> BackrollPasswordConfigKey = new ConfigKey<>("Advanced", String.class,
|
||||
"backup.plugin.backroll.config.password",
|
||||
"VviX8dALauSyYJMqVYJqf3UyZOpO3joS",
|
||||
"Password for backroll plugin.", true, ConfigKey.Scope.Zone);
|
||||
|
||||
private BackrollClient backrollClient;
|
||||
|
||||
@Inject
|
||||
private BackupDao backupDao;
|
||||
@Inject
|
||||
private VMInstanceDao vmInstanceDao;
|
||||
|
||||
public BackrollBackupProvider(BackupDao backupDao, VMInstanceDao vmInstanceDao, BackrollClient client, Logger logger){
|
||||
this.backupDao = backupDao;
|
||||
this.vmInstanceDao = vmInstanceDao;
|
||||
this.backrollClient = client;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public BackrollBackupProvider(){}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "backroll";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Backroll Backup Plugin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BackupOffering> listBackupOfferings(Long zoneId) {
|
||||
logger.debug("Listing backup policies on backroll B&R Plugin");
|
||||
BackrollClient client = getClient(zoneId);
|
||||
try{
|
||||
String urlToRequest = client.getBackupOfferingUrl();
|
||||
logger.info("BackrollProvider: urlToRequest: " + urlToRequest);
|
||||
if (!StringUtils.isEmpty(urlToRequest)){
|
||||
List<BackupOffering> results = new ArrayList<BackupOffering>();
|
||||
// return client.getBackupOfferings(urlToRequest);
|
||||
results = client.getBackupOfferings(urlToRequest);
|
||||
if(results.size()>0) {
|
||||
logger.info("BackrollProvider: results > 0");
|
||||
} else {
|
||||
logger.info("BackrollProvider: results <= 0");
|
||||
}
|
||||
return results;
|
||||
}
|
||||
} catch (ParseException | BackrollApiException | IOException e) {
|
||||
logger.info("BackrollProvider: catch erreur: {}", e);
|
||||
throw new CloudRuntimeException("Failed to load backup offerings");
|
||||
}
|
||||
return new ArrayList<BackupOffering>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidProviderOffering(Long zoneId, String uuid) {
|
||||
logger.info("Checking if backup offering exists on the Backroll Backup Provider");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean assignVMToBackupOffering(VirtualMachine vm, BackupOffering backupOffering) {
|
||||
logger.info("Creating VM backup for VM {} from backup offering {}", vm.getInstanceName(), backupOffering.getName());
|
||||
if(vm instanceof VMInstanceVO) {
|
||||
((VMInstanceVO) vm).setBackupExternalId(backupOffering.getUuid());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@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;
|
||||
try {
|
||||
isSuccess = getClient(vm.getDataCenterId()).restoreVMFromBackup(vm.getUuid(), getBackupName(backup));
|
||||
} catch (ParseException | BackrollApiException | IOException e) {
|
||||
throw new CloudRuntimeException("Failed to restore VM from Backup");
|
||||
}
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<VirtualMachine> vms) {
|
||||
final Map<VirtualMachine, Backup.Metric> metrics = new HashMap<>();
|
||||
if (CollectionUtils.isEmpty(vms)) {
|
||||
logger.warn("Unable to get VM Backup Metrics because the list of VMs is empty.");
|
||||
return metrics;
|
||||
}
|
||||
|
||||
List<String> vmUuids = vms.stream().filter(Objects::nonNull).map(VirtualMachine::getUuid).collect(Collectors.toList());
|
||||
logger.debug("Get Backup Metrics for VMs: {}.", String.join(", ", vmUuids));
|
||||
|
||||
BackrollClient client = getClient(zoneId);
|
||||
for (final VirtualMachine vm : vms) {
|
||||
if (vm == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
// get backups from database
|
||||
List<Backup> backupsInDb = backupDao.listByVmId(zoneId, vm.getId());
|
||||
|
||||
// check backing up task
|
||||
for (Backup backup : backupsInDb) {
|
||||
if (backup.getStatus().equals(Backup.Status.BackingUp)) {
|
||||
BackrollTaskStatus response;
|
||||
try {
|
||||
response = client.checkBackupTaskStatus(backup.getExternalId());
|
||||
} catch (ParseException | BackrollApiException | IOException e) {
|
||||
logger.error(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());
|
||||
|
||||
BackupVO backupToUpdate = ((BackupVO) backup);
|
||||
|
||||
if (response.getState().equals("PENDING")) {
|
||||
backupToUpdate.setStatus(Backup.Status.BackingUp);
|
||||
} else if (response.getState().equals("FAILURE")) {
|
||||
backupToUpdate.setStatus(Backup.Status.Failed);
|
||||
} else if (response.getState().equals("SUCCESS")) {
|
||||
backupToUpdate.setStatus(Backup.Status.BackedUp);
|
||||
backupToUpdate.setExternalId(response.getInfo());
|
||||
|
||||
BackrollBackupMetrics backupMetrics = null;
|
||||
try {
|
||||
backupMetrics = client.getBackupMetrics(vm.getUuid() , response.getInfo());
|
||||
if (backupMetrics != null) {
|
||||
backupToUpdate.setProtectedSize(backupMetrics.getDeduplicated());
|
||||
backupToUpdate.setSize(backupMetrics.getSize());
|
||||
}
|
||||
} catch (BackrollApiException | IOException e) {
|
||||
logger.error(e);
|
||||
throw new CloudRuntimeException("Failed to get backup metrics");
|
||||
}
|
||||
} else {
|
||||
backupToUpdate.setStatus(Backup.Status.BackingUp);
|
||||
}
|
||||
|
||||
if (backupDao.persist(backupToUpdate) != null) {
|
||||
logger.info("Backroll backup updated");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(backup.getExternalId().contains(",")) {
|
||||
String backupId = backup.getExternalId().split(",")[1];
|
||||
BackupVO backupToUpdate = ((BackupVO) backup);
|
||||
backupToUpdate.setExternalId(backupId);
|
||||
try {
|
||||
BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , backupId);
|
||||
if (backupMetrics != null) {
|
||||
backupToUpdate.setProtectedSize(backupMetrics.getDeduplicated());
|
||||
backupToUpdate.setSize(backupMetrics.getSize());
|
||||
}
|
||||
} catch (BackrollApiException | IOException e) {
|
||||
logger.error(e);
|
||||
throw new CloudRuntimeException("Failed to get backup metrics");
|
||||
}
|
||||
if (backupDao.persist(backupToUpdate) != null) {
|
||||
logger.info("Backroll backup updated");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// refresh backup in database list
|
||||
backupsInDb = backupDao.listByVmId(zoneId, vm.getId());
|
||||
|
||||
Long usedSize = 0L;
|
||||
Long dataSize = 0L;
|
||||
List<RestorePoint> backups = client.listRestorePoints(vm.getUuid());
|
||||
for (RestorePoint backup : backups) {
|
||||
|
||||
BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , getBackupName(backup.getId()));
|
||||
if (backupMetrics != null) {
|
||||
usedSize += Long.valueOf(backupMetrics.getDeduplicated());
|
||||
dataSize += Long.valueOf(backupMetrics.getSize());
|
||||
|
||||
// update backup metrics
|
||||
Backup backupToFind = backupsInDb.stream()
|
||||
.filter(backupInDb -> backupInDb.getExternalId().contains(backup.getId()))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
|
||||
if (backupToFind != null) {
|
||||
BackupVO backupToUpdate = ((BackupVO) backupToFind);
|
||||
backupToUpdate.setProtectedSize(usedSize);
|
||||
backupToUpdate.setSize(dataSize);
|
||||
backupDao.persist(backupToUpdate);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Metric metric = new Metric(dataSize, usedSize);
|
||||
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 (BackrollApiException | IOException e) {
|
||||
throw new CloudRuntimeException("Failed to retrieve backup metrics");
|
||||
}
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeVMFromBackupOffering(VirtualMachine vm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willDeleteBackupsOnOfferingRemoval() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Boolean, Backup> takeBackup(VirtualMachine vm) {
|
||||
logger.info("Starting backup for VM ID {} on backroll provider", vm.getUuid());
|
||||
final BackrollClient client = getClient(vm.getDataCenterId());
|
||||
|
||||
try {
|
||||
String urlToRequest = client.startBackupJob(vm.getUuid());
|
||||
logger.info("BackrollProvider: urlToRequest: " + urlToRequest);
|
||||
String backupJob = urlToRequest.replace("/status/", "");
|
||||
if (!StringUtils.isEmpty(backupJob)) {
|
||||
BackupVO backup = new BackupVO();
|
||||
backup.setVmId(vm.getId());
|
||||
backup.setExternalId(backupJob);
|
||||
backup.setType("INCREMENTAL");
|
||||
backup.setDate(new DateTime().toDate());
|
||||
backup.setSize(0L);
|
||||
backup.setProtectedSize(0L);
|
||||
backup.setStatus(Backup.Status.BackingUp);
|
||||
backup.setBackupOfferingId(vm.getBackupOfferingId());
|
||||
backup.setAccountId(vm.getAccountId());
|
||||
backup.setDomainId(vm.getDomainId());
|
||||
backup.setZoneId(vm.getDataCenterId());
|
||||
Boolean result = backupDao.persist(backup) != null;
|
||||
return new Pair<Boolean,Backup>(result, backup);
|
||||
}
|
||||
} catch (ParseException | BackrollApiException | IOException e) {
|
||||
logger.debug(e.getMessage());
|
||||
throw new CloudRuntimeException("Failed to take backup");
|
||||
}
|
||||
return new Pair<Boolean,Backup>(false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfigComponentName() {
|
||||
return BackupService.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigKey<?>[] getConfigKeys() {
|
||||
return new ConfigKey[]{
|
||||
BackrollUrlConfigKey,
|
||||
BackrollAppNameConfigKey,
|
||||
BackrollPasswordConfigKey
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
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");
|
||||
} else {
|
||||
logger.debug("BACKROLL: try delete backup");
|
||||
|
||||
if (backup.getStatus().equals(Backup.Status.Removed) || backup.getStatus().equals(Backup.Status.Failed)){
|
||||
return deleteBackupInDb(backup);
|
||||
} else {
|
||||
VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
|
||||
try {
|
||||
if (getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup))) {
|
||||
logger.debug("BACKROLL: Backup deletion for backup {} complete on backroll side.", backup.getUuid());
|
||||
return deleteBackupInDb(backup);
|
||||
}
|
||||
} catch (BackrollApiException | IOException e) {
|
||||
logger.error(e);
|
||||
throw new CloudRuntimeException("BACKROLL: Failed to delete backup");
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean deleteBackupInDb(Backup backup) {
|
||||
BackupVO backupToUpdate = ((BackupVO) backup);
|
||||
backupToUpdate.setStatus(Backup.Status.Removed);
|
||||
if (backupDao.persist(backupToUpdate) != null) {
|
||||
logger.debug("BACKROLL: Backroll backup {} deleted in database.", backup.getUuid());
|
||||
VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected BackrollClient getClient(final Long zoneId) {
|
||||
logger.debug("Backroll Provider GetClient with zone id {}", zoneId);
|
||||
try {
|
||||
if (backrollClient == null) {
|
||||
logger.debug("backroll client null - instantiation of new one ");
|
||||
BackrollHttpClientProvider provider = BackrollHttpClientProvider.createProvider(new BackrollHttpClientProvider(), BackrollUrlConfigKey.valueIn(zoneId), BackrollAppNameConfigKey.valueIn(zoneId), BackrollPasswordConfigKey.valueIn(zoneId), true, 300, 600);
|
||||
backrollClient = new BackrollClient(provider);
|
||||
}
|
||||
return backrollClient;
|
||||
} catch (URISyntaxException e) {
|
||||
logger.error(e);
|
||||
throw new CloudRuntimeException("Failed to parse Backroll API URL: " + e.getMessage());
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
logger.error(e);
|
||||
throw new CloudRuntimeException("Failed to build Backroll API client");
|
||||
}
|
||||
}
|
||||
|
||||
private String getBackupName(Backup backup) {
|
||||
return getBackupName(backup.getExternalId());
|
||||
}
|
||||
|
||||
private String getBackupName(String externalId) {
|
||||
return externalId.substring(externalId.indexOf(",") + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> 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");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RestorePoint> listRestorePoints(VirtualMachine vm) {
|
||||
try {
|
||||
final BackrollClient client = getClient(vm.getDataCenterId());
|
||||
return client.listRestorePoints(vm.getUuid());
|
||||
} catch (BackrollApiException | IOException e) {
|
||||
logger.error(e);
|
||||
throw new CloudRuntimeException("Error while listing restore points");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Backup createNewBackupEntryForRestorePoint(RestorePoint restorePoint, VirtualMachine vm, Metric metric) {
|
||||
final BackrollClient client = getClient(vm.getDataCenterId());
|
||||
BackupVO backupToInsert = new BackupVO();
|
||||
backupToInsert.setVmId(vm.getId());
|
||||
backupToInsert.setExternalId(restorePoint.getId());
|
||||
backupToInsert.setType("INCREMENTAL");
|
||||
backupToInsert.setDate(restorePoint.getCreated());
|
||||
backupToInsert.setStatus(Backup.Status.BackedUp);
|
||||
backupToInsert.setBackupOfferingId(vm.getBackupOfferingId());
|
||||
backupToInsert.setAccountId(vm.getAccountId());
|
||||
backupToInsert.setDomainId(vm.getDomainId());
|
||||
backupToInsert.setZoneId(vm.getDataCenterId());
|
||||
|
||||
try {
|
||||
BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , getBackupName(restorePoint.getId()));
|
||||
if (backupMetrics != null) {
|
||||
backupToInsert.setProtectedSize(backupMetrics.getDeduplicated());
|
||||
backupToInsert.setSize(backupMetrics.getSize());
|
||||
}
|
||||
} catch (IOException | BackrollApiException e) {
|
||||
logger.error(e);
|
||||
}
|
||||
|
||||
backupDao.persist(backupToInsert);
|
||||
return backupToInsert;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
// 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.backup.Backup;
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
import org.apache.cloudstack.backup.Backup.Metric;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollOffering;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollTaskStatus;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollVmBackup;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollTaskRequestResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.TaskState;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.archive.BackrollBackupsFromVMResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.backup.BackrollBackupStatusResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.backup.BackrollBackupStatusSuccessResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.backup.BackrollBackupMetricsResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.BackrollVmMetricsResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.CacheStats;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups.BackupInfos;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups.VirtualMachineBackupsResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.policy.BackrollBackupPolicyResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.policy.BackupPoliciesResponse;
|
||||
import org.apache.cloudstack.backup.backroll.utils.BackrollApiException;
|
||||
import org.apache.cloudstack.backup.backroll.utils.BackrollHttpClientProvider;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class BackrollClient {
|
||||
|
||||
protected Logger logger = LogManager.getLogger(BackrollClient.class);
|
||||
|
||||
private BackrollHttpClientProvider httpProvider;
|
||||
|
||||
public BackrollClient(BackrollHttpClientProvider httpProvider)
|
||||
throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
|
||||
|
||||
this.httpProvider = httpProvider;
|
||||
}
|
||||
|
||||
public String startBackupJob(final String jobId) throws IOException, BackrollApiException {
|
||||
logger.info("startBackupJob : Trying to start backup for Backroll job: {}", jobId);
|
||||
String backupJob = "";
|
||||
BackrollTaskRequestResponse requestResponse = httpProvider.post(String.format("/tasks/singlebackup/%s", jobId),
|
||||
null, BackrollTaskRequestResponse.class);
|
||||
logger.info("startBackupJob : BackupJob status link: {}", requestResponse.location);
|
||||
backupJob = requestResponse.location.replace("/api/v1", "");
|
||||
return StringUtils.isEmpty(backupJob) ? null : backupJob;
|
||||
}
|
||||
|
||||
public String getBackupOfferingUrl() throws IOException, BackrollApiException {
|
||||
logger.info("Trying to get backroll backup policies url");
|
||||
String url = "";
|
||||
BackrollTaskRequestResponse requestResponse = httpProvider.get("/backup_policies",
|
||||
BackrollTaskRequestResponse.class);
|
||||
logger.info("BackrollClient:getBackupOfferingUrl:Apres Parse: " + requestResponse.location);
|
||||
url = requestResponse.location.replace("/api/v1", "");
|
||||
return StringUtils.isEmpty(url) ? null : url;
|
||||
}
|
||||
|
||||
public List<BackupOffering> getBackupOfferings(String idTask) throws BackrollApiException, IOException {
|
||||
logger.info("Trying to list backroll backup policies");
|
||||
final List<BackupOffering> policies = new ArrayList<>();
|
||||
BackupPoliciesResponse backupPoliciesResponse = httpProvider.waitGet(idTask, BackupPoliciesResponse.class);
|
||||
logger.info(
|
||||
"BackrollClient:getBackupOfferings:Apres Parse: " + backupPoliciesResponse.backupPolicies.get(0).name);
|
||||
for (final BackrollBackupPolicyResponse policy : backupPoliciesResponse.backupPolicies) {
|
||||
policies.add(new BackrollOffering(policy.name, policy.id));
|
||||
}
|
||||
|
||||
return policies;
|
||||
}
|
||||
|
||||
public boolean restoreVMFromBackup(final String vmId, final String backupName)
|
||||
throws IOException, BackrollApiException {
|
||||
logger.info("Start restore backup with backroll with backup {} for vm {}", backupName, vmId);
|
||||
|
||||
boolean isRestoreOk = false;
|
||||
|
||||
JSONObject jsonBody = new JSONObject();
|
||||
try {
|
||||
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());
|
||||
}
|
||||
|
||||
BackrollTaskRequestResponse requestResponse = httpProvider.post(String.format("/tasks/restore/%s", vmId),
|
||||
jsonBody, BackrollTaskRequestResponse.class);
|
||||
String urlToRequest = requestResponse.location.replace("/api/v1", "");
|
||||
|
||||
String result = httpProvider.waitGetWithoutParseResponse(urlToRequest);
|
||||
if (result.contains("SUCCESS")) {
|
||||
logger.debug("RESTORE SUCCESS content : " + result);
|
||||
logger.debug("RESTORE SUCCESS");
|
||||
isRestoreOk = true;
|
||||
}
|
||||
|
||||
return isRestoreOk;
|
||||
}
|
||||
|
||||
public BackrollTaskStatus checkBackupTaskStatus(String taskId) throws IOException, BackrollApiException {
|
||||
logger.info("Trying to get backup status for Backroll task: {}", taskId);
|
||||
|
||||
BackrollTaskStatus status = new BackrollTaskStatus();
|
||||
|
||||
String backupResponse = httpProvider.getWithoutParseResponse("/status/" + taskId);
|
||||
|
||||
if (backupResponse.contains(TaskState.FAILURE) || backupResponse.contains(TaskState.PENDING)) {
|
||||
BackrollBackupStatusResponse backupStatusRequestResponse = new ObjectMapper().readValue(backupResponse,
|
||||
BackrollBackupStatusResponse.class);
|
||||
status.setState(backupStatusRequestResponse.state);
|
||||
} else {
|
||||
BackrollBackupStatusSuccessResponse backupStatusSuccessRequestResponse = new ObjectMapper()
|
||||
.readValue(backupResponse, BackrollBackupStatusSuccessResponse.class);
|
||||
status.setState(backupStatusSuccessRequestResponse.state);
|
||||
status.setInfo(backupStatusSuccessRequestResponse.info);
|
||||
}
|
||||
|
||||
return StringUtils.isEmpty(status.getState()) ? null : status;
|
||||
}
|
||||
|
||||
public boolean deleteBackup(final String vmId, final String backupName) throws IOException, BackrollApiException {
|
||||
logger.info("BACKROLL: Trying to delete backup {} for vm {} using Backroll", vmId, backupName);
|
||||
boolean isBackupDeleted = false;
|
||||
|
||||
BackrollTaskRequestResponse requestResponse = httpProvider.delete(
|
||||
String.format("/virtualmachines/%s/backups/%s", vmId, backupName), BackrollTaskRequestResponse.class);
|
||||
String urlToRequest = requestResponse.location.replace("/api/v1", "");
|
||||
|
||||
BackrollBackupsFromVMResponse backrollBackupsFromVMResponse = httpProvider.waitGet(urlToRequest,
|
||||
BackrollBackupsFromVMResponse.class);
|
||||
logger.debug(backrollBackupsFromVMResponse.state);
|
||||
isBackupDeleted = backrollBackupsFromVMResponse.state.equals(TaskState.SUCCESS);
|
||||
|
||||
return isBackupDeleted;
|
||||
}
|
||||
|
||||
public Metric getVirtualMachineMetrics(final String vmId) throws IOException, BackrollApiException {
|
||||
logger.info("Trying to retrieve virtual machine metric from Backroll for vm {}", vmId);
|
||||
|
||||
Metric metric = new Metric(0L, 0L);
|
||||
|
||||
BackrollTaskRequestResponse requestResponse = httpProvider
|
||||
.get(String.format("/virtualmachines/%s/repository", vmId), BackrollTaskRequestResponse.class);
|
||||
|
||||
String urlToRequest = requestResponse.location.replace("/api/v1", "");
|
||||
|
||||
BackrollVmMetricsResponse vmMetricsResponse = httpProvider.waitGet(urlToRequest,
|
||||
BackrollVmMetricsResponse.class);
|
||||
|
||||
if (vmMetricsResponse != null && vmMetricsResponse.state.equals(TaskState.SUCCESS)) {
|
||||
logger.debug("SUCCESS ok");
|
||||
CacheStats stats = null;
|
||||
try {
|
||||
stats = vmMetricsResponse.infos.cache.stats;
|
||||
} catch (NullPointerException e) {
|
||||
}
|
||||
if (stats != null) {
|
||||
long size = Long.parseLong(stats.totalSize);
|
||||
metric = new Metric(size, size);
|
||||
}
|
||||
}
|
||||
|
||||
return metric;
|
||||
}
|
||||
|
||||
public BackrollBackupMetrics getBackupMetrics(String vmId, String backupId)
|
||||
throws IOException, BackrollApiException {
|
||||
logger.info("Trying to get backup metrics for VM: {}, and backup: {}", vmId, backupId);
|
||||
|
||||
BackrollBackupMetrics metrics = null;
|
||||
|
||||
BackrollTaskRequestResponse requestResponse = httpProvider.get(
|
||||
String.format("/virtualmachines/%s/backups/%s", vmId, backupId), BackrollTaskRequestResponse.class);
|
||||
|
||||
String urlToRequest = requestResponse.location.replace("/api/v1", "");
|
||||
|
||||
logger.debug(urlToRequest);
|
||||
|
||||
BackrollBackupMetricsResponse metricsResponse = httpProvider.waitGet(urlToRequest,
|
||||
BackrollBackupMetricsResponse.class);
|
||||
if (metricsResponse.info != null) {
|
||||
metrics = new BackrollBackupMetrics(Long.parseLong(metricsResponse.info.originalSize),
|
||||
Long.parseLong(metricsResponse.info.deduplicatedSize));
|
||||
}
|
||||
return metrics;
|
||||
}
|
||||
|
||||
public List<BackrollVmBackup> getAllBackupsfromVirtualMachine(String vmId)
|
||||
throws BackrollApiException, IOException {
|
||||
List<BackrollVmBackup> backups = new ArrayList<BackrollVmBackup>();
|
||||
List<BackupInfos> backupInfos = getBackupInfosFromVm(vmId);
|
||||
if (backupInfos != null && backupInfos.size() > 0) {
|
||||
for (BackupInfos infos : backupInfos) {
|
||||
var dateStart = new DateTime(infos.start);
|
||||
backups.add(new BackrollVmBackup(infos.id, infos.name, dateStart.toDate()));
|
||||
}
|
||||
}
|
||||
return backups;
|
||||
}
|
||||
|
||||
public List<BackupInfos> getBackupInfosFromVm(String vmId)
|
||||
throws BackrollApiException, IOException {
|
||||
logger.info("Trying to retrieve all backups for vm {}", vmId);
|
||||
BackrollTaskRequestResponse requestResponse = httpProvider
|
||||
.get(String.format("/virtualmachines/%s/backups", vmId), BackrollTaskRequestResponse.class);
|
||||
|
||||
String urlToRequest = requestResponse.location.replace("/api/v1", "");
|
||||
logger.debug(urlToRequest);
|
||||
VirtualMachineBackupsResponse virtualMachineBackupsResponse = httpProvider.waitGet(urlToRequest,
|
||||
VirtualMachineBackupsResponse.class);
|
||||
if (virtualMachineBackupsResponse.state.equals(TaskState.SUCCESS)) {
|
||||
return virtualMachineBackupsResponse.info.archives;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public List<Backup.RestorePoint> listRestorePoints(String vmId) throws BackrollApiException, IOException {
|
||||
List<Backup.RestorePoint> backups = new ArrayList<Backup.RestorePoint>();
|
||||
List<BackupInfos> backupInfos = getBackupInfosFromVm(vmId);
|
||||
if (backupInfos != null && backupInfos.size() > 0) {
|
||||
for (BackupInfos infos : backupInfos) {
|
||||
var dateStart = new DateTime(infos.start);
|
||||
backups.add(new Backup.RestorePoint(infos.name, dateStart.toDate(), "INCREMENTAL"));
|
||||
}
|
||||
}
|
||||
return backups;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// 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;
|
||||
|
||||
public class BackrollBackup {
|
||||
private String archive;
|
||||
|
||||
public String getArchive() {
|
||||
return archive;
|
||||
}
|
||||
|
||||
public BackrollBackup(String archive) {
|
||||
this.archive = archive;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// 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;
|
||||
|
||||
public class BackrollBackupMetrics {
|
||||
private long size;
|
||||
private long deduplicated;
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public long getDeduplicated() {
|
||||
return deduplicated;
|
||||
}
|
||||
|
||||
public BackrollBackupMetrics(long size, long deduplicated) {
|
||||
this.size = size;
|
||||
this.deduplicated = deduplicated;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// 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;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
|
||||
public class BackrollOffering implements BackupOffering {
|
||||
|
||||
private String name;
|
||||
private String uid;
|
||||
|
||||
public BackrollOffering(String name, String uid) {
|
||||
this.name = name;
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExternalId() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Backroll Backup Offering (Job)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getZoneId() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserDrivenBackupAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProvider() {
|
||||
return "backroll";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreated() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
return uid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// 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;
|
||||
|
||||
public class BackrollTaskStatus {
|
||||
private String state;
|
||||
private String error;
|
||||
private String info;
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
public void setInfo(String info) {
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// 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;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class BackrollVmBackup {
|
||||
private String id;
|
||||
private String name;
|
||||
private Date date;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public BackrollVmBackup(String id, String name, Date date) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.date = date;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public abstract class BackrollAsyncResponse {
|
||||
@JsonProperty("state")
|
||||
public String state;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollTaskRequestResponse {
|
||||
@JsonProperty("Location")
|
||||
public String location;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// 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 {
|
||||
public static final String PENDING = "PENDING";
|
||||
public static final String FAILURE = "FAILURE";
|
||||
public static final String SUCCESS = "SUCCESS";
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class TaskStateResponse {
|
||||
@JsonProperty("state")
|
||||
public String state;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// 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.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class LoginApiResponse {
|
||||
@JsonProperty("access_token")
|
||||
public String accessToken;
|
||||
|
||||
@JsonProperty("expires_in")
|
||||
public int expiresIn;
|
||||
|
||||
@JsonProperty("refresh_expires_in")
|
||||
public String refreshExpiresIn;
|
||||
|
||||
@JsonProperty("token_type")
|
||||
public String tokenType;
|
||||
|
||||
@JsonProperty("not-before-policy")
|
||||
public String notBeforePolicy;
|
||||
|
||||
@JsonProperty("scope")
|
||||
public String scope;
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// 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.archive;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollArchiveResponse {
|
||||
@JsonProperty("archive")
|
||||
public String archive;
|
||||
|
||||
// TODO Merged typo ?
|
||||
@JsonProperty("barchive")
|
||||
public String barchive;
|
||||
|
||||
@JsonProperty("id")
|
||||
public String id;
|
||||
|
||||
@JsonProperty("name")
|
||||
public String name;
|
||||
|
||||
@JsonProperty("start")
|
||||
public DateTime start;
|
||||
|
||||
@JsonProperty("time")
|
||||
public DateTime time;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// 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.archive;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollArchivesResponse {
|
||||
@JsonProperty("archives")
|
||||
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||
public List<BackrollArchiveResponse> archives;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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.archive;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollAsyncResponse;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollBackupsFromVMResponse extends BackrollAsyncResponse {
|
||||
@JsonProperty("info")
|
||||
public BackrollArchivesResponse archives;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// 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.backup;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollAsyncResponse;
|
||||
|
||||
public class BackrollBackupResponse extends BackrollAsyncResponse{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// 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.backup;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollBackupStatusResponse {
|
||||
@JsonProperty("state")
|
||||
public String state;
|
||||
|
||||
@JsonProperty("current")
|
||||
public String current;
|
||||
|
||||
@JsonProperty("total")
|
||||
public String total;
|
||||
|
||||
@JsonProperty("status")
|
||||
public String status;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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.backup;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollBackupStatusSuccessResponse {
|
||||
@JsonProperty("state")
|
||||
public String state;
|
||||
|
||||
@JsonProperty("info")
|
||||
public String info;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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.metrics.backup;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollAsyncResponse;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollBackupMetricsResponse extends BackrollAsyncResponse {
|
||||
@JsonProperty("info")
|
||||
public BackupMetricsInfo info;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// 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.metrics.backup;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackupMetricsInfo {
|
||||
@JsonProperty("compressed_size")
|
||||
public String compressedSize;
|
||||
|
||||
@JsonProperty("deduplicated_size")
|
||||
public String deduplicatedSize;
|
||||
|
||||
@JsonProperty("nfiles")
|
||||
public String nFiles;
|
||||
|
||||
@JsonProperty("original_size")
|
||||
public String originalSize;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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.metrics.virtualMachine;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollAsyncResponse;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollVmMetricsResponse extends BackrollAsyncResponse{
|
||||
@JsonProperty("info")
|
||||
public MetricsInfos infos;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// 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.metrics.virtualMachine;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class CacheStats {
|
||||
@JsonProperty("total_chunks")
|
||||
public String totalChunks;
|
||||
|
||||
@JsonProperty("total_csize")
|
||||
public String totalCsize;
|
||||
|
||||
@JsonProperty("total_size")
|
||||
public String totalSize;
|
||||
|
||||
@JsonProperty("total_unique_chunks")
|
||||
public String totalUniqueChunks;
|
||||
|
||||
@JsonProperty("unique_csize")
|
||||
public String uniqueCsize;
|
||||
|
||||
@JsonProperty("unique_size")
|
||||
public String uniqueSize;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// 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.metrics.virtualMachine;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class InfosCache {
|
||||
@JsonProperty("path")
|
||||
public String path;
|
||||
|
||||
@JsonProperty("stats")
|
||||
public CacheStats stats;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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.metrics.virtualMachine;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class InfosEncryption {
|
||||
@JsonProperty("mode")
|
||||
public String mode;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// 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.metrics.virtualMachine;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class InfosRepository {
|
||||
@JsonProperty("id")
|
||||
public String id;
|
||||
|
||||
@JsonProperty("last_modified")
|
||||
public String lastModified;
|
||||
|
||||
@JsonProperty("location")
|
||||
public String location;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// 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.metrics.virtualMachine;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class MetricsInfos {
|
||||
@JsonProperty("cache")
|
||||
public InfosCache cache;
|
||||
|
||||
@JsonProperty("encryption")
|
||||
public InfosEncryption encryption;
|
||||
|
||||
@JsonProperty("repository")
|
||||
public InfosRepository repository;
|
||||
|
||||
@JsonProperty("security_dir")
|
||||
public String securityDir;
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// 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.metrics.virtualMachineBackups;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class Archives {
|
||||
@JsonProperty("archives")
|
||||
public List<BackupInfos> archives;
|
||||
|
||||
@JsonProperty(value = "encryption", required = false)
|
||||
public InfosEncryption encryption;
|
||||
|
||||
@JsonProperty(value = "repository", required = false)
|
||||
public InfosRepository repository;
|
||||
|
||||
@JsonProperty(value = "state", required = false)
|
||||
public String state;
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// 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.metrics.virtualMachineBackups;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackupInfos {
|
||||
@JsonProperty("archive")
|
||||
public String archive;
|
||||
|
||||
// TODO Merged typo ?
|
||||
@JsonProperty("barchive")
|
||||
public String barchive;
|
||||
|
||||
@JsonProperty("id")
|
||||
public String id;
|
||||
|
||||
@JsonProperty("name")
|
||||
public String name;
|
||||
|
||||
@JsonProperty("start")
|
||||
public String start;
|
||||
|
||||
@JsonProperty("time")
|
||||
public String time;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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.metrics.virtualMachineBackups;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class InfosEncryption {
|
||||
@JsonProperty("mode")
|
||||
public String mode;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// 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.metrics.virtualMachineBackups;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class InfosRepository {
|
||||
@JsonProperty("id")
|
||||
public String id;
|
||||
|
||||
@JsonProperty("last_modified")
|
||||
public String lastModified;
|
||||
|
||||
@JsonProperty("location")
|
||||
public String location;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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.metrics.virtualMachineBackups;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollAsyncResponse;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class VirtualMachineBackupsResponse extends BackrollAsyncResponse {
|
||||
@JsonProperty("info")
|
||||
public Archives info;
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// 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.policy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackrollBackupPolicyResponse {
|
||||
@JsonProperty("name")
|
||||
public String name;
|
||||
|
||||
@JsonProperty("retention_day")
|
||||
public int retentionDay;
|
||||
|
||||
@JsonProperty("schedule")
|
||||
public String schedule;
|
||||
|
||||
@JsonProperty("retention_month")
|
||||
public int retentionMonth;
|
||||
|
||||
@JsonProperty("storage")
|
||||
public String storage;
|
||||
|
||||
@JsonProperty("enabled")
|
||||
public Boolean enabled;
|
||||
|
||||
@JsonProperty("description")
|
||||
public String description;
|
||||
|
||||
@JsonProperty("id")
|
||||
public String id;
|
||||
|
||||
@JsonProperty("retention_week")
|
||||
public int retentionWeek;
|
||||
|
||||
@JsonProperty("retention_year")
|
||||
public int retentionYear;
|
||||
|
||||
@JsonProperty("externalhook")
|
||||
public String externalHook;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// 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.policy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollAsyncResponse;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class BackupPoliciesResponse extends BackrollAsyncResponse {
|
||||
|
||||
@JsonProperty("info")
|
||||
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||
public List<BackrollBackupPolicyResponse> backupPolicies;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// 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.restore;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollAsyncResponse;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class BackrollRestoreResponse extends BackrollAsyncResponse {
|
||||
@JsonProperty("info")
|
||||
public String info;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// 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.utils;
|
||||
|
||||
|
||||
public class BackrollApiException extends Exception {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,403 @@
|
|||
// 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.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.backup.backroll.BackrollClient;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.TaskState;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.api.LoginApiResponse;
|
||||
import org.apache.cloudstack.utils.security.SSLUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.ParseException;
|
||||
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;
|
||||
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;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.utils.nio.TrustAllManager;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class BackrollHttpClientProvider {
|
||||
private URI apiURI;;
|
||||
private String backrollToken = null;
|
||||
private String appname = null;
|
||||
private String password = null;
|
||||
private RequestConfig config = null;
|
||||
private boolean validateCertificate = false;
|
||||
|
||||
private Logger logger = LogManager.getLogger(BackrollClient.class);
|
||||
|
||||
public static BackrollHttpClientProvider createProvider(final BackrollHttpClientProvider backrollHttpClientProvider, final String url, final String appname, final String password,
|
||||
final boolean validateCertificate, final int timeout,
|
||||
final int restoreTimeout) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
|
||||
//BackrollHttpClientProvider backrollHttpClientProvider = new BackrollHttpClientProvider();
|
||||
backrollHttpClientProvider.apiURI = new URI(url);
|
||||
backrollHttpClientProvider.appname = appname;
|
||||
backrollHttpClientProvider.password = password;
|
||||
backrollHttpClientProvider.validateCertificate = validateCertificate;
|
||||
|
||||
backrollHttpClientProvider.config = RequestConfig.custom()
|
||||
.setConnectTimeout(timeout * 1000)
|
||||
.setConnectionRequestTimeout(timeout * 1000)
|
||||
.setSocketTimeout(timeout * 1000)
|
||||
.build();
|
||||
|
||||
return backrollHttpClientProvider;
|
||||
}
|
||||
|
||||
protected CloseableHttpClient createHttpClient() throws BackrollApiException {
|
||||
if(!validateCertificate) {
|
||||
SSLContext sslContext;
|
||||
try {
|
||||
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();
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
logger.error(e);
|
||||
e.printStackTrace();
|
||||
throw new BackrollApiException();
|
||||
}
|
||||
} else {
|
||||
return HttpClientBuilder.create()
|
||||
.setDefaultRequestConfig(config)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T post(final String path, final JSONObject json, Class<T> classOfT) throws BackrollApiException, IOException {
|
||||
|
||||
loginIfAuthenticationFailed();
|
||||
|
||||
try (CloseableHttpClient httpClient = createHttpClient()) {
|
||||
|
||||
String xml = null;
|
||||
StringEntity params = null;
|
||||
if (json != null) {
|
||||
logger.debug("JSON {}", json.toString());
|
||||
params = new StringEntity(json.toString(), ContentType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
String url = apiURI.toString() + path;
|
||||
final HttpPost request = new HttpPost(url);
|
||||
|
||||
if (params != null) {
|
||||
request.setEntity(params);
|
||||
}
|
||||
|
||||
request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + backrollToken);
|
||||
request.setHeader("Content-type", "application/json");
|
||||
|
||||
final CloseableHttpResponse response = httpClient.execute(request);
|
||||
|
||||
logger.debug("Response received in POST request with body {} is: {} for URL {}.", xml, response.toString(), url);
|
||||
|
||||
String result = okBody(response);
|
||||
|
||||
T requestResponse = new ObjectMapper().readValue(result, classOfT);
|
||||
//response.close();
|
||||
|
||||
return requestResponse;
|
||||
} catch (ParseException | NotOkBodyException e) {
|
||||
logger.error(e);
|
||||
e.printStackTrace();
|
||||
throw new BackrollApiException();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T get(String path, Class<T> classOfT) throws IOException, BackrollApiException{
|
||||
logger.debug("Backroll Get Auth ");
|
||||
loginIfAuthenticationFailed();
|
||||
logger.debug("Backroll Get Auth ok");
|
||||
try (CloseableHttpClient httpClient = createHttpClient()) {
|
||||
|
||||
String url = apiURI.toString() + path;
|
||||
logger.debug("Backroll URL {}", url);
|
||||
|
||||
HttpGet request = new HttpGet(url);
|
||||
request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + backrollToken);
|
||||
request.setHeader("Content-type", "application/json");
|
||||
CloseableHttpResponse response = httpClient.execute(request);
|
||||
logger.debug("Response received in GET request is: {} for URL: {}.", response.toString(), url);
|
||||
|
||||
String result = okBody(response);
|
||||
T requestResponse = new ObjectMapper().readValue(result, classOfT);
|
||||
//response.close();
|
||||
|
||||
return requestResponse;
|
||||
} catch (NotOkBodyException e) {
|
||||
logger.error(e);
|
||||
e.printStackTrace();
|
||||
throw new BackrollApiException();
|
||||
}
|
||||
}
|
||||
|
||||
public String getWithoutParseResponse(String path) throws IOException, BackrollApiException{
|
||||
logger.debug("Backroll Get Auth ");
|
||||
loginIfAuthenticationFailed();
|
||||
logger.debug("Backroll Get Auth ok");
|
||||
try (CloseableHttpClient httpClient = createHttpClient()) {
|
||||
|
||||
String url = apiURI.toString() + path;
|
||||
logger.debug("Backroll URL {}", url);
|
||||
|
||||
HttpGet request = new HttpGet(url);
|
||||
request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + backrollToken);
|
||||
request.setHeader("Content-type", "application/json");
|
||||
CloseableHttpResponse response = httpClient.execute(request);
|
||||
logger.debug("Response received in GET request is: {} for URL: {}.", response.toString(), url);
|
||||
|
||||
String result = okBody(response);
|
||||
//response.close();
|
||||
|
||||
return result;
|
||||
} catch (NotOkBodyException e) {
|
||||
logger.error(e);
|
||||
e.printStackTrace();
|
||||
throw new BackrollApiException();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T delete(String path, Class<T> classOfT) throws IOException, BackrollApiException {
|
||||
|
||||
loginIfAuthenticationFailed();
|
||||
|
||||
try (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 CloseableHttpResponse response = httpClient.execute(request);
|
||||
logger.debug("Response received in GET request is: {} for URL: {}.", response.toString(), url);
|
||||
|
||||
String result = okBody(response);
|
||||
T requestResponse = new ObjectMapper().readValue(result, classOfT);
|
||||
//response.close();
|
||||
|
||||
return requestResponse;
|
||||
} catch (NotOkBodyException e) {
|
||||
logger.error(e);
|
||||
e.printStackTrace();
|
||||
throw new BackrollApiException();
|
||||
}
|
||||
}
|
||||
|
||||
public class NotOkBodyException extends Exception {
|
||||
public NotOkBodyException() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
public String okBody(final CloseableHttpResponse response) throws NotOkBodyException {
|
||||
String result = "";
|
||||
switch (response.getStatusLine().getStatusCode()) {
|
||||
case HttpStatus.SC_OK:
|
||||
case HttpStatus.SC_ACCEPTED:
|
||||
HttpEntity bodyEntity = response.getEntity();
|
||||
try {
|
||||
logger.debug("bodyentity : {}", bodyEntity);
|
||||
result = EntityUtils.toString(bodyEntity);
|
||||
logger.debug("bodyentity : result {}", result);
|
||||
EntityUtils.consumeQuietly(bodyEntity);
|
||||
return result;
|
||||
} catch (ParseException | IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new NotOkBodyException();
|
||||
} finally {
|
||||
EntityUtils.consumeQuietly(bodyEntity);
|
||||
}
|
||||
default:
|
||||
try {
|
||||
closeConnection(response);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
throw new NotOkBodyException();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T waitGet(String url, Class<T> classOfT) throws IOException, BackrollApiException {
|
||||
// int threshold = 30; // 5 minutes
|
||||
int maxAttempts = 12; // 2 minutes
|
||||
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
String body = getWithoutParseResponse(url);
|
||||
if(!StringUtils.isEmpty(body)){
|
||||
if (!body.contains(TaskState.PENDING)) {
|
||||
logger.debug("METRICS waitGetWithoutParseResponse : result {}", body);
|
||||
T result = new ObjectMapper().readValue(body, classOfT);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e);
|
||||
e.printStackTrace();
|
||||
throw new BackrollApiException();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String waitGetWithoutParseResponse(String url)
|
||||
throws IOException, BackrollApiException {
|
||||
// int threshold = 30; // 5 minutes
|
||||
int maxAttempts = 12; // 2 minutes
|
||||
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
|
||||
String body = getWithoutParseResponse(url);
|
||||
if (!body.contains(TaskState.PENDING)) {
|
||||
logger.debug("waitGetWithoutParseResponse : result {}", body);
|
||||
return body;
|
||||
}
|
||||
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
logger.error(e);
|
||||
e.printStackTrace();
|
||||
throw new BackrollApiException();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean isAuthenticated() throws BackrollApiException, IOException {
|
||||
boolean result = false;
|
||||
|
||||
if(StringUtils.isEmpty(backrollToken)) {
|
||||
logger.debug("Backroll Tocken empty : " + backrollToken);
|
||||
return result;
|
||||
}
|
||||
|
||||
try (CloseableHttpClient httpClient = createHttpClient()) {
|
||||
final HttpPost request = new HttpPost(apiURI.toString() + "/auth");
|
||||
CloseableHttpResponse httpResponse = httpClient.execute(request);
|
||||
logger.debug("Backroll Auth response : " + EntityUtils.toString(httpResponse.getEntity()));
|
||||
logger.debug("Backroll Auth response status : " + httpResponse.getStatusLine().getStatusCode());
|
||||
String response = okBody(httpResponse);
|
||||
logger.debug("Backroll Auth response 2 : " + response);
|
||||
logger.debug("Backroll Auth ok");
|
||||
result = true;
|
||||
}catch (NotOkBodyException e) {
|
||||
logger.error(e);
|
||||
e.printStackTrace();
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void closeConnection(CloseableHttpResponse closeableHttpResponse) throws IOException {
|
||||
closeableHttpResponse.close();
|
||||
}
|
||||
|
||||
public void loginIfAuthenticationFailed() throws BackrollApiException, IOException {
|
||||
if (!isAuthenticated()) {
|
||||
login();
|
||||
}
|
||||
}
|
||||
|
||||
protected void login() throws BackrollApiException, IOException {
|
||||
logger.debug("Backroll client - start login");
|
||||
|
||||
CloseableHttpClient httpClient = createHttpClient();
|
||||
CloseableHttpResponse httpResponse = 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", password);
|
||||
params = new StringEntity(jsonBody.toString());
|
||||
request.setEntity(params);
|
||||
|
||||
httpResponse = httpClient.execute(request);
|
||||
try {
|
||||
String response = okBody(httpResponse);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
logger.info("BACKROLL: " + response);
|
||||
LoginApiResponse loginResponse = objectMapper.readValue(response, LoginApiResponse.class);
|
||||
logger.info("ok");
|
||||
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) {
|
||||
logger.error(e);
|
||||
if (httpResponse.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) {
|
||||
logger.error(e);
|
||||
throw new CloudRuntimeException("Failed to authenticate Backroll API service due to:" + e.getMessage());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
logger.error(e);
|
||||
throw new CloudRuntimeException("Failed to authenticate Backroll API service due to:" + e.getMessage());
|
||||
}
|
||||
finally {
|
||||
closeConnection(httpResponse);
|
||||
}
|
||||
logger.debug("Backroll client - end login");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# 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.
|
||||
name=backroll-backup
|
||||
parent=backup
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
|
||||
>
|
||||
<bean id="backrollBackupRecoveryDriver" class="org.apache.cloudstack.backup.BackrollBackupProvider">
|
||||
<property name="name" value="backroll" />
|
||||
</bean>
|
||||
</beans>
|
||||
|
|
@ -0,0 +1,394 @@
|
|||
// 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 static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.BackrollClient;
|
||||
import org.apache.cloudstack.backup.backroll.utils.BackrollApiException;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollOffering;
|
||||
import org.apache.cloudstack.backup.Backup.RestorePoint;
|
||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
|
||||
public class BackrollBackupProviderTest {
|
||||
@Mock
|
||||
BackrollClient clientMock;
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
BackrollBackupProvider backupProvider;
|
||||
|
||||
@Mock
|
||||
BackrollBackupProvider backupProviderMock;
|
||||
|
||||
@Mock
|
||||
VMInstanceDao vmInstanceDao;
|
||||
|
||||
@Mock
|
||||
private ConfigKey<String> BackrollUrlConfigKey;
|
||||
|
||||
@Mock
|
||||
private ConfigKey<String> BackrollAppNameConfigKey;
|
||||
|
||||
@Mock
|
||||
private ConfigKey<String> BackrollPasswordConfigKey;
|
||||
|
||||
@Mock
|
||||
BackupDao backupDao;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
vmInstanceDao = mock(VMInstanceDao.class);
|
||||
clientMock = mock(BackrollClient.class);
|
||||
backupDao = mock(BackupDao.class);
|
||||
backupProvider = new BackrollBackupProvider(backupDao, vmInstanceDao, clientMock, Mockito.mock(Logger.class));
|
||||
backupProvider.BackrollAppNameConfigKey = BackrollAppNameConfigKey;
|
||||
backupProvider.BackrollPasswordConfigKey = BackrollPasswordConfigKey;
|
||||
backupProvider.BackrollUrlConfigKey = BackrollUrlConfigKey;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listBackupOfferings_Test() throws BackrollApiException, IOException {
|
||||
Mockito.doReturn("dummyUrlToRequest").when(clientMock).getBackupOfferingUrl();
|
||||
Mockito.doReturn(Arrays.asList(new BackrollOffering("dummyName", "dummyId"))).when(clientMock)
|
||||
.getBackupOfferings(Mockito.anyString());
|
||||
List<BackupOffering> results = backupProvider.listBackupOfferings(2L);
|
||||
assertTrue(results.size() == 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void takeBackup_Test() throws BackrollApiException, IOException {
|
||||
|
||||
VMInstanceVO vmInstanceVO = new VMInstanceVO();
|
||||
vmInstanceVO.setInstanceName("test");
|
||||
vmInstanceVO.setDataCenterId(2l);
|
||||
vmInstanceVO.setUuid(UUID.randomUUID().toString());
|
||||
vmInstanceVO.setBackupOfferingId(2L);
|
||||
|
||||
Mockito.doReturn("/status/f32092e4-3e8a-461b-8733-ed93e23fa782").when(clientMock)
|
||||
.startBackupJob(Mockito.anyString());
|
||||
Mockito.doReturn(new BackupVO()).when(backupDao).persist(Mockito.any(BackupVO.class));
|
||||
Pair<Boolean, Backup> result = backupProvider.takeBackup(vmInstanceVO);
|
||||
assertTrue(result.first());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restoreBackedUpVolume_Test() {
|
||||
try {
|
||||
backupProvider.restoreBackedUpVolume(new BackupVO(), "dummyString", "dummyString", "dummyString",
|
||||
new Pair<String, VirtualMachine.State>("dummyString", VirtualMachine.State.Shutdown));
|
||||
} catch (Exception e) {
|
||||
assertEquals(CloudRuntimeException.class, e.getClass());
|
||||
String expected = String.format("Backroll plugin does not support this feature");
|
||||
assertEquals(expected, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getConfigKeys_Test() {
|
||||
assertEquals(3, backupProvider.getConfigKeys().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getConfigComponentName_Test() {
|
||||
assertEquals(BackupService.class.getSimpleName(), backupProvider.getConfigComponentName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBackupMetricsEmpty_Test() {
|
||||
assertEquals(backupProvider.getBackupMetrics(2L, Arrays.asList()).size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBackupMetrics_Test() throws BackrollApiException, IOException{
|
||||
|
||||
VMInstanceVO vmInstanceVO = new VMInstanceVO();
|
||||
vmInstanceVO.setInstanceName("test");
|
||||
vmInstanceVO.setDataCenterId(1l);
|
||||
vmInstanceVO.setBackupOfferingId(1l);
|
||||
|
||||
VMInstanceVO vmInstanceVO2 = new VMInstanceVO();
|
||||
vmInstanceVO2.setInstanceName("test2");
|
||||
vmInstanceVO2.setDataCenterId(2l);
|
||||
vmInstanceVO2.setBackupOfferingId(2l);
|
||||
|
||||
VMInstanceVO vmInstanceVO3 = new VMInstanceVO();
|
||||
vmInstanceVO3.setInstanceName("test3");
|
||||
vmInstanceVO3.setDataCenterId(3l);
|
||||
vmInstanceVO3.setBackupOfferingId(3l);
|
||||
|
||||
BackrollBackupMetrics metrics = new BackrollBackupMetrics(5L, 6L);
|
||||
|
||||
Mockito.doReturn(metrics).when(clientMock).getBackupMetrics(Mockito.anyString(), Mockito.anyString());
|
||||
assertEquals(backupProvider.getBackupMetrics(2L, Arrays.asList(vmInstanceVO, vmInstanceVO2, vmInstanceVO3)).size(), 1);
|
||||
|
||||
// Mockito.verify(clientMock, times(3)).getBackupMetrics(Mockito.anyString(), Mockito.anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restoreVMFromBackupTrue_Test() throws BackrollApiException, IOException {
|
||||
VMInstanceVO vmInstanceVO = new VMInstanceVO();
|
||||
vmInstanceVO.setDataCenterId(2l);
|
||||
|
||||
BackupVO backupVo = new BackupVO();
|
||||
backupVo.setExternalId("abc,defgh");
|
||||
|
||||
Mockito.doReturn(true).when(clientMock).restoreVMFromBackup(Mockito.anyString(), Mockito.anyString());
|
||||
|
||||
Boolean result = backupProvider.restoreVMFromBackup(vmInstanceVO, backupVo);
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restoreVMFromBackupFalse_Test() throws BackrollApiException, IOException {
|
||||
VMInstanceVO vmInstanceVO = new VMInstanceVO();
|
||||
vmInstanceVO.setDataCenterId(2l);
|
||||
|
||||
BackupVO backupVo = new BackupVO();
|
||||
backupVo.setExternalId("abc,defgh");
|
||||
|
||||
Mockito.doReturn(false).when(clientMock).restoreVMFromBackup(Mockito.anyString(), Mockito.anyString());
|
||||
|
||||
try {
|
||||
backupProvider.restoreVMFromBackup(vmInstanceVO, backupVo);
|
||||
} catch (Exception e) {
|
||||
assertEquals(CloudRuntimeException.class, e.getClass());
|
||||
String expected = String.format("Failed to restore VM from Backup");
|
||||
assertEquals(expected, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDescription_Test() {
|
||||
assertEquals("Backroll Backup Plugin", backupProvider.getDescription());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidProviderOffering_Test() {
|
||||
assertTrue(backupProvider.isValidProviderOffering(2L, "dummyString"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getName_Test() {
|
||||
assertEquals("backroll", backupProvider.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assignVMToBackupOffering_Test() {
|
||||
VMInstanceVO vmInstanceVO = new VMInstanceVO();
|
||||
BackrollOffering backrollOf = new BackrollOffering("dummyName", UUID.randomUUID().toString());
|
||||
assertTrue(backupProvider.assignVMToBackupOffering(vmInstanceVO, backrollOf));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeVMFromBackupOffering_Test() {
|
||||
assertTrue(backupProvider.removeVMFromBackupOffering(new VMInstanceVO()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void willDeleteBackupsOnOfferingRemoval_Test() {
|
||||
assertFalse(backupProvider.willDeleteBackupsOnOfferingRemoval());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getClient_Test() {
|
||||
BackrollClient client = backupProvider.getClient(2L);
|
||||
assertEquals(client, clientMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteBackupTestSuccess_Test() throws BackrollApiException, IOException {
|
||||
VMInstanceVO vmInstanceVO = new VMInstanceVO();
|
||||
vmInstanceVO.setInstanceName("test");
|
||||
vmInstanceVO.setDataCenterId(2l);
|
||||
vmInstanceVO.setUuid(UUID.randomUUID().toString());
|
||||
BackupVO backup = new BackupVO();
|
||||
backup.setVmId(1l);
|
||||
backup.setExternalId("abc,defgh");
|
||||
backup.setType("Full");
|
||||
backup.setZoneId(2l);
|
||||
backup.setStatus(Backup.Status.Removed);
|
||||
Boolean deleteBackupResponse = true;
|
||||
Mockito.doReturn(vmInstanceVO).when(vmInstanceDao).findByIdIncludingRemoved(Mockito.anyLong());
|
||||
Mockito.doReturn(deleteBackupResponse).when(clientMock).deleteBackup(Mockito.anyString(), Mockito.anyString());
|
||||
Mockito.doReturn(new BackupVO()).when(backupDao).persist(Mockito.any(BackupVO.class));
|
||||
boolean result = backupProvider.deleteBackup(backup, true);
|
||||
assertEquals(true, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteBackupBackinUp_Test() {
|
||||
BackupVO backup = new BackupVO();
|
||||
backup.setStatus(Backup.Status.BackingUp);
|
||||
try {
|
||||
backupProvider.deleteBackup(backup, false);
|
||||
} catch (Exception e) {
|
||||
assertEquals(CloudRuntimeException.class, e.getClass());
|
||||
String expected = String.format("You can't delete a backup while it still BackingUp");
|
||||
assertEquals(expected, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listRestorePoints_Test() throws BackrollApiException, IOException {
|
||||
List<RestorePoint> rps = Arrays.asList(new RestorePoint("rp1", new Date(), "incremental"),
|
||||
new RestorePoint("rp2", new Date(), "incremental"),
|
||||
new RestorePoint("rp3", new Date(), "incremental"),
|
||||
new RestorePoint("rp4", new Date(), "incremental"));
|
||||
|
||||
VMInstanceVO vmInstanceVO3 = new VMInstanceVO();
|
||||
vmInstanceVO3.setInstanceName("test3");
|
||||
vmInstanceVO3.setDataCenterId(3l);
|
||||
vmInstanceVO3.setBackupOfferingId(3l);
|
||||
|
||||
Mockito.doReturn(rps).when(clientMock).listRestorePoints(Mockito.anyString());
|
||||
|
||||
List<RestorePoint> rPoints = backupProvider.listRestorePoints(vmInstanceVO3);
|
||||
|
||||
assertEquals(rPoints.size(), rps.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNewBackupEntryForRestorePoint_Test() throws BackrollApiException, IOException {
|
||||
RestorePoint restorePoint = new RestorePoint("restore-123", new Date(), "INCREMENTAL");
|
||||
|
||||
VMInstanceVO vm = new VMInstanceVO();
|
||||
vm.setUuid("vm-uuid-456");
|
||||
vm.setDataCenterId(2L);
|
||||
vm.setBackupOfferingId(3L);
|
||||
|
||||
Backup.Metric metric = null;
|
||||
|
||||
BackrollBackupMetrics backupMetrics = new BackrollBackupMetrics(100L, 200L);
|
||||
Mockito.doReturn(backupMetrics).when(clientMock).getBackupMetrics(vm.getUuid(), restorePoint.getId());
|
||||
|
||||
BackupVO savedBackup = new BackupVO();
|
||||
Mockito.doReturn(savedBackup).when(backupDao).persist(Mockito.any(BackupVO.class));
|
||||
|
||||
Backup result = backupProvider.createNewBackupEntryForRestorePoint(restorePoint, vm, metric);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(vm.getId(), result.getVmId());
|
||||
assertEquals(restorePoint.getId(), result.getExternalId());
|
||||
assertEquals("INCREMENTAL", result.getType());
|
||||
assertEquals(restorePoint.getCreated(), result.getDate());
|
||||
assertEquals(Backup.Status.BackedUp, result.getStatus());
|
||||
assertEquals(vm.getBackupOfferingId(), (Long)result.getBackupOfferingId());
|
||||
assertEquals(vm.getAccountId(), result.getAccountId());
|
||||
assertEquals(vm.getDomainId(), result.getDomainId());
|
||||
assertEquals(vm.getDataCenterId(), result.getZoneId());
|
||||
assertEquals((Long)backupMetrics.getSize(), result.getSize());
|
||||
assertEquals((Long)backupMetrics.getDeduplicated(), result.getProtectedSize());
|
||||
|
||||
Mockito.verify(clientMock).getBackupMetrics(vm.getUuid(), restorePoint.getId());
|
||||
Mockito.verify(backupDao).persist(Mockito.any(BackupVO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNewBackupEntryForRestorePoint_WithMetric_Test() throws BackrollApiException, IOException {
|
||||
RestorePoint restorePoint = new RestorePoint("restore-789", new Date(), "INCREMENTAL");
|
||||
|
||||
VMInstanceVO vm = new VMInstanceVO();
|
||||
vm.setUuid("vm-uuid-789");
|
||||
vm.setDataCenterId(3L);
|
||||
vm.setBackupOfferingId(4L);
|
||||
|
||||
Backup.Metric metric = new Backup.Metric(150L, 250L);
|
||||
|
||||
BackupVO savedBackup = new BackupVO();
|
||||
Mockito.doReturn(savedBackup).when(backupDao).persist(Mockito.any(BackupVO.class));
|
||||
|
||||
Backup result = backupProvider.createNewBackupEntryForRestorePoint(restorePoint, vm, metric);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(vm.getId(), result.getVmId());
|
||||
assertEquals(restorePoint.getId(), result.getExternalId());
|
||||
assertEquals("INCREMENTAL", result.getType());
|
||||
assertEquals(restorePoint.getCreated(), result.getDate());
|
||||
assertEquals(Backup.Status.BackedUp, result.getStatus());
|
||||
assertEquals(vm.getBackupOfferingId(), (Long)result.getBackupOfferingId());
|
||||
assertEquals(vm.getAccountId(), result.getAccountId());
|
||||
assertEquals(vm.getDomainId(), result.getDomainId());
|
||||
assertEquals(vm.getDataCenterId(), result.getZoneId());
|
||||
|
||||
Mockito.verify(backupDao).persist(Mockito.any(BackupVO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNewBackupEntryForRestorePoint_BackrollApiException_Test()
|
||||
throws BackrollApiException, IOException {
|
||||
|
||||
RestorePoint restorePoint =new RestorePoint("restore-404", new Date(), "INCREMENTAL");
|
||||
|
||||
VMInstanceVO vm = new VMInstanceVO();
|
||||
vm.setUuid("vm-uuid-404");
|
||||
vm.setDataCenterId(4L);
|
||||
vm.setBackupOfferingId(5L);
|
||||
|
||||
Backup.Metric metric = null;
|
||||
|
||||
Mockito.doThrow(new BackrollApiException()).when(clientMock).getBackupMetrics(vm.getUuid(),
|
||||
restorePoint.getId());
|
||||
|
||||
backupProvider.createNewBackupEntryForRestorePoint(restorePoint, vm, metric);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createNewBackupEntryForRestorePoint_IOException_Test() throws BackrollApiException, IOException {
|
||||
|
||||
RestorePoint restorePoint = new RestorePoint("restore-500", new Date(), "INCREMENTAL");
|
||||
|
||||
VMInstanceVO vm = new VMInstanceVO();
|
||||
vm.setUuid("vm-uuid-500");
|
||||
vm.setDataCenterId(5L);
|
||||
vm.setBackupOfferingId(6L);
|
||||
|
||||
Backup.Metric metric = null;
|
||||
|
||||
Mockito.doThrow(new IOException("IO Error")).when(clientMock).getBackupMetrics(vm.getUuid(),
|
||||
restorePoint.getId());
|
||||
|
||||
backupProvider.createNewBackupEntryForRestorePoint(restorePoint, vm, metric);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
// 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.backup.Backup;
|
||||
import org.apache.cloudstack.backup.Backup.Metric;
|
||||
import org.apache.cloudstack.backup.BackupOffering;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollTaskStatus;
|
||||
import org.apache.cloudstack.backup.backroll.model.BackrollVmBackup;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.BackrollTaskRequestResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.TaskState;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.archive.BackrollArchiveResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.archive.BackrollArchivesResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.archive.BackrollBackupsFromVMResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.backup.BackrollBackupMetricsResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.backup.BackupMetricsInfo;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.BackrollVmMetricsResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.CacheStats;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.InfosCache;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.MetricsInfos;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups.VirtualMachineBackupsResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.policy.BackrollBackupPolicyResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.policy.BackupPoliciesResponse;
|
||||
import org.apache.cloudstack.backup.backroll.utils.BackrollApiException;
|
||||
import org.apache.cloudstack.backup.backroll.utils.BackrollHttpClientProvider;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.joda.time.DateTime;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.tomakehurst.wiremock.junit.WireMockRule;
|
||||
|
||||
public class BackrollClientTest {
|
||||
private BackrollClient client;
|
||||
|
||||
@Mock
|
||||
private BackrollHttpClientProvider backrollHttpClientProviderMock;
|
||||
|
||||
@Rule
|
||||
public WireMockRule wireMockRule = new WireMockRule(9399);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
backrollHttpClientProviderMock = mock(BackrollHttpClientProvider.class);
|
||||
client = new BackrollClient(backrollHttpClientProviderMock);
|
||||
client.logger = Mockito.mock(Logger.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAllBackupsfromVirtualMachine_test() throws Exception {
|
||||
String vmId = "TEST-vm_uuid";
|
||||
String virtualMachineResponseString = "{ \"state\": \"SUCCESS\", \"info\": { \"archives\": [ { \"archive\": \"ROOT-00000\", \"barchive\": \"ROOT-00000\", \"id\": \"25d55ad283aa400af464c76d713c07ad7d163abdd3b8fbcdbdc46b827e5e0457\", \"name\": \"ROOT-00000\", \"start\": \"2024-11-08T18:24:48.000000\", \"time\": \"2024-11-08T18:24:48.000000\" } ], \"encryption\": { \"mode\": \"none\" }, \"repository\": { \"id\": \"36a11ebc0775a097c927735cc7015d19be7309be69fc15b896c5b1fd87fcbd79\", \"last_modified\": \"2024-11-29T09:53:09.000000\", \"location\": \"/mnt/backup/backup1\" } } }";
|
||||
BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse();
|
||||
backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
VirtualMachineBackupsResponse virtualMachineBackupsResponseMock = new ObjectMapper()
|
||||
.readValue(virtualMachineResponseString, VirtualMachineBackupsResponse.class);
|
||||
|
||||
// Mocking client responses
|
||||
doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock)
|
||||
.get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any());
|
||||
doReturn(virtualMachineBackupsResponseMock).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(),
|
||||
Mockito.any());
|
||||
// Run the method under test
|
||||
List<BackrollVmBackup> backupsTestList = client.getAllBackupsfromVirtualMachine(vmId);
|
||||
|
||||
// Check results
|
||||
assertEquals(1, backupsTestList.size()); // Should be 1 based on provided mock data
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBackupMetrics_Test() throws IOException, BackrollApiException {
|
||||
BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse();
|
||||
backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
BackrollBackupMetricsResponse mockResponse = new BackrollBackupMetricsResponse();
|
||||
mockResponse.info = new BackupMetricsInfo();
|
||||
mockResponse.info.originalSize = "1000";
|
||||
mockResponse.info.deduplicatedSize = "800";
|
||||
|
||||
doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock)
|
||||
.get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any());
|
||||
doReturn(mockResponse).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(), Mockito.any());
|
||||
|
||||
BackrollBackupMetrics metrics = client.getBackupMetrics("dummyVMId", "dummyBackupId");
|
||||
|
||||
assertEquals(1000L, metrics.getSize());
|
||||
assertEquals(800L, metrics.getDeduplicated());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getVirtualMachineMetrics_Test() throws IOException, BackrollApiException {
|
||||
BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse();
|
||||
backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
|
||||
BackrollVmMetricsResponse mockResponse = new BackrollVmMetricsResponse();
|
||||
mockResponse.state = TaskState.SUCCESS;
|
||||
mockResponse.infos = new MetricsInfos();
|
||||
mockResponse.infos.cache = new InfosCache();
|
||||
mockResponse.infos.cache.stats = new CacheStats();
|
||||
mockResponse.infos.cache.stats.totalSize = "10000";
|
||||
|
||||
doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock)
|
||||
.get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any());
|
||||
doReturn(mockResponse).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(), Mockito.any());
|
||||
|
||||
Metric metrics = client.getVirtualMachineMetrics("dummyVMId");
|
||||
|
||||
assertEquals(10000L, (long) metrics.getBackupSize());
|
||||
assertEquals(10000L, (long) metrics.getDataSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteBackup_Test() throws IOException, BackrollApiException {
|
||||
BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse();
|
||||
backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
|
||||
BackrollBackupsFromVMResponse mockResponse = new BackrollBackupsFromVMResponse();
|
||||
mockResponse.state = TaskState.SUCCESS;
|
||||
mockResponse.archives = new BackrollArchivesResponse();
|
||||
mockResponse.archives.archives = Arrays.asList(new BackrollArchiveResponse());
|
||||
|
||||
doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock)
|
||||
.delete(Mockito.matches(".*/virtualmachines/.*"), Mockito.any());
|
||||
doReturn(mockResponse).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(), Mockito.any());
|
||||
|
||||
Boolean isBackupDeleted = client.deleteBackup("dummyVMId", "dummyBackUpName");
|
||||
|
||||
assertTrue(isBackupDeleted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkBackupTaskStatusSuccess_Test() throws IOException, BackrollApiException {
|
||||
String backupResponse = "{\"state\":\"SUCCESS\",\"info\":\"test\"}";
|
||||
doReturn(backupResponse).when(backrollHttpClientProviderMock)
|
||||
.getWithoutParseResponse(Mockito.matches(".*status/.*"));
|
||||
|
||||
BackrollTaskStatus status = client.checkBackupTaskStatus("dummytaskid");
|
||||
|
||||
assertEquals(TaskState.SUCCESS, status.getState());
|
||||
assertEquals("test", status.getInfo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkBackupTaskStatus_Test() throws IOException, BackrollApiException {
|
||||
String backupResponse = "{\"state\":\"PENDING\",\"current\":0,\"total\":1,\"status\":\"Pending...\"}";
|
||||
doReturn(backupResponse).when(backrollHttpClientProviderMock)
|
||||
.getWithoutParseResponse(Mockito.matches(".*/status/.*"));
|
||||
|
||||
BackrollTaskStatus status = client.checkBackupTaskStatus("dummytaskid");
|
||||
|
||||
assertEquals(TaskState.PENDING, status.getState());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restoreVMFromBackup_Test() throws IOException, BackrollApiException {
|
||||
BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse();
|
||||
backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
String resultMock = "SUCCESS WOW YOUHOU";
|
||||
doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock)
|
||||
.post(Mockito.matches(".*/tasks/restore/.*"), Mockito.any(JSONObject.class), Mockito.any());
|
||||
doReturn(resultMock).when(backrollHttpClientProviderMock).waitGetWithoutParseResponse(Mockito.anyString());
|
||||
|
||||
Boolean isRestoreOk = client.restoreVMFromBackup("dummyVMId", "dummyBackUpName");
|
||||
|
||||
assertTrue(isRestoreOk);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startBackupJob_Test() throws IOException, BackrollApiException {
|
||||
|
||||
BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse();
|
||||
backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock)
|
||||
.post(Mockito.matches(".*/tasks/singlebackup/.*"), Mockito.nullable(JSONObject.class), Mockito.any());
|
||||
|
||||
String response = client.startBackupJob("dummyJobId");
|
||||
|
||||
assertEquals("/status/f32092e4-3e8a-461b-8733-ed93e23fa782", response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBackupOfferingUrl_Test() throws IOException, BackrollApiException {
|
||||
BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse();
|
||||
backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock)
|
||||
.get(Mockito.matches(".*/backup_policies.*"), Mockito.any());
|
||||
|
||||
String response = client.getBackupOfferingUrl();
|
||||
|
||||
assertEquals("/status/f32092e4-3e8a-461b-8733-ed93e23fa782", response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBackupOfferings_Test() throws BackrollApiException, IOException {
|
||||
|
||||
BackrollBackupPolicyResponse policy1 = new BackrollBackupPolicyResponse();
|
||||
policy1.name = "User-Policy-1";
|
||||
policy1.retentionDay = 6;
|
||||
policy1.schedule = "0 0 * * 1";
|
||||
policy1.retentionMonth = 0;
|
||||
policy1.storage = "f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
policy1.enabled = false;
|
||||
policy1.description = "User's policy 1 description";
|
||||
policy1.id = "f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
policy1.retentionWeek = 0;
|
||||
policy1.retentionYear = 0;
|
||||
policy1.externalHook = null;
|
||||
|
||||
BackrollBackupPolicyResponse policy2 = new BackrollBackupPolicyResponse();
|
||||
policy1.name = "User-Policy-2";
|
||||
policy1.retentionDay = 6;
|
||||
policy1.schedule = "0 0 * * 1";
|
||||
policy1.retentionMonth = 0;
|
||||
policy1.storage = "f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
policy1.enabled = false;
|
||||
policy1.description = "User's policy 2 description";
|
||||
policy1.id = "f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
policy1.retentionWeek = 0;
|
||||
policy1.retentionYear = 0;
|
||||
policy1.externalHook = null;
|
||||
BackupPoliciesResponse backupPoliciesResponseMock = new BackupPoliciesResponse();
|
||||
backupPoliciesResponseMock.backupPolicies = Arrays.asList(policy1, policy2);
|
||||
|
||||
doReturn(backupPoliciesResponseMock).when(backrollHttpClientProviderMock)
|
||||
.waitGet(Mockito.matches("/status/f32092e4-3e8a-461b-8733-ed93e23fa782"), Mockito.any());
|
||||
|
||||
List<BackupOffering> response = client.getBackupOfferings("/status/f32092e4-3e8a-461b-8733-ed93e23fa782");
|
||||
|
||||
assertEquals(response.size(), 2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listRestorePoints_Test() throws BackrollApiException, IOException {
|
||||
String vmId = "vm-123";
|
||||
|
||||
String virtualMachineResponseString = "{ \"state\": \"SUCCESS\", \"info\": { \"archives\": [ { \"archive\": \"ROOT-00000\", \"barchive\": \"ROOT-00000\", \"id\": \"25d55ad283aa400af464c76d713c07ad7d163abdd3b8fbcdbdc46b827e5e0457\", \"name\": \"ROOT-00000\", \"start\": \"2024-11-08T18:24:48.000000\", \"time\": \"2024-11-08T18:24:48.000000\" } ], \"encryption\": { \"mode\": \"none\" }, \"repository\": { \"id\": \"36a11ebc0775a097c927735cc7015d19be7309be69fc15b896c5b1fd87fcbd79\", \"last_modified\": \"2024-11-29T09:53:09.000000\", \"location\": \"/mnt/backup/backup1\" } } }";
|
||||
BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse();
|
||||
backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782";
|
||||
VirtualMachineBackupsResponse virtualMachineBackupsResponseMock = new ObjectMapper()
|
||||
.readValue(virtualMachineResponseString, VirtualMachineBackupsResponse.class);
|
||||
|
||||
doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock)
|
||||
.get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any());
|
||||
doReturn(virtualMachineBackupsResponseMock).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(),
|
||||
Mockito.any());
|
||||
|
||||
List<Backup.RestorePoint> restorePoints = client.listRestorePoints(vmId);
|
||||
|
||||
assertNotNull(restorePoints);
|
||||
assertEquals(1, restorePoints.size());
|
||||
|
||||
Backup.RestorePoint rp1 = restorePoints.get(0);
|
||||
assertEquals("ROOT-00000", rp1.getId());
|
||||
assertEquals(new DateTime("2024-11-08T18:24:48.000000").toDate(), rp1.getCreated());
|
||||
assertEquals("INCREMENTAL", rp1.getType());
|
||||
|
||||
Mockito.verify(backrollHttpClientProviderMock).get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any());
|
||||
Mockito.verify(backrollHttpClientProviderMock).waitGet(anyString(), Mockito.any());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,315 @@
|
|||
// 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.utils;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.cloudstack.backup.backroll.model.response.api.LoginApiResponse;
|
||||
import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups.VirtualMachineBackupsResponse;
|
||||
import org.apache.cloudstack.backup.backroll.utils.BackrollHttpClientProvider.NotOkBodyException;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
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;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
import org.apache.cloudstack.utils.security.SSLUtils;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
|
||||
public class BackrollHttpClientProviderTest {
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
BackrollHttpClientProvider backupHttpClientProvider;
|
||||
|
||||
@Mock
|
||||
private CloseableHttpClient httpClient;
|
||||
|
||||
@Mock
|
||||
private CloseableHttpResponse response;
|
||||
|
||||
@Mock
|
||||
private RequestConfig config;
|
||||
|
||||
@Spy
|
||||
private SSLUtils sslUtils;
|
||||
|
||||
@Spy
|
||||
private HttpClientBuilder httpClientBuilder;
|
||||
|
||||
@Mock
|
||||
private SSLContext sslContext;
|
||||
|
||||
@Mock
|
||||
private SSLConnectionSocketFactory sslConnectionSocketFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
backupHttpClientProvider = BackrollHttpClientProvider.createProvider(backupHttpClientProvider,
|
||||
"http://api.backup.demo.ccc:5050/api/v1", "backroll-api", "VviX8dALauSyYJMqVYJqf3UyZOpO3joS", true,
|
||||
300, 600);
|
||||
}
|
||||
|
||||
private void defaultTestHttpClient(String path)
|
||||
throws BackrollApiException, ClientProtocolException, IOException, NotOkBodyException {
|
||||
|
||||
LoginApiResponse responseLogin = new LoginApiResponse();
|
||||
responseLogin.accessToken = "dummyToken";
|
||||
responseLogin.expiresIn = 3600;
|
||||
responseLogin.notBeforePolicy = "dummyNotBeforePolicy";
|
||||
responseLogin.refreshExpiresIn = "7200";
|
||||
responseLogin.scope = "dummyScope";
|
||||
|
||||
String virtualMachineResponseString = "{ \"state\": \"SUCCESS\", \"info\": { \"archives\": [ { \"archive\": \"ROOT-00000\", \"barchive\": \"ROOT-00000\", \"id\": \"25d55ad283aa400af464c76d713c07ad7d163abdd3b8fbcdbdc46b827e5e0457\", \"name\": \"ROOT-00000\", \"start\": \"2024-11-08T18:24:48.000000\", \"time\": \"2024-11-08T18:24:48.000000\" } ], \"encryption\": { \"mode\": \"none\" }, \"repository\": { \"id\": \"36a11ebc0775a097c927735cc7015d19be7309be69fc15b896c5b1fd87fcbd79\", \"last_modified\": \"2024-11-29T09:53:09.000000\", \"location\": \"/mnt/backup/backup1\" } } }";
|
||||
|
||||
CloseableHttpResponse response2 = mock(CloseableHttpResponse.class);
|
||||
StatusLine statusLine = mock(StatusLine.class);
|
||||
|
||||
doReturn(httpClient).when(backupHttpClientProvider).createHttpClient();
|
||||
doReturn(response).when(httpClient)
|
||||
.execute(argThat(argument -> argument != null && argument.getURI().toString().contains("login")));
|
||||
|
||||
doReturn(response2).when(httpClient)
|
||||
.execute(argThat(argument -> argument != null && argument.getURI().toString().contains(path)));
|
||||
|
||||
doReturn(new ObjectMapper().writeValueAsString(responseLogin)).when(backupHttpClientProvider).okBody(response);
|
||||
doReturn(virtualMachineResponseString).when(backupHttpClientProvider).okBody(response2);
|
||||
|
||||
doReturn(statusLine).when(response).getStatusLine();
|
||||
doReturn(HttpStatus.SC_OK).when(statusLine).getStatusCode();
|
||||
|
||||
doNothing().when(response).close();
|
||||
|
||||
doReturn(new StringEntity("{\"mockKey\": \"mockValue\"}", ContentType.APPLICATION_JSON)).when(response)
|
||||
.getEntity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateHttpClient_WithValidateCertificateTrue()
|
||||
throws KeyManagementException, NoSuchAlgorithmException, URISyntaxException, BackrollApiException {
|
||||
backupHttpClientProvider = BackrollHttpClientProvider.createProvider(backupHttpClientProvider,
|
||||
"http://api.backup.demo.ccc:5050/api/v1", "backroll-api", "VviX8dALauSyYJMqVYJqf3UyZOpO3joS", true,
|
||||
300, 600);
|
||||
|
||||
// Mock HttpClientBuilder
|
||||
HttpClientBuilder mockBuilder = mock(HttpClientBuilder.class);
|
||||
try (MockedStatic<HttpClientBuilder> utilities = Mockito.mockStatic(HttpClientBuilder.class)) {
|
||||
utilities.when(HttpClientBuilder::create).thenReturn(mockBuilder);
|
||||
when(mockBuilder.setDefaultRequestConfig(config)).thenReturn(mockBuilder);
|
||||
when(mockBuilder.build()).thenReturn(httpClient);
|
||||
}
|
||||
|
||||
// Test the method
|
||||
CloseableHttpClient client = backupHttpClientProvider.createHttpClient();
|
||||
|
||||
// Verify and assert
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateHttpClient_WithValidateCertificateFalse()
|
||||
throws KeyManagementException, NoSuchAlgorithmException, URISyntaxException, BackrollApiException {
|
||||
backupHttpClientProvider = BackrollHttpClientProvider.createProvider(backupHttpClientProvider,
|
||||
"http://api.backup.demo.ccc:5050/api/v1", "backroll-api", "VviX8dALauSyYJMqVYJqf3UyZOpO3joS", false,
|
||||
300, 600);
|
||||
|
||||
// Mock HttpClientBuilder
|
||||
HttpClientBuilder mockBuilder = mock(HttpClientBuilder.class);
|
||||
try (MockedStatic<HttpClientBuilder> utilities = Mockito.mockStatic(HttpClientBuilder.class)) {
|
||||
utilities.when(HttpClientBuilder::create).thenReturn(mockBuilder);
|
||||
when(mockBuilder.setDefaultRequestConfig(config)).thenReturn(mockBuilder);
|
||||
when(mockBuilder.setSSLSocketFactory(any(SSLConnectionSocketFactory.class))).thenReturn(mockBuilder);
|
||||
when(mockBuilder.build()).thenReturn(httpClient);
|
||||
}
|
||||
|
||||
// Test the method
|
||||
CloseableHttpClient client = backupHttpClientProvider.createHttpClient();
|
||||
|
||||
// Verify and assert
|
||||
assertNotNull(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void NotOkBodyException_Test(){
|
||||
BackrollHttpClientProvider.NotOkBodyException exception = backupHttpClientProvider.new NotOkBodyException();
|
||||
assertNotNull(exception);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void get_Test_success() throws Exception {
|
||||
// Arrange
|
||||
String path = "/test";
|
||||
defaultTestHttpClient(path);
|
||||
|
||||
// Act
|
||||
VirtualMachineBackupsResponse result = backupHttpClientProvider.get(path,
|
||||
VirtualMachineBackupsResponse.class);
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
verify(backupHttpClientProvider, times(2)).okBody(Mockito.any(CloseableHttpResponse.class));
|
||||
verify(httpClient, times(1)).execute(Mockito.any(HttpPost.class));
|
||||
verify(httpClient, times(1)).execute(Mockito.any(HttpGet.class));
|
||||
verify(response, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete_Test_success() throws Exception {
|
||||
// Arrange
|
||||
String path = "/test";
|
||||
defaultTestHttpClient(path);
|
||||
|
||||
// Act
|
||||
VirtualMachineBackupsResponse result = backupHttpClientProvider.delete(path,
|
||||
VirtualMachineBackupsResponse.class);
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
verify(backupHttpClientProvider, times(2)).okBody(Mockito.any(CloseableHttpResponse.class));
|
||||
verify(httpClient, times(1)).execute(Mockito.any(HttpPost.class));
|
||||
verify(httpClient, times(1)).execute(Mockito.any(HttpDelete.class));
|
||||
verify(response, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void okBody_Test_success() throws BackrollApiException, IOException, NotOkBodyException {
|
||||
StatusLine statusLine = mock(StatusLine.class);
|
||||
doReturn(statusLine).when(response).getStatusLine();
|
||||
doReturn(HttpStatus.SC_OK).when(statusLine).getStatusCode();
|
||||
doReturn(new StringEntity("{\"mockKey\": \"mockValue\"}", ContentType.APPLICATION_JSON)).when(response)
|
||||
.getEntity();
|
||||
doNothing().when(response).close();
|
||||
|
||||
String result = backupHttpClientProvider.okBody(response);
|
||||
assertNotNull(result);
|
||||
}
|
||||
|
||||
@Test(expected = BackrollHttpClientProvider.NotOkBodyException.class)
|
||||
public void okBody_Test_Error() throws BackrollApiException, IOException, NotOkBodyException {
|
||||
StatusLine statusLine = mock(StatusLine.class);
|
||||
doReturn(statusLine).when(response).getStatusLine();
|
||||
doReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR).when(statusLine).getStatusCode();
|
||||
|
||||
backupHttpClientProvider.okBody(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waitGet_Test() throws Exception {
|
||||
String path = "/test";
|
||||
defaultTestHttpClient(path);
|
||||
|
||||
// Act
|
||||
VirtualMachineBackupsResponse result = backupHttpClientProvider.waitGet(path,
|
||||
VirtualMachineBackupsResponse.class);
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
verify(backupHttpClientProvider, times(2)).okBody(Mockito.any(CloseableHttpResponse.class));
|
||||
verify(httpClient, times(1)).execute(Mockito.any(HttpGet.class));
|
||||
verify(response, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waitGetWithoutParseResponse_Test() throws Exception {
|
||||
String path = "/test";
|
||||
defaultTestHttpClient(path);
|
||||
|
||||
// Act
|
||||
String result = backupHttpClientProvider.waitGetWithoutParseResponse(path);
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
verify(backupHttpClientProvider, times(2)).okBody(Mockito.any(CloseableHttpResponse.class));
|
||||
verify(httpClient, times(1)).execute(Mockito.any(HttpGet.class));
|
||||
verify(response, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_success() throws Exception {
|
||||
// Arrange
|
||||
String path = "/test";
|
||||
JSONObject json = new JSONObject();
|
||||
defaultTestHttpClient(path);
|
||||
|
||||
// Act
|
||||
VirtualMachineBackupsResponse result = backupHttpClientProvider.post(path, json,
|
||||
VirtualMachineBackupsResponse.class);
|
||||
|
||||
// Assert
|
||||
assertNotNull(result);
|
||||
verify(backupHttpClientProvider, times(2)).okBody(Mockito.any(CloseableHttpResponse.class));
|
||||
verify(httpClient, times(2)).execute(Mockito.any(HttpPost.class));
|
||||
verify(response, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationFailure() throws Exception {
|
||||
doReturn(false).when(backupHttpClientProvider).isAuthenticated();
|
||||
doNothing().when(backupHttpClientProvider).login();
|
||||
backupHttpClientProvider.loginIfAuthenticationFailed();
|
||||
verify(backupHttpClientProvider).login();
|
||||
}
|
||||
|
||||
@Test(expected = BackrollApiException.class)
|
||||
public void testLoginFailure() throws Exception {
|
||||
doReturn(false).when(backupHttpClientProvider).isAuthenticated();
|
||||
doThrow(BackrollApiException.class).when(backupHttpClientProvider).login();
|
||||
backupHttpClientProvider.loginIfAuthenticationFailed();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginSuccess() throws Exception {
|
||||
doReturn(true).when(backupHttpClientProvider).isAuthenticated();
|
||||
backupHttpClientProvider.loginIfAuthenticationFailed();
|
||||
verify(backupHttpClientProvider, times(0)).login();
|
||||
}
|
||||
}
|
||||
|
|
@ -60,6 +60,7 @@
|
|||
<module>api/rate-limit</module>
|
||||
<module>api/solidfire-intg-test</module>
|
||||
|
||||
<module>backup/backroll</module>
|
||||
<module>backup/dummy</module>
|
||||
<module>backup/networker</module>
|
||||
<module>backup/nas</module>
|
||||
|
|
@ -231,6 +232,7 @@
|
|||
</activation>
|
||||
<modules>
|
||||
<module>api/vmware-sioc</module>
|
||||
<module>backup/backroll</module>
|
||||
<module>backup/veeam</module>
|
||||
<module>hypervisors/vmware</module>
|
||||
<module>network-elements/cisco-vnmc</module>
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue