diff --git a/.gitignore b/.gitignore index e638a09ae21..87b56ab5868 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,4 @@ scripts/.pydevproject venv node_modules .vscode +*.bz2 diff --git a/client/pom.xml b/client/pom.xml index cbe45d88b6c..502f889eec6 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -547,6 +547,11 @@ cloud-plugin-integrations-prometheus-exporter ${project.version} + + org.apache.cloudstack + cloud-plugin-backup-backroll + ${project.version} + org.apache.cloudstack cloud-plugin-backup-dummy @@ -1001,6 +1006,11 @@ cloud-plugin-backup-veeam ${project.version} + + org.apache.cloudstack + cloud-plugin-backup-backroll + ${project.version} + diff --git a/developer/utils/conf/db.properties b/developer/utils/conf/db.properties new file mode 100644 index 00000000000..ad9b71ef319 --- /dev/null +++ b/developer/utils/conf/db.properties @@ -0,0 +1,76 @@ +# +# 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. +# + + +# management server clustering parameters, change cluster.node.IP to the machine IP address +# in which the management server is running +cluster.node.IP=127.0.0.1 +cluster.servlet.port=9090 +region.id=1 + +# CloudStack database settings +db.cloud.username=cloud +db.cloud.password=cloud +db.root.password=12345 +db.cloud.host=localhost +db.cloud.driver=jdbc:mysql +db.cloud.port=3306 +db.cloud.name=cloud + +# CloudStack database tuning parameters +db.cloud.maxActive=250 +db.cloud.maxIdle=30 +db.cloud.maxWait=10000 +db.cloud.autoReconnect=true +db.cloud.validationQuery=SELECT 1 +db.cloud.testOnBorrow=true +db.cloud.testWhileIdle=true +db.cloud.timeBetweenEvictionRunsMillis=40000 +db.cloud.minEvictableIdleTimeMillis=240000 +db.cloud.poolPreparedStatements=false +db.cloud.url.params=prepStmtCacheSize=517&cachePrepStmts=true&prepStmtCacheSqlLimit=4096&sessionVariables=sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'&serverTimezone=UTC + +# usage database settings +db.usage.username=cloud +db.usage.password=cloud +db.usage.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.usage.driver=jdbc:mysql +db.usage.port=3306 +db.usage.name=cloud_usage + +# usage database tuning parameters +db.usage.maxActive=100 +db.usage.maxIdle=30 +db.usage.maxWait=10000 +db.usage.autoReconnect=true +db.usage.url.params=serverTimezone=UTC + +# Simulator database settings +db.simulator.username=cloud +db.simulator.password=cloud +db.simulator.host=localhost +# It's not guaranteed that using a different DB provider than the one from the regular cloud DB will work +db.simulator.driver=jdbc:mysql +db.simulator.port=3306 +db.simulator.name=simulator +db.simulator.maxActive=250 +db.simulator.maxIdle=30 +db.simulator.maxWait=10000 +db.simulator.autoReconnect=true diff --git a/plugins/backup/backroll/pom.xml b/plugins/backup/backroll/pom.xml new file mode 100644 index 00000000000..14bbd8c48e4 --- /dev/null +++ b/plugins/backup/backroll/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + cloud-plugin-backup-backroll + Apache CloudStack Plugin - BackRoll Backup and Recovery Plugin by DIMSI + + cloudstack-plugins + org.apache.cloudstack + 4.19.0.0-SNAPSHOT + ../../pom.xml + + + + org.apache.cloudstack + cloud-api + ${project.version} + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.json + json + + + diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java new file mode 100644 index 00000000000..522cb9e24ea --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java @@ -0,0 +1,390 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.backup; + +import java.net.URISyntaxException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.text.MessageFormat; +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.backroll.BackrollClient; +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.dao.BackupDao; +import org.apache.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; + +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; + +public class BackrollBackupProvider extends AdapterBase implements BackupProvider, Configurable { + + private static final Logger s_logger = Logger.getLogger(BackrollBackupProvider.class); + public static final String BACKUP_IDENTIFIER = "-CSBKP-"; + + public ConfigKey BackrollUrlConfigKey = new ConfigKey<>("Advanced", String.class, + "backup.plugin.backroll.config.url", + "http://api.backup.demo.ccc:5050/api/v1", + "Url for backroll plugin by DIMSI", true, ConfigKey.Scope.Zone); + + public ConfigKey BackrollAppNameConfigKey = new ConfigKey<>("Advanced", String.class, + "backup.plugin.backroll.config.appname", + "backroll_api", + "App Name for backroll plugin by DIMSI", true, ConfigKey.Scope.Zone); + + public ConfigKey BackrollPasswordConfigKey = new ConfigKey<>("Advanced", String.class, + "backup.plugin.backroll.config.password", + "VviX8dALauSyYJMqVYJqf3UyZOpO3joS", + "Password for backroll plugin by DIMSI", true, ConfigKey.Scope.Zone); + + private BackrollClient backrollClient; + + @Inject + private BackupDao backupDao; + @Inject + private VMInstanceDao vmInstanceDao; + + @Override + public String getName() { + return "backroll"; + } + + @Override + public String getDescription() { + return "Backroll Backup Plugin"; + } + + @Override + public List listBackupOfferings(Long zoneId) { + s_logger.debug("Listing backup policies on backroll B&R Plugin"); + BackrollClient client = getClient(zoneId); + String urlToRequest = client.getBackupOfferingUrl(); + if(!StringUtils.isEmpty(urlToRequest)){ + return client.getBackupOfferings(urlToRequest); + } + return new ArrayList(); + } + + @Override + public boolean isValidProviderOffering(Long zoneId, String uuid) { + s_logger.info("Checking if backup offering exists on the Backroll Backup Provider"); + return true; + } + + @Override + public boolean assignVMToBackupOffering(VirtualMachine vm, BackupOffering backupOffering) { + s_logger.info("Creating VM backup for VM " + vm.getInstanceName() + " from backup offering " + backupOffering.getName()); + ((VMInstanceVO) vm).setBackupExternalId(backupOffering.getUuid()); + return true; + } + + @Override + public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) { + s_logger.debug("Restoring vm " + vm.getUuid() + "from backup " + backup.getUuid() + " on the backroll Backup Provider"); + boolean isSuccess = getClient(vm.getDataCenterId()).restoreVMFromBackup(vm.getUuid(), getBackupName(backup)); + return isSuccess; + } + + @Override + public Pair restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid) { + s_logger.debug("Restoring volume " + volumeUuid + "from backup " + backup.getUuid() + " on the backroll Backup Provider"); + throw new CloudRuntimeException("Backroll plugin does not support this feature"); + } + + @Override + public Map getBackupMetrics(Long zoneId, List vms) { + final Map metrics = new HashMap<>(); + if (CollectionUtils.isEmpty(vms)) { + s_logger.warn("Unable to get VM Backup Metrics because the list of VMs is empty."); + return metrics; + } + + List vmUuids = vms.stream().filter(Objects::nonNull).map(VirtualMachine::getUuid).collect(Collectors.toList()); + s_logger.debug(String.format("Get Backup Metrics for VMs: [%s].", String.join(", ", vmUuids))); + + for (final VirtualMachine vm : vms) { + if (vm == null) { + continue; + } + + Metric metric = getClient(zoneId).getVirtualMachineMetrics(vm.getUuid()); + s_logger.debug(String.format("Metrics for VM [uuid: %s, name: %s] is [backup size: %s, data size: %s].", vm.getUuid(), + vm.getInstanceName(), metric.getBackupSize(), metric.getDataSize())); + metrics.put(vm, metric); + } + return metrics; + } + + @Override + public boolean removeVMFromBackupOffering(VirtualMachine vm) { + s_logger.info("Removing VM ID " + vm.getUuid() + " from Backrool backup offering "); + + boolean isAnyProblemWhileRemovingBackups = false; + + List backupsInCs = backupDao.listByVmId(null, vm.getId()); + + for (Backup backup : backupsInCs) { + s_logger.debug("Trying to remove backup with id" + backup.getId()); + + if (getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup))) { + var message = MessageFormat.format("Backup {0} deleted in Backroll for virtual machine {1}", backup.getId(), vm.getName()); + s_logger.info(message); + if(!backupDao.remove(backup.getId())){ + isAnyProblemWhileRemovingBackups = true; + } + message = MessageFormat.format("Backup {0} deleted in CS for virtual machine {1}", backup.getId(), vm.getName()); + s_logger.info(message); + } else { + isAnyProblemWhileRemovingBackups = false; + } + } + + if(isAnyProblemWhileRemovingBackups) { + var message = MessageFormat.format("Problems occured while removing some backups for virtual machine {0}", vm.getName()); + s_logger.info(message); + } + return isAnyProblemWhileRemovingBackups; + } + + @Override + public boolean willDeleteBackupsOnOfferingRemoval() { + return false; + } + + @Override + public boolean takeBackup(VirtualMachine vm) { + s_logger.info("Starting backup for VM ID " + vm.getUuid() + " on backroll provider"); + final BackrollClient client = getClient(vm.getDataCenterId()); + + String idBackupTask = client.startBackupJob(vm.getUuid()); + if(!StringUtils.isEmpty(idBackupTask)) { + BackupVO backup = new BackupVO(); + backup.setVmId(vm.getId()); + backup.setExternalId(idBackupTask); + backup.setType("INCREMENTIAL"); + 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()); + return backupDao.persist(backup) != null; + } + return false; + } + + @Override + public void syncBackups(VirtualMachine vm, Backup.Metric metric) { + s_logger.info("Starting sync backup for VM ID " + vm.getUuid() + " on backroll provider"); + + final BackrollClient client = getClient(vm.getDataCenterId()); + List backupsInDb = backupDao.listByVmId(null, vm.getId()); + + for (Backup backup : backupsInDb) { + if(backup.getStatus().equals(Backup.Status.BackingUp)) { + BackrollTaskStatus response = client.checkBackupTaskStatus(backup.getExternalId()); + if(response != null) { + s_logger.debug("backroll backup id: " + backup.getExternalId()); + s_logger.debug("backroll backup status: " + response.getState()); + + BackupVO backupToUpdate = new BackupVO(); + backupToUpdate.setVmId(backup.getVmId()); + backupToUpdate.setExternalId(backup.getExternalId()); + backupToUpdate.setType(backup.getType()); + backupToUpdate.setDate(backup.getDate()); + backupToUpdate.setSize(backup.getSize()); + backupToUpdate.setProtectedSize(backup.getProtectedSize()); + backupToUpdate.setBackupOfferingId(vm.getBackupOfferingId()); + backupToUpdate.setAccountId(backup.getAccountId()); + backupToUpdate.setDomainId(backup.getDomainId()); + backupToUpdate.setZoneId(backup.getZoneId()); + + 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(backup.getExternalId() + "," + response.getInfo()); + + BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , response.getInfo()); + if(backupMetrics != null) { + backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size + backupToUpdate.setProtectedSize(backupMetrics.getSize()); // total size + } + } else { + backupToUpdate.setStatus(Backup.Status.BackingUp); + } + + if(backupDao.persist(backupToUpdate) != null) { + s_logger.info("Backroll mise à jour enregistrée"); + backupDao.remove(backup.getId()); + } + } + } else if(backup.getStatus().equals(Backup.Status.BackedUp) && backup.getSize().equals(0L)) { + String backupId = backup.getExternalId().contains(",") ? backup.getExternalId().split(",")[1] : backup.getExternalId(); + BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , backupId); + if(backupMetrics != null) { + BackupVO backupToUpdate = ((BackupVO) backup); + backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size + backupToUpdate.setProtectedSize(backupMetrics.getSize()); // total size + backupDao.persist(backupToUpdate); + } + } + } + + // Backups synchronisation between Backroll ad CS Db + List backupsFromBackroll = client.getAllBackupsfromVirtualMachine(vm.getUuid()); + backupsInDb = backupDao.listByVmId(null, vm.getId()); + + // insert new backroll backup in CS + for (BackrollVmBackup backupInBackroll : backupsFromBackroll) { + Backup backupToFind = backupsInDb.stream() + .filter(backupInDb -> backupInDb.getExternalId().contains(backupInBackroll.getName())) + .findAny() + .orElse(null); + + if(backupToFind == null) { + BackupVO backupToInsert = new BackupVO(); + backupToInsert.setVmId(vm.getId()); + backupToInsert.setExternalId(backupInBackroll.getId() + "," + backupInBackroll.getName()); + backupToInsert.setType("INCREMENTIAL"); + backupToInsert.setDate(backupInBackroll.getDate()); + backupToInsert.setSize(0L); + backupToInsert.setProtectedSize(0L); + backupToInsert.setStatus(Backup.Status.BackedUp); + backupToInsert.setBackupOfferingId(vm.getBackupOfferingId()); + backupToInsert.setAccountId(vm.getAccountId()); + backupToInsert.setDomainId(vm.getDomainId()); + backupToInsert.setZoneId(vm.getDataCenterId()); + backupDao.persist(backupToInsert); + } + if(backupToFind != null && backupToFind.getStatus() == Backup.Status.Removed) { + BackupVO backupToUpdate = ((BackupVO) backupToFind); + backupToUpdate.setStatus(Backup.Status.BackedUp); + if(backupDao.persist(backupToUpdate) != null) { + s_logger.info("Backroll mise à jour enregistrée"); + backupDao.remove(backupToFind.getId()); + } + } + } + + // delete deleted backroll backup in CS + backupsInDb = backupDao.listByVmId(null, vm.getId()); + for (Backup backup : backupsInDb) { + String backupName = backup.getExternalId().contains(",") ? backup.getExternalId().split(",")[1] : backup.getExternalId(); + BackrollVmBackup backupToFind = backupsFromBackroll.stream() + .filter(backupInBackroll -> backupInBackroll.getName().contains(backupName)) + .findAny() + .orElse(null); + + if(backupToFind == null) { + BackupVO backupToUpdate = ((BackupVO) backup); + backupToUpdate.setStatus(Backup.Status.Removed); + if(backupDao.persist(backupToUpdate) != null) { + s_logger.debug("Backroll suppression enregistrée (sync)"); + } + } + } + } + + @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) { + s_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 { + s_logger.debug("backroll - try delete backup"); + VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId()); + + if(backup.getStatus().equals(Backup.Status.Removed) || backup.getStatus().equals(Backup.Status.Failed)){ + return deleteBackupInDb(backup); + } else { + if (getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup))) { + s_logger.debug("backroll delete backup ok on backroll side"); + return deleteBackupInDb(backup); + } + } + } + return false; + } + + private boolean deleteBackupInDb(Backup backup) { + BackupVO backupToUpdate = ((BackupVO) backup); + backupToUpdate.setStatus(Backup.Status.Removed); + if(backupDao.persist(backupToUpdate) != null) { + s_logger.debug("Backroll backup delete in database"); + return true; + } + return false; + } + + protected BackrollClient getClient(final Long zoneId) { + s_logger.debug("Backroll Provider GetClient"); + try { + if(backrollClient == null){ + s_logger.debug("backroll client null - instanciation of new one "); + backrollClient = new BackrollClient(BackrollUrlConfigKey.valueIn(zoneId), BackrollAppNameConfigKey.valueIn(zoneId), BackrollPasswordConfigKey.valueIn(zoneId), true, 300, 600); + } + return backrollClient; + } catch (URISyntaxException e) { + throw new CloudRuntimeException("Failed to parse Backroll API URL: " + e.getMessage()); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + s_logger.info("Failed to build Backroll API client due to: ", e); + } + throw new CloudRuntimeException("Failed to build Backroll API client"); + } + + private String getBackupName(Backup backup) { + return backup.getExternalId().substring(backup.getExternalId().indexOf(",") + 1); + } +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java new file mode 100644 index 00000000000..2abf5c2522a --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java @@ -0,0 +1,612 @@ +package org.apache.cloudstack.backup.backroll; + +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.ArrayList; +import java.util.List; +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.model.BackrollBackup; +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.api.LoginApiResponse; +import org.apache.cloudstack.backup.backroll.model.response.archive.BackrollArchiveResponse; +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.utils.security.SSLUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +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.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.apache.log4j.Logger; +import org.joda.time.DateTime; +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; +import org.apache.cloudstack.backup.BackupOffering; +import org.apache.cloudstack.backup.Backup.Metric; + +public class BackrollClient { + + private static final Logger LOG = Logger.getLogger(BackrollClient.class); + + private int restoreTimeout; + + private final URI apiURI; + + private final HttpClient httpClient; + + private String backrollToken = null; + private String appname = null; + private String password = null; + + public BackrollClient(final String url, final String appname, final String password, + final boolean validateCertificate, final int timeout, + final int restoreTimeout) + throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { + this.apiURI = new URI(url); + this.restoreTimeout = restoreTimeout; + this.appname = appname; + this.password = password; + + final RequestConfig config = RequestConfig.custom() + .setConnectTimeout(timeout * 1000) + .setConnectionRequestTimeout(timeout * 1000) + .setSocketTimeout(timeout * 1000) + .build(); + + if (!validateCertificate) { + final SSLContext sslcontext = SSLUtils.getSSLContext(); + sslcontext.init(null, new X509TrustManager[] { new TrustAllManager() }, new SecureRandom()); + final SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, + NoopHostnameVerifier.INSTANCE); + this.httpClient = HttpClientBuilder.create() + .setDefaultRequestConfig(config) + .setSSLSocketFactory(factory) + .build(); + } else { + this.httpClient = HttpClientBuilder.create() + .setDefaultRequestConfig(config) + .build(); + } + + if (StringUtils.isEmpty(backrollToken) || !isAuthentificated()) { + login(appname, password); + } + } + + public String startBackupJob(final String jobId) { + LOG.info(String.format("Trying to start backup for Backroll job: %s", jobId)); + + try { + loginIfAuthentificationFailed(); + + final HttpResponse response = post(String.format("/tasks/singlebackup/%s", jobId), null); + if(isResponseOk(response)) { + HttpEntity body = response.getEntity(); + String bodyStr = EntityUtils.toString(body); + BackrollTaskRequestResponse backupTaskRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollTaskRequestResponse.class); + String idBackupTask = backupTaskRequestResponse.location.replace("/api/v1/status/", ""); + EntityUtils.consumeQuietly(response.getEntity()); + return idBackupTask; + } + } catch (final IOException e) { + LOG.error(String.format("Failed to start Backroll backup job due to: %s", e.getMessage())); + } + return null; + } + + public String getBackupOfferingUrl(){ + LOG.info("Trying to list backroll backup policies"); + + loginIfAuthentificationFailed(); + + try { + + final HttpResponse backupPoliciesRequestResponse = get("/backup_policies"); + + if(isResponseOk(backupPoliciesRequestResponse)) { + HttpEntity body = backupPoliciesRequestResponse.getEntity(); + String bodyStr = EntityUtils.toString(body); + BackrollTaskRequestResponse backupTaskRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollTaskRequestResponse.class); + EntityUtils.consumeQuietly(backupPoliciesRequestResponse.getEntity()); + return backupTaskRequestResponse.location.replace("/api/v1", ""); + } + } catch (final IOException e) { + LOG.error(String.format("Failed to list Backroll jobs due to: %s", e.getMessage())); + } + return null; + } + + public List getBackupOfferings(String idTask) { + LOG.info("Trying to list backroll backup policies"); + + loginIfAuthentificationFailed(); + + try { + String bodyStr = waitForGetRequestResponse(idTask); + + BackupPoliciesResponse backupPoliciesResponse = new ObjectMapper().readValue(bodyStr, BackupPoliciesResponse.class); + + final List policies = new ArrayList<>(); + for (final BackrollBackupPolicyResponse policy : backupPoliciesResponse.backupPolicies) { + policies.add(new BackrollOffering(policy.name, policy.id)); + } + return policies; + } catch (final IOException e) { + LOG.error(String.format("Failed to list Backroll jobs due to: %s", e.getMessage())); + } catch (InterruptedException e) { + LOG.error(String.format("Failed to list Backroll jobs due to: %s", e.getMessage())); + } + return new ArrayList(); + } + + public boolean restoreVMFromBackup(final String vmId, final String backupName) { + LOG.info(String.format("Start restore backup with backroll with backup %s for vm %s", backupName, vmId)); + + loginIfAuthentificationFailed(); + + try { + 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) { + LOG.error(String.format("Backroll Error: %s", e.getMessage())); + } + + final HttpResponse response = post(String.format("/tasks/restore/%s", vmId), jsonBody); + LOG.debug(response.toString()); + + if(isResponseOk(response)) { + HttpEntity body = response.getEntity(); + String bodyStr = EntityUtils.toString(body); + LOG.debug(bodyStr); + + BackrollTaskRequestResponse backupTaskRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollTaskRequestResponse.class); + String urlToRequest = backupTaskRequestResponse.location.replace("/api/v1", ""); + EntityUtils.consumeQuietly(response.getEntity()); + + String responseStatus = waitForGetRequestResponse(urlToRequest); + LOG.debug("RESTORE " + responseStatus); + if(responseStatus.contains("SUCCESS")) { + LOG.debug("RESTORE SUCCESS"); + return true; + } else { + return false; + } + } + } catch (final IOException | InterruptedException e) { + LOG.error(String.format("Ouch! Failed to restore VM with Backroll due to: %s", e.getMessage())); + throw new CloudRuntimeException(String.format("Ouch! Failed to restore VM with Backroll due to: %s", e.getMessage())); + } + return false; + } + + public BackrollTaskStatus checkBackupTaskStatus(String taskId) { + LOG.info(String.format("Trying to get backup status for Backroll task: %s", taskId)); + + loginIfAuthentificationFailed(); + + try { + final HttpResponse backupStatusResponse = get("/status/" + taskId); + + if(isResponseOk(backupStatusResponse)) { + BackrollTaskStatus status = new BackrollTaskStatus(); + + HttpEntity body = backupStatusResponse.getEntity(); + String bodyStr = EntityUtils.toString(body); + + if(bodyStr.contains("FAILURE") || bodyStr.contains("PENDING")) { + BackrollBackupStatusResponse backupStatusRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollBackupStatusResponse.class); + EntityUtils.consumeQuietly(backupStatusResponse.getEntity()); + status.setState(backupStatusRequestResponse.state); + } else { + BackrollBackupStatusSuccessResponse backupStatusSuccessRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollBackupStatusSuccessResponse.class); + EntityUtils.consumeQuietly(backupStatusResponse.getEntity()); + status.setState(backupStatusSuccessRequestResponse.state); + status.setInfo(backupStatusSuccessRequestResponse.info); + } + + return status; + } else { + EntityUtils.consumeQuietly(backupStatusResponse.getEntity()); + // throw new CloudRuntimeException("Failed to retrieve backups status for this VM via Backroll"); + LOG.error(String.format("Failed to retrieve backups status for this VM via Backroll")); + } + } catch (final IOException e) { + LOG.error(String.format("Failed to check backups status due to: %s", e.getMessage())); + } + return null; + } + + public boolean deleteBackup(final String vmId, final String backupName) { + LOG.info(String.format("Trying to delete backup %s for vm %s using Backroll", vmId, backupName)); + + loginIfAuthentificationFailed(); + + try { + final HttpResponse response = delete(String.format("/virtualmachines/%s/backups/%s", vmId, backupName)); + LOG.debug(response.toString()); + if(isResponseOk(response)) { + HttpEntity body = response.getEntity(); + String bodyStr = EntityUtils.toString(body); + LOG.debug(bodyStr); + BackrollTaskRequestResponse backupTaskRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollTaskRequestResponse.class); + String urlToRequest = backupTaskRequestResponse.location.replace("/api/v1", ""); + EntityUtils.consumeQuietly(response.getEntity()); + + String responseStatus = waitForGetRequestResponse(urlToRequest); + LOG.debug(responseStatus); + BackrollBackupsFromVMResponse backrollBackupsFromVMResponse = new ObjectMapper().readValue(responseStatus, BackrollBackupsFromVMResponse.class); + if(backrollBackupsFromVMResponse.state.equals("SUCCESS")) { + EntityUtils.consumeQuietly(response.getEntity()); + return true; + } else { + EntityUtils.consumeQuietly(response.getEntity()); + return false; + } + } + EntityUtils.consumeQuietly(response.getEntity()); + return false; + } catch (final IOException | InterruptedException e) { + LOG.error(String.format("Failed to delete backup using Backroll due to: %s", e.getMessage())); + } + return false; + } + + public Metric getVirtualMachineMetrics(final String vmId){ + LOG.info(String.format("Trying to retrieve virtual machine metric from Backroll for vm %s", vmId)); + + loginIfAuthentificationFailed(); + + Metric metric = new Metric(0L,0L); + + try { + + final HttpResponse metricsRequestResponse = get(String.format("/virtualmachines/%s/repository", vmId)); + + if(isResponseOk(metricsRequestResponse)) { + HttpEntity body = metricsRequestResponse.getEntity(); + String bodyStr = EntityUtils.toString(body); + LOG.debug(bodyStr); + BackrollTaskRequestResponse backupTaskRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollTaskRequestResponse.class); + String urlToRequest = backupTaskRequestResponse.location.replace("/api/v1", ""); + LOG.debug(urlToRequest); + EntityUtils.consumeQuietly(metricsRequestResponse.getEntity()); + bodyStr = waitForGetRequestResponse(urlToRequest); + LOG.debug(bodyStr); + + BackrollVmMetricsResponse vmMetricsResponse = new ObjectMapper().readValue(bodyStr, BackrollVmMetricsResponse.class); + + if(vmMetricsResponse != null) { + + if(vmMetricsResponse.state.equals("SUCCESS")) { + LOG.debug("SUCCESS ok"); + if(vmMetricsResponse.infos != null) { + if(vmMetricsResponse.infos.cache != null) { + if(vmMetricsResponse.infos.cache.stats != null) { + CacheStats stats = vmMetricsResponse.infos.cache.stats; + long size = Long.parseLong(stats.totalSize); + return new Metric(size,size); + } + } + } + } + } + + EntityUtils.consumeQuietly(metricsRequestResponse.getEntity()); + } + } catch (final IOException | InterruptedException e) { + LOG.error(String.format("Failed to retrieve virtual machine metrics with Backroll due to: %s", e.getMessage())); + } + + return metric; + } + + public BackrollBackupMetrics getBackupMetrics(String vmId, String backupId) { + LOG.info(String.format("Trying to get backup metrics for VM: %s, and backup: %s", vmId, backupId)); + + loginIfAuthentificationFailed(); + + try { + final HttpResponse backupMetricsResponse = get(String.format("/virtualmachines/%s/backups/%s", vmId, backupId)); + + if(isResponseOk(backupMetricsResponse)) { + HttpEntity body = backupMetricsResponse.getEntity(); + String bodyStr = EntityUtils.toString(body); + + BackrollTaskRequestResponse backupTaskRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollTaskRequestResponse.class); + String urlToRequest = backupTaskRequestResponse.location.replace("/api/v1", ""); + LOG.debug(urlToRequest); + EntityUtils.consumeQuietly(backupMetricsResponse.getEntity()); + bodyStr = waitForGetRequestResponse(urlToRequest); + LOG.debug(bodyStr); + + BackrollBackupMetricsResponse metrics = new ObjectMapper().readValue(bodyStr, BackrollBackupMetricsResponse.class); + EntityUtils.consumeQuietly(backupMetricsResponse.getEntity()); + if(metrics.info != null) { + return new BackrollBackupMetrics(Long.parseLong(metrics.info.originalSize), Long.parseLong(metrics.info.deduplicatedSize)); + } + } else { + EntityUtils.consumeQuietly(backupMetricsResponse.getEntity()); + throw new CloudRuntimeException("Failed to retrieve backups status for this VM via Backroll"); + } + } catch (final IOException | InterruptedException e) { + LOG.error(String.format("Failed to check backups status due to: %s", e.getMessage())); + } + return null; + } + + public List getAllBackupsfromVirtualMachine(String vmId) { + LOG.info(String.format("Trying to retrieve all backups for vm %s", vmId)); + + List backups = new ArrayList(); + + try { + HttpResponse backupsResponse = get(String.format("/virtualmachines/%s/backups", vmId)); + + if(isResponseOk(backupsResponse)) { + HttpEntity body = backupsResponse.getEntity(); + String bodyStr = EntityUtils.toString(body); + + BackrollTaskRequestResponse backupTaskRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollTaskRequestResponse.class); + String urlToRequest = backupTaskRequestResponse.location.replace("/api/v1", ""); + LOG.debug(urlToRequest); + EntityUtils.consumeQuietly(backupsResponse.getEntity()); + + bodyStr = waitForGetRequestResponse(urlToRequest); + + VirtualMachineBackupsResponse response = new ObjectMapper().readValue(bodyStr, VirtualMachineBackupsResponse.class); + EntityUtils.consumeQuietly(backupsResponse.getEntity()); + + if(response.state.equals("SUCCESS")) { + if(response.info.archives.size() > 0) { + for (BackupInfos infos : response.info.archives) { + var dateStart = new DateTime(infos.start); + backups.add(new BackrollVmBackup(infos.id, infos.name, dateStart.toDate())); + } + } + } + } + + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + + return backups; + } + + private HttpResponse post(final String path, final JSONObject json) throws IOException { + String xml = null; + StringEntity params = null; + if (json != null) { + LOG.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 HttpResponse response = httpClient.execute(request); + + LOG.info(String.format("Response received in POST request with body [%s] is: [%s] for URL [%s].", xml, response.toString(), url)); + + return response; + } + + protected HttpResponse get(final String path) throws IOException { + String url = apiURI.toString() + path; + LOG.debug(String.format("Backroll URL %s", url)); + final HttpGet request = new HttpGet(url); + request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + backrollToken); + request.setHeader("Content-type", "application/json"); + final HttpResponse response = httpClient.execute(request); + LOG.debug(String.format("Response received in GET request is: [%s] for URL: [%s].", response.toString(), url)); + return response; + } + + protected HttpResponse delete(final String path) throws IOException { + String url = apiURI.toString() + path; + final HttpDelete request = new HttpDelete(url); + request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + backrollToken); + request.setHeader("Content-type", "application/json"); + final HttpResponse response = httpClient.execute(request); + LOG.debug(String.format("Response received in GET request is: [%s] for URL: [%s].", response.toString(), url)); + return response; + } + + private boolean isResponseOk(final HttpResponse response) { + if((response.getStatusLine().getStatusCode() == HttpStatus.SC_OK || + response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED)) { + return true; + } else { + return false; + } + } + + private boolean isResponseAuthorized(final HttpResponse response) { + return (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK || response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED) ? true : false; + } + + private String waitForGetRequestResponse(String urlToRequest) throws IOException, InterruptedException { + HttpEntity body; + String bodyStr = ""; + int cpt = 0; + //int threshold = 30; // 5 minutes + int threshold = 12; // 2 minutes + + do { + if(cpt == threshold){ + break; + } else { + final HttpResponse response = get(urlToRequest); + LOG.debug("Backroll!!!" + response); + if (isResponseOk(response)) { + + body = response.getEntity(); + bodyStr = EntityUtils.toString(body); + LOG.debug(bodyStr); + EntityUtils.consumeQuietly(response.getEntity()); + } else { + throw new CloudRuntimeException("An error occured with Backroll"); + } + cpt++; + TimeUnit.SECONDS.sleep(10); + } + + } while (bodyStr.contains("PENDING")); + + if(cpt == threshold){ + bodyStr = "ERROR"; + } + + return bodyStr; + } + + private boolean isAuthentificated() { + boolean result = false; + try { + final HttpResponse response = post("/auth", null); + result = isResponseAuthorized(response); + EntityUtils.consumeQuietly(response.getEntity()); + } catch (IOException e) { + LOG.error(String.format("Failed to authentificate to Backroll due to: %s", e.getMessage())); + } + return result; + } + + private void loginIfAuthentificationFailed() { + if(!isAuthentificated()) { + login(appname, password); + } + } + + private void login(final String appname, final String appsecret) { + LOG.info("Backroll client - start login"); + final HttpPost request = new HttpPost(apiURI.toString() + "/login"); + + request.addHeader("content-type", "application/json"); + + JSONObject jsonBody = new JSONObject(); + StringEntity params; + + try { + jsonBody.put("app_id", appname); + jsonBody.put("app_secret", appsecret); + params = new StringEntity(jsonBody.toString()); + request.setEntity(params); + + final HttpResponse response = httpClient.execute(request); + + if (isResponseOk(response)) { + HttpEntity body = response.getEntity(); + String bodyStr = EntityUtils.toString(body); + + LoginApiResponse loginResponse = new ObjectMapper().readValue(bodyStr, LoginApiResponse.class); + backrollToken = loginResponse.accessToken; + LOG.debug(String.format("Backroll client - Token : %s", backrollToken)); + + EntityUtils.consumeQuietly(response.getEntity()); + + if (StringUtils.isEmpty(loginResponse.accessToken)) { + throw new CloudRuntimeException("Backroll token is not available to perform API requests"); + } + } else { + EntityUtils.consumeQuietly(response.getEntity()); + if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { + throw new CloudRuntimeException( + "Failed to create and authenticate Backroll client, please check the settings."); + } else { + throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, + "Backroll API call unauthorized, please ask your administrator to fix integration issues."); + } + } + + } catch (final IOException e) { + throw new CloudRuntimeException("Failed to authenticate Backroll API service due to:" + e.getMessage()); + } catch (JSONException e) { + e.printStackTrace(); + } + LOG.info("Backroll client - end login"); + } + + private List getBackrollBackups(final String vmId) { + try { + LOG.info("start to list Backroll backups for vm " + vmId); + final HttpResponse backupsAskingResponse = get("/virtualmachines/" + vmId + "/backups"); + + if(isResponseOk(backupsAskingResponse)) { + HttpEntity body = backupsAskingResponse.getEntity(); + String bodyStr = EntityUtils.toString(body); + BackrollTaskRequestResponse backupTaskRequestResponse = new ObjectMapper().readValue(bodyStr, BackrollTaskRequestResponse.class); + String urlToRequest = backupTaskRequestResponse.location.replace("/api/v1", ""); + LOG.debug(urlToRequest); + EntityUtils.consumeQuietly(backupsAskingResponse.getEntity()); + bodyStr = waitForGetRequestResponse(urlToRequest); + LOG.debug(bodyStr); + BackrollBackupsFromVMResponse backrollBackupsFromVMResponse = new ObjectMapper().readValue(bodyStr, BackrollBackupsFromVMResponse.class); + + final List backups = new ArrayList<>(); + for (final BackrollArchiveResponse archive : backrollBackupsFromVMResponse.archives.archives) { + backups.add(new BackrollBackup(archive.name)); + LOG.debug(archive.name); + } + return backups; + } else { + throw new CloudRuntimeException( + "Failed to retrieve backups for this VM via Backroll"); + } + } catch (final IOException e) { + LOG.error("Failed to list backup form vm with Backroll due to:", e); + } catch (InterruptedException e) { + LOG.error("Backroll Error:", e); + } + return new ArrayList(); + } +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/api/command/GetBackrollHello.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/api/command/GetBackrollHello.java new file mode 100644 index 00000000000..6e5128f2d96 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/api/command/GetBackrollHello.java @@ -0,0 +1,56 @@ +// 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.api.command; + +/* import org.apache.log4j.Logger; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.backup.backroll.api.response.ApiHelloResponse; */ + +/* @APICommand(name = "getBackrollHello", responseObject = ApiHelloResponse.class, description = "Get Hello", + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) */ +public class GetBackrollHello {//extends BaseCmd { + /* private static final Logger LOGGER = Logger.getLogger(GetBackrollHello.class.getName()); + private static final String NAME = "gethelloresponse"; + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return NAME; + } + + @Override + public long getEntityOwnerId() { + return 0; + } + + @Override + public void execute() { + LOGGER.info("'getBackrollHello.execute' method invoked"); + + ApiHelloResponse response = new ApiHelloResponse("Hello"); + + response.setResponseName(getCommandName()); + response.setObjectName("msg"); + + setResponseObject(response); + } */ +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/api/response/ApiHelloResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/api/response/ApiHelloResponse.java new file mode 100644 index 00000000000..ef71e264db2 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/api/response/ApiHelloResponse.java @@ -0,0 +1,32 @@ +// 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.api.response; + +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class ApiHelloResponse extends BaseResponse { + @SerializedName("TEXT") + @Param(description = "Text") + private String msg; + + public ApiHelloResponse(String msg) { + this.msg = msg; + } +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollBackup.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollBackup.java new file mode 100644 index 00000000000..ddaadc3643c --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollBackup.java @@ -0,0 +1,13 @@ +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; + } +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollBackupMetrics.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollBackupMetrics.java new file mode 100644 index 00000000000..e275f0fb2a9 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollBackupMetrics.java @@ -0,0 +1,19 @@ +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; + } +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollOffering.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollOffering.java new file mode 100644 index 00000000000..7d329aaa405 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollOffering.java @@ -0,0 +1,61 @@ +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; + } +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollTaskStatus.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollTaskStatus.java new file mode 100644 index 00000000000..6f63f6f5364 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollTaskStatus.java @@ -0,0 +1,31 @@ +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; + } +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollVmBackup.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollVmBackup.java new file mode 100644 index 00000000000..1a837405ce5 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/BackrollVmBackup.java @@ -0,0 +1,27 @@ +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; + } +} \ No newline at end of file diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/BackrollTaskRequestResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/BackrollTaskRequestResponse.java new file mode 100644 index 00000000000..b4ad1ea31f6 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/BackrollTaskRequestResponse.java @@ -0,0 +1,8 @@ +package org.apache.cloudstack.backup.backroll.model.response; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BackrollTaskRequestResponse { + @JsonProperty("Location") + public String location; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/api/LoginApiResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/api/LoginApiResponse.java new file mode 100644 index 00000000000..e9906171304 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/api/LoginApiResponse.java @@ -0,0 +1,23 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollArchiveResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollArchiveResponse.java new file mode 100644 index 00000000000..03b3c3e56ea --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollArchiveResponse.java @@ -0,0 +1,25 @@ +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; + + @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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollArchivesResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollArchivesResponse.java new file mode 100644 index 00000000000..28de0ce3114 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollArchivesResponse.java @@ -0,0 +1,12 @@ +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 archives; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollBackupsFromVMResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollBackupsFromVMResponse.java new file mode 100644 index 00000000000..db5a579a147 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/archive/BackrollBackupsFromVMResponse.java @@ -0,0 +1,11 @@ +package org.apache.cloudstack.backup.backroll.model.response.archive; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BackrollBackupsFromVMResponse { + @JsonProperty("state") + public String state; + + @JsonProperty("info") + public BackrollArchivesResponse archives; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/backup/BackrollBackupStatusResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/backup/BackrollBackupStatusResponse.java new file mode 100644 index 00000000000..9f34503d9ba --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/backup/BackrollBackupStatusResponse.java @@ -0,0 +1,17 @@ +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; +} \ No newline at end of file diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/backup/BackrollBackupStatusSuccessResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/backup/BackrollBackupStatusSuccessResponse.java new file mode 100644 index 00000000000..7b72e45c958 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/backup/BackrollBackupStatusSuccessResponse.java @@ -0,0 +1,11 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/backup/BackrollBackupMetricsResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/backup/BackrollBackupMetricsResponse.java new file mode 100644 index 00000000000..52675b26a80 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/backup/BackrollBackupMetricsResponse.java @@ -0,0 +1,11 @@ +package org.apache.cloudstack.backup.backroll.model.response.metrics.backup; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BackrollBackupMetricsResponse { + @JsonProperty("state") + public String state; + + @JsonProperty("info") + public BackupMetricsInfo info; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/backup/BackupMetricsInfo.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/backup/BackupMetricsInfo.java new file mode 100644 index 00000000000..6d9381f4dcb --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/backup/BackupMetricsInfo.java @@ -0,0 +1,17 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/BackrollVmMetricsResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/BackrollVmMetricsResponse.java new file mode 100644 index 00000000000..8a0e4304e85 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/BackrollVmMetricsResponse.java @@ -0,0 +1,11 @@ +package org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BackrollVmMetricsResponse { + @JsonProperty("state") + public String state; + + @JsonProperty("info") + public MetricsInfos infos; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/CacheStats.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/CacheStats.java new file mode 100644 index 00000000000..f445e423ada --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/CacheStats.java @@ -0,0 +1,23 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosCache.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosCache.java new file mode 100644 index 00000000000..5fa64fc5c89 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosCache.java @@ -0,0 +1,11 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosEncryption.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosEncryption.java new file mode 100644 index 00000000000..e0a86d9de29 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosEncryption.java @@ -0,0 +1,8 @@ +package org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class InfosEncryption { + @JsonProperty("mode") + public String mode; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosRepository.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosRepository.java new file mode 100644 index 00000000000..695a53ed211 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/InfosRepository.java @@ -0,0 +1,14 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/MetricsInfos.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/MetricsInfos.java new file mode 100644 index 00000000000..bf9ff009095 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachine/MetricsInfos.java @@ -0,0 +1,17 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/Archives.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/Archives.java new file mode 100644 index 00000000000..f70e0dc183b --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/Archives.java @@ -0,0 +1,19 @@ +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 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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/BackupInfos.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/BackupInfos.java new file mode 100644 index 00000000000..175b1a664f7 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/BackupInfos.java @@ -0,0 +1,23 @@ +package org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BackupInfos { + @JsonProperty("archive") + public String archive; + + @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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/InfosEncryption.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/InfosEncryption.java new file mode 100644 index 00000000000..05d40cdd149 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/InfosEncryption.java @@ -0,0 +1,8 @@ +package org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class InfosEncryption { + @JsonProperty("mode") + public String mode; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/InfosRepository.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/InfosRepository.java new file mode 100644 index 00000000000..796a37b7164 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/InfosRepository.java @@ -0,0 +1,14 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/VirtualMachineBackupsResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/VirtualMachineBackupsResponse.java new file mode 100644 index 00000000000..79cc6afe3b4 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/metrics/virtualMachineBackups/VirtualMachineBackupsResponse.java @@ -0,0 +1,11 @@ +package org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class VirtualMachineBackupsResponse { + @JsonProperty("state") + public String state; + + @JsonProperty("info") + public Archives info; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/policy/BackrollBackupPolicyResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/policy/BackrollBackupPolicyResponse.java new file mode 100644 index 00000000000..d62e043f704 --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/policy/BackrollBackupPolicyResponse.java @@ -0,0 +1,38 @@ +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; +} diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/policy/BackupPoliciesResponse.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/policy/BackupPoliciesResponse.java new file mode 100644 index 00000000000..5373e884ada --- /dev/null +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/model/response/policy/BackupPoliciesResponse.java @@ -0,0 +1,15 @@ +package org.apache.cloudstack.backup.backroll.model.response.policy; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BackupPoliciesResponse { + @JsonProperty("state") + public String state; + + @JsonProperty("info") + @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) + public List backupPolicies; +} diff --git a/plugins/backup/backroll/src/main/resources/META-INF/cloudstack/backroll-backup/module.properties b/plugins/backup/backroll/src/main/resources/META-INF/cloudstack/backroll-backup/module.properties new file mode 100644 index 00000000000..a181dadfb20 --- /dev/null +++ b/plugins/backup/backroll/src/main/resources/META-INF/cloudstack/backroll-backup/module.properties @@ -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 diff --git a/plugins/backup/backroll/src/main/resources/META-INF/cloudstack/backroll-backup/spring-backup-backroll-context.xml b/plugins/backup/backroll/src/main/resources/META-INF/cloudstack/backroll-backup/spring-backup-backroll-context.xml new file mode 100644 index 00000000000..231c694ab8b --- /dev/null +++ b/plugins/backup/backroll/src/main/resources/META-INF/cloudstack/backroll-backup/spring-backup-backroll-context.xml @@ -0,0 +1,27 @@ + + + + + + diff --git a/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/BackrollBackupProviderTest.java b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/BackrollBackupProviderTest.java new file mode 100644 index 00000000000..82d8b3d1af9 --- /dev/null +++ b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/BackrollBackupProviderTest.java @@ -0,0 +1,49 @@ +// 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; + + +//@RunWith(MockitoJUnitRunner.class) +public class BackrollBackupProviderTest { + /*@Spy + @InjectMocks + BackrollBackupProvider backupProvider = new BackrollBackupProvider(); + + @Mock + BackrollClient client; + + @Mock + VMInstanceDao vmInstanceDao; + + @Mock + BackupDao backupDao; + + @Test + public void providerGetDescription() { + assertEquals("Backroll Backup Plugin", backupProvider.getDescription()); + + } + + @Test + public void listBackupOfferingsToBackrollTestOk() { + + List results = backupProvider.listBackupOfferings(0L); + assertEquals("Backroll Backup Plugin", "Backroll Backup Plugin"); + + }*/ +} \ No newline at end of file diff --git a/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/BackrollClientTest.java b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/BackrollClientTest.java new file mode 100644 index 00000000000..0ba9ebb9772 --- /dev/null +++ b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/BackrollClientTest.java @@ -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; + +public class BackrollClientTest { + +} \ No newline at end of file diff --git a/plugins/pom.xml b/plugins/pom.xml index d0661c01a2c..2f4c40b2152 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -60,6 +60,7 @@ api/rate-limit api/solidfire-intg-test + backup/backroll backup/dummy backup/networker @@ -194,6 +195,7 @@ api/vmware-sioc + backup/backroll backup/veeam hypervisors/vmware network-elements/cisco-vnmc diff --git a/ui/package-lock.json b/ui/package-lock.json index d17a02d3c36..e7e8cce2824 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -2486,9 +2486,9 @@ } }, "@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.1.tgz", + "integrity": "sha512-iaQslNbARe8fctL5Lk+DsmgWOM83lM+7FzP0eQUJs1jd3kBE8NWqBTIT2S8SqQOJjxvt2eyIjpOuYeRXq2AdMw==", "dev": true, "requires": { "@types/express-serve-static-core": "*", @@ -2589,9 +2589,9 @@ "dev": true }, "@types/http-proxy": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", - "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "version": "1.17.12", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.12.tgz", + "integrity": "sha512-kQtujO08dVtQ2wXAuSFfk9ASy3sug4+ogFR8Kd8UgP8PEuc1/G/8yjYRmp//PcDNJEUKOza/MrQu15bouEUCiw==", "dev": true, "requires": { "@types/node": "*" @@ -2803,9 +2803,9 @@ "dev": true }, "@types/tapable": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz", - "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.9.tgz", + "integrity": "sha512-fOHIwZua0sRltqWzODGUM6b4ffZrf/vzGUmNXdR+4DzuJP42PMbM5dLKcdzlYvv8bMJ3GALOzkk1q7cDm2zPyA==", "dev": true }, "@types/through": { @@ -2818,9 +2818,9 @@ } }, "@types/uglify-js": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.16.0.tgz", - "integrity": "sha512-0yeUr92L3r0GLRnBOvtYK1v2SjqMIqQDHMl7GLb+l2L8+6LSFWEEWEIgVsPdMn5ImLM8qzWT8xFPtQYpp8co0g==", + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.2.tgz", + "integrity": "sha512-9SjrHO54LINgC/6Ehr81NjAxAYvwEZqjUHLjJYvC4Nmr9jbLQCIZbWSvl4vXQkkmR1UAuaKDycau3O1kWGFyXQ==", "dev": true, "requires": { "source-map": "^0.6.1" @@ -2832,9 +2832,9 @@ "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, "@types/webpack": { - "version": "4.41.32", - "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.32.tgz", - "integrity": "sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==", + "version": "4.41.33", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.33.tgz", + "integrity": "sha512-PPajH64Ft2vWevkerISMtnZ8rTs4YmRbs+23c402J0INmxDKCrhZNvwZYtzx96gY2wAtXdrK1BS2fiC8MlLr3g==", "dev": true, "requires": { "@types/node": "*", @@ -3489,18 +3489,18 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -3529,9 +3529,9 @@ } }, "vue-loader": { - "version": "15.9.8", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.8.tgz", - "integrity": "sha512-GwSkxPrihfLR69/dSV3+5CdMQ0D+jXg8Ma1S4nQXKJAznYFX14vHdc/NetQc34Dw+rBbIJyP7JOuVb9Fhprvog==", + "version": "15.10.2", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.2.tgz", + "integrity": "sha512-ndeSe/8KQc/nlA7TJ+OBhv2qalmj1s+uBs7yHDRFaAXscFTApBzY9F1jES3bautmgWjDlDct0fw8rPuySDLwxw==", "dev": true, "requires": { "@vue/component-compiler-utils": "^3.1.0", @@ -4211,9 +4211,9 @@ "dev": true }, "address": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.0.tgz", - "integrity": "sha512-tNEZYz5G/zYunxFm7sfhAxkXEuLj3K6BKwv6ZURlsF6yiUQ65z0Q2wZW9L5cPUl9ocofGvXOdFYbFHp0+6MOig==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", "dev": true }, "agent-base": { @@ -7866,18 +7866,18 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -8179,18 +8179,18 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -8199,9 +8199,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -10813,18 +10813,18 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -15140,12 +15140,30 @@ } }, "launch-editor-middleware": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.4.0.tgz", - "integrity": "sha512-/M7AX/6xktZY60KE7j71XLrj9U6H5TBoP+mJzhYB3fcdAq8rcazit/K0qWiu1jvytUPXP4lJRd1VJFwvdMQ/uw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.6.0.tgz", + "integrity": "sha512-K2yxgljj5TdCeRN1lBtO3/J26+AIDDDw+04y6VAiZbWcTdBwsYN6RrZBnW5DN/QiSIdKNjKdATLUUluWWFYTIA==", "dev": true, "requires": { - "launch-editor": "^2.4.0" + "launch-editor": "^2.6.0" + }, + "dependencies": { + "launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "dev": true, + "requires": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + } } }, "left-pad": { @@ -15848,18 +15866,18 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -17637,18 +17655,18 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -18063,9 +18081,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -18120,9 +18138,9 @@ "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==" }, "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "optional": true }, @@ -20413,9 +20431,9 @@ }, "dependencies": { "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -22084,18 +22102,18 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -22638,18 +22656,18 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" } }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "requires": { "big.js": "^5.2.2", @@ -23415,9 +23433,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, "string-width": { diff --git a/ui/package.json b/ui/package.json index b269effb422..326869a1d0c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -81,7 +81,7 @@ "@vue/cli-plugin-router": "~4.5.0", "@vue/cli-plugin-unit-jest": "~4.5.0", "@vue/cli-plugin-vuex": "~4.5.0", - "@vue/cli-service": "~4.5.0", + "@vue/cli-service": "^4.5.19", "@vue/compiler-sfc": "^3.2.31", "@vue/eslint-config-standard": "^5.1.2", "@vue/test-utils": "^2.0.0-0",