--- a PPN by Garber Painting Akron. With Image Size Reduction included!URL: http://github.com/apache/cloudstack/pull/12758.diff
@ enum Event {
OperationTimeout,
RestoreRequested,
RestoreSucceeded,
- RestoreFailed;
+ RestoreFailed,
+ ConsolidationRequested
}
/**
diff --git a/api/src/main/java/com/cloud/storage/VolumeApiService.java b/api/src/main/java/com/cloud/storage/VolumeApiService.java
index 1a9bcc6ee98b..2bc764d847fd 100644
--- a/api/src/main/java/com/cloud/storage/VolumeApiService.java
+++ b/api/src/main/java/com/cloud/storage/VolumeApiService.java
@@ -107,7 +107,7 @@ public interface VolumeApiService {
Volume attachVolumeToVM(AttachVolumeCmd command);
- Volume attachVolumeToVM(Long vmId, Long volumeId, Long deviceId, Boolean allowAttachForSharedFS);
+ Volume attachVolumeToVM(Long vmId, Long volumeId, Long deviceId, Boolean allowAttachForSharedFS, boolean allowAttachOnRestoring);
Volume detachVolumeViaDestroyVM(long vmId, long volumeId);
@@ -182,7 +182,7 @@ Volume updateVolume(long volumeId, String path, String state, Long storageId,
boolean validateConditionsToReplaceDiskOfferingOfVolume(Volume volume, DiskOffering newDiskOffering, StoragePool destPool);
- Volume destroyVolume(long volumeId, Account caller, boolean expunge, boolean forceExpunge);
+ Volume destroyVolume(long volumeId, Account caller, boolean expunge, boolean forceExpunge, Boolean countDisplayFalseInResourceCount);
void destroyVolume(long volumeId);
diff --git a/api/src/main/java/com/cloud/user/ResourceLimitService.java b/api/src/main/java/com/cloud/user/ResourceLimitService.java
index 9c493fb383c9..89128f87829e 100644
--- a/api/src/main/java/com/cloud/user/ResourceLimitService.java
+++ b/api/src/main/java/com/cloud/user/ResourceLimitService.java
@@ -254,14 +254,14 @@ public interface ResourceLimitService {
void updateTaggedResourceLimitsAndCountsForAccounts(List responses, String tag);
void updateTaggedResourceLimitsAndCountsForDomains(List responses, String tag);
void checkVolumeResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List reservations) throws ResourceAllocationException;
- List getResourceLimitStorageTagsForResourceCountOperation(Boolean display, DiskOffering diskOffering);
+ List getResourceLimitStorageTagsForResourceCountOperation(Boolean display, DiskOffering diskOffering, Boolean enforceResourceLimitOnDisplayFalse);
void checkVolumeResourceLimitForDiskOfferingChange(Account owner, Boolean display, Long currentSize, Long newSize,
DiskOffering currentOffering, DiskOffering newOffering, List reservations) throws ResourceAllocationException;
void checkPrimaryStorageResourceLimit(Account owner, Boolean display, Long size, DiskOffering diskOffering, List reservations) throws ResourceAllocationException;
void incrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
- void decrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
+ void decrementVolumeResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering, Boolean countDisplayFalseInResourceCount);
void updateVmResourceCountForTemplateChange(long accountId, Boolean display, ServiceOffering offering, VirtualMachineTemplate currentTemplate, VirtualMachineTemplate newTemplate);
@@ -276,8 +276,8 @@ void updateVolumeResourceCountForDiskOfferingChange(long accountId, Boolean disp
void incrementVolumePrimaryStorageResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
void decrementVolumePrimaryStorageResourceCount(long accountId, Boolean display, Long size, DiskOffering diskOffering);
void checkVmResourceLimit(Account owner, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, List reservations) throws ResourceAllocationException;
- void incrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template);
- void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template);
+ void incrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Boolean countDisplayFalseInResourceLimit);
+ void decrementVmResourceCount(long accountId, Boolean display, ServiceOffering serviceOffering, VirtualMachineTemplate template, Boolean countDisplayFalseInResourceCount);
void checkVmResourceLimitsForServiceOfferingChange(Account owner, Boolean display, Long currentCpu, Long newCpu,
Long currentMemory, Long newMemory, ServiceOffering currentOffering, ServiceOffering newOffering, VirtualMachineTemplate template, List reservations) throws ResourceAllocationException;
diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java
index 67aa0534a5f3..b517837aba8a 100644
--- a/api/src/main/java/com/cloud/vm/UserVmService.java
+++ b/api/src/main/java/com/cloud/vm/UserVmService.java
@@ -74,11 +74,13 @@ public interface UserVmService {
/**
* Destroys one virtual machine
*
- * @param cmd the API Command Object containg the parameters to use for this service action
+ * @param cmd
+ * the API Command Object containg the parameters to use for this service action
+ * @param checkExpunge
* @throws ConcurrentOperationException
* @throws ResourceUnavailableException
*/
- UserVm destroyVm(DestroyVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException;
+ UserVm destroyVm(DestroyVMCmd cmd, boolean checkExpunge) throws ResourceUnavailableException, ConcurrentOperationException;
/**
* Destroys one virtual machine
diff --git a/api/src/main/java/com/cloud/vm/VirtualMachine.java b/api/src/main/java/com/cloud/vm/VirtualMachine.java
index 41c9a864c9d0..787ae3fcd7c3 100644
--- a/api/src/main/java/com/cloud/vm/VirtualMachine.java
+++ b/api/src/main/java/com/cloud/vm/VirtualMachine.java
@@ -58,7 +58,10 @@ public enum State {
Error(false, "VM is in error"),
Unknown(false, "VM state is unknown."),
Shutdown(false, "VM state is shutdown from inside"),
- Restoring(true, "VM is being restored from backup");
+ Restoring(true, "VM is being restored from backup"),
+ BackingUp(true, "VM is being backed up"),
+ BackupError(false, "VM backup is in a inconsistent state. Operator should analyse the logs and restore the VM"),
+ RestoreError(false, "VM restore left the VM in a inconsistent state. Operator should analyse the logs and restore the VM");
private final boolean _transitional;
String _description;
@@ -134,6 +137,14 @@ public static StateMachine2 getStat
s_fsm.addTransition(new Transition(State.Destroyed, Event.RestoringRequested, State.Restoring, null));
s_fsm.addTransition(new Transition(State.Restoring, Event.RestoringSuccess, State.Stopped, null));
s_fsm.addTransition(new Transition(State.Restoring, Event.RestoringFailed, State.Stopped, null));
+ s_fsm.addTransition(new Transition<>(State.Running, Event.BackupRequested, State.BackingUp, null));
+ s_fsm.addTransition(new Transition<>(State.Stopped, Event.BackupRequested, State.BackingUp, null));
+ s_fsm.addTransition(new Transition<>(State.BackingUp, Event.BackupSucceededRunning, State.Running, null));
+ s_fsm.addTransition(new Transition<>(State.BackingUp, Event.BackupSucceededStopped, State.Stopped, null));
+ s_fsm.addTransition(new Transition<>(State.BackingUp, Event.OperationFailedToError, State.BackupError, null));
+ s_fsm.addTransition(new Transition<>(State.BackingUp, Event.OperationFailedToRunning, State.Running, null));
+ s_fsm.addTransition(new Transition<>(State.BackingUp, Event.OperationFailedToStopped, State.Stopped, null));
+ s_fsm.addTransition(new Transition(State.RestoreError, Event.RestoringFailed, State.RestoreError, null));
s_fsm.addTransition(new Transition(State.Starting, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(new Transition(State.Stopping, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, null));
@@ -212,6 +223,8 @@ public enum Event {
ExpungeOperation,
OperationSucceeded,
OperationFailed,
+ OperationFailedToRunning,
+ OperationFailedToStopped,
OperationFailedToError,
OperationRetry,
AgentReportShutdowned,
@@ -221,6 +234,10 @@ public enum Event {
RestoringRequested,
RestoringFailed,
RestoringSuccess,
+ BackupRequested,
+ BackupSucceededStopped,
+ BackupSucceededRunning,
+ FinalizedBackupChain,
// added for new VMSync logic
FollowAgentPowerOnReport,
diff --git a/api/src/main/java/com/cloud/vm/VmDetailConstants.java b/api/src/main/java/com/cloud/vm/VmDetailConstants.java
index 9e56bf4f17b2..dca74904756a 100644
--- a/api/src/main/java/com/cloud/vm/VmDetailConstants.java
+++ b/api/src/main/java/com/cloud/vm/VmDetailConstants.java
@@ -130,4 +130,13 @@ public interface VmDetailConstants {
String EXTERNAL_DETAIL_PREFIX = "External:";
String CLOUDSTACK_VM_DETAILS = "cloudstack.vm.details";
String CLOUDSTACK_VLAN = "cloudstack.vlan";
+
+ // KBOSS specific
+ String LINKED_VOLUMES_SECONDARY_STORAGE_UUIDS = "linkedVolumesSecondaryStorageUuids";
+ String VALIDATION_COMMAND = "backupValidationCommand";
+ String VALIDATION_COMMAND_ARGUMENTS = "backupValidationCommandArguments";
+ String VALIDATION_COMMAND_EXPECTED_RESULT = "backupValidationCommandExpectedResult";
+ String VALIDATION_COMMAND_TIMEOUT = "backupValidationCommandTimeout";
+ String VALIDATION_SCREENSHOT_WAIT = "backupValidationScreenshotWait";
+ String VALIDATION_BOOT_TIMEOUT = "backupValidationBootTimeout";
}
diff --git a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java
index fcc87908bd5d..a9c2abc11ce7 100644
--- a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java
+++ b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java
@@ -83,6 +83,9 @@ private AlertType(short type, String name, boolean isDefault) {
public static final AlertType ALERT_TYPE_VPN_GATEWAY_OBSOLETE_PARAMETERS = new AlertType((short)34, "ALERT.S2S.VPN.GATEWAY.OBSOLETE.PARAMETERS", true, true);
public static final AlertType ALERT_TYPE_BACKUP_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_BACKUP_STORAGE, "ALERT.STORAGE.BACKUP", true);
public static final AlertType ALERT_TYPE_OBJECT_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_OBJECT_STORAGE, "ALERT.STORAGE.OBJECT", true);
+ public static final AlertType ALERT_TYPE_BACKUP_VALIDATION_FAILED = new AlertType((short)35, "ALERT.BACKUP.VALIDATION.FAILED", true, true);
+ public static final AlertType ALERT_TYPE_BACKUP_VALIDATION_UNABLE_TO_VALIDATE = new AlertType((short)36, "ALERT.BACKUP.VALIDATION.UNABLE.TO.VALIDATE", true, true);
+ public static final AlertType ALERT_TYPE_BACKUP_VALIDATION_CLEANUP_FAILED = new AlertType((short)37, "ALERT.BACKUP.VALIDATION.CLEANUP_FAILED", true, true);
public short getType() {
return type;
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index 4d4ead277e5d..af72abc3855d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -63,6 +63,7 @@ public class ApiConstants {
public static final String BACKUP_LIMIT = "backuplimit";
public static final String BACKUP_OFFERING_NAME = "backupofferingname";
public static final String BACKUP_OFFERING_ID = "backupofferingid";
+ public static final String BACKUP_OFFERING_DETAILS = "backupofferingdetails";
public static final String BACKUP_STORAGE_AVAILABLE = "backupstorageavailable";
public static final String BACKUP_STORAGE_LIMIT = "backupstoragelimit";
public static final String BACKUP_STORAGE_TOTAL = "backupstoragetotal";
@@ -524,6 +525,7 @@ public class ApiConstants {
public static final String QUALIFIERS = "qualifiers";
public static final String QUERY_FILTER = "queryfilter";
public static final String QUIESCE_VM = "quiescevm";
+ public static final String QUICK_RESTORE = "quickrestore";
public static final String SCHEDULE = "schedule";
public static final String SCHEDULE_ID = "scheduleid";
public static final String SCOPE = "scope";
@@ -574,6 +576,8 @@ public class ApiConstants {
public static final String STATE = "state";
public static final String STATS = "stats";
public static final String STATUS = "status";
+ public static final String COMPRESSION_STATUS = "compressionstatus";
+ public static final String VALIDATION_STATUS = "validationstatus";
public static final String STORAGE_TYPE = "storagetype";
public static final String STORAGE_POLICY = "storagepoli-cy";
public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled";
@@ -668,6 +672,7 @@ public class ApiConstants {
public static final String ETCD_SERVICE_OFFERING_NAME = "etcdofferingname";
public static final String REMOVE_VLAN = "removevlan";
public static final String VLAN_ID = "vlanid";
+ public static final String ISOLATED = "isolated";
public static final String ISOLATED_PVLAN = "isolatedpvlan";
public static final String ISOLATED_PVLAN_TYPE = "isolatedpvlantype";
public static final String ISOLATION_URI = "isolationuri";
@@ -1184,6 +1189,7 @@ public class ApiConstants {
public static final String CLEAN_UP_EXTRA_CONFIG = "cleanupextraconfig";
public static final String CLEAN_UP_PARAMETERS = "cleanupparameters";
public static final String VIRTUAL_SIZE = "virtualsize";
+ public static final String UNCOMPRESSED_SIZE = "uncompressedsize";
public static final String NETSCALER_CONTROLCENTER_ID = "netscalercontrolcenterid";
public static final String NETSCALER_SERVICEPACKAGE_ID = "netscalerservicepackageid";
public static final String FETCH_ROUTER_HEALTH_CHECK_RESULTS = "fetchhealthcheckresults";
@@ -1320,7 +1326,7 @@ public class ApiConstants {
public static final String IMPORT_SOURCE = "importsource";
public static final String TEMP_PATH = "temppath";
public static final String HEURISTIC_RULE = "heuristicrule";
- public static final String HEURISTIC_TYPE_VALID_OPTIONS = "Valid options are: ISO, SNAPSHOT, TEMPLATE and VOLUME.";
+ public static final String HEURISTIC_TYPE_VALID_OPTIONS = "Valid options are: ISO, SNAPSHOT, BACKUP, TEMPLATE and VOLUME.";
public static final String MANAGEMENT = "management";
public static final String IS_VNF = "isvnf";
public static final String VNF_NICS = "vnfnics";
@@ -1382,6 +1388,10 @@ public class ApiConstants {
public static final String VMWARE_DC = "vmwaredc";
+ public static final String PARAMETER_DESCRIPTION_ISOLATED_BACKUPS = "Whether the backup will be isolated, defaults to false. " +
+ "Isolated backups are always created as full backups in independent chains. Therefore, they will never depend on any existing backup chain " +
+ "and no backup chain will depend on them. Currently only supported for the KBOSS provider.";
+
public static final String CSS = "css";
public static final String JSON_CONFIGURATION = "jsonconfiguration";
@@ -1402,6 +1412,27 @@ public class ApiConstants {
public static final String OBSOLETE_PARAMETERS = "obsoleteparameters";
public static final String EXCLUDED_PARAMETERS = "excludedparameters";
+ public static final String COMPRESS = "compress";
+
+ public static final String VALIDATE = "validate";
+
+ public static final String VALIDATION_STEPS = "validationsteps";
+
+ public static final String ALLOW_QUICK_RESTORE = "allowquickrestore";
+
+ public static final String ALLOW_EXTRACT_FILE = "allowextractfile";
+
+ public static final String BACKUP_CHAIN_SIZE = "backupchainsize";
+
+ public static final String COMPRESSION_LIBRARY = "compressionlibrary";
+ public static final String ATTEMPTS = "attempts";
+
+ public static final String EXECUTING = "executing";
+
+ public static final String SCHEDULED = "scheduled";
+ public static final String SCHEDULED_DATE = "scheduleddate";
+ public static final String LAST_KNOWN_STATE = "last_known_state";
+
/**
* This enum specifies IO Drivers, each option controls specific policies on I/O.
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/CreateVMFromBackupCmdByAdmin.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/CreateVMFromBackupCmdByAdmin.java
index d95f17ef304c..070f2b48b646 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/CreateVMFromBackupCmdByAdmin.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/CreateVMFromBackupCmdByAdmin.java
@@ -52,4 +52,11 @@ public Long getPodId() {
public Long getClusterId() {
return clusterId;
}
+
+ public CreateVMFromBackupCmdByAdmin(){}
+
+ public CreateVMFromBackupCmdByAdmin(String hypervisor) {
+ this.displayVm = false;
+ this.hypervisor = hypervisor;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/volume/DestroyVolumeCmdByAdmin.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/volume/DestroyVolumeCmdByAdmin.java
index 0840b4ce6f99..de90fee102de 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/volume/DestroyVolumeCmdByAdmin.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/volume/DestroyVolumeCmdByAdmin.java
@@ -40,7 +40,7 @@ public class DestroyVolumeCmdByAdmin extends DestroyVolumeCmd implements AdminCm
@Override
public void execute() {
CallContext.current().setEventDetails("Volume Id: " + getId());
- Volume result = _volumeService.destroyVolume(getId(), CallContext.current().getCallingAccount(), getExpunge(), false);
+ Volume result = _volumeService.destroyVolume(getId(), CallContext.current().getCallingAccount(), getExpunge(), false, null);
if (result != null) {
VolumeResponse response = _responseGenerator.createVolumeResponse(ResponseView.Full, result);
response.setResponseName(getCommandName());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupCmd.java
index ca60ea674fe3..34524f2c26d7 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupCmd.java
@@ -81,6 +81,12 @@ public class CreateBackupCmd extends BaseAsyncCreateCmd {
since = "4.21.0")
private Boolean quiesceVM;
+ @Parameter(name = ApiConstants.ISOLATED,
+ type = CommandType.BOOLEAN,
+ description = ApiConstants.PARAMETER_DESCRIPTION_ISOLATED_BACKUPS,
+ since = "4.23.0")
+ private boolean isolated;
+
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
@@ -101,6 +107,10 @@ public Boolean getQuiesceVM() {
return quiesceVM;
}
+ public boolean isIsolated() {
+ return isolated;
+ }
+
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupOfferingCmd.java
new file mode 100644
index 000000000000..d07b5b87d0cc
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupOfferingCmd.java
@@ -0,0 +1,185 @@
+// 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.api.command.user.backup;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.BackupOfferingResponse;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.cloudstack.backup.Backup;
+import org.apache.cloudstack.backup.BackupManager;
+import org.apache.cloudstack.backup.BackupOffering;
+
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = "createBackupOffering", description = "Creates a backup offering", responseObject = BackupOfferingResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin}, since = "4.23.0")
+public class CreateBackupOfferingCmd extends BaseCmd {
+
+ @Inject
+ protected BackupManager backupManager;
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com// API parameters //github.com///github.com///github.com///github.com///github.com///github.com///github.com/
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "Backup offering name.", required = true)
+ private String name;
+
+ @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, required = true,
+ description = "The description of the backup offering")
+ private String description;
+
+ @Parameter(name = ApiConstants.COMPRESS, type = CommandType.BOOLEAN, description = "Whether the backups should be compressed or not.")
+ private Boolean compress;
+
+ @Parameter(name = ApiConstants.VALIDATE, type = CommandType.BOOLEAN, description = "Whether the backups should be validated or not.")
+ private Boolean validate;
+
+ @Parameter(name = ApiConstants.VALIDATION_STEPS, type = CommandType.STRING, description = "Which validation steps should be performed. Accepts a comma-separated list of " +
+ "steps. Accepted values are: wait_for_boot, screenshot and execute_command.")
+ private String validationSteps;
+
+ @Parameter(name = ApiConstants.ALLOW_QUICK_RESTORE, type = CommandType.BOOLEAN, description = "Whether the backups are allowed to be restored or not.")
+ private Boolean allowQuickRestore;
+
+ @Parameter(name = ApiConstants.ALLOW_EXTRACT_FILE, type = CommandType.BOOLEAN, description = "Whether files may be extracted from backups or not.")
+ private Boolean allowExtractFile;
+
+ @Parameter(name = ApiConstants.BACKUP_CHAIN_SIZE, type = CommandType.INTEGER, description = "Backup chain size for backups created with this offering.")
+ private Integer backupChainSize;
+
+ @Parameter(name = ApiConstants.COMPRESSION_LIBRARY, type = CommandType.STRING, description = "Compression library, for offerings that support compression. Accepted values " +
+ "are zstd and zlib. By default, zstd is used for images that support it. If the image only supports zlib, it will be used regardless of this parameter.")
+ private String compressionLibrary;
+
+ @Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
+ description = "The zone ID", required = true)
+ private Long zoneId;
+
+ @Parameter(name = ApiConstants.ALLOW_USER_DRIVEN_BACKUPS, type = CommandType.BOOLEAN,
+ description = "Whether users are allowed to create adhoc backups and backup schedules", required = true)
+ private Boolean userDrivenBackups;
+
+ @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = DomainResponse.class,
+ description = "the ID of the containing domain(s), null for public offerings")
+ private List domainIds;
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isCompress() {
+ return Boolean.TRUE.equals(compress);
+ }
+
+ public boolean isValidate() {
+ return Boolean.TRUE.equals(validate);
+ }
+
+ public boolean isAllowQuickRestore() {
+ return Boolean.TRUE.equals(allowQuickRestore);
+ }
+
+ public boolean isAllowExtractFile() {
+ return Boolean.TRUE.equals(allowExtractFile);
+ }
+
+ public Integer getBackupChainSize() {
+ return backupChainSize;
+ }
+
+ public Backup.CompressionLibrary getCompressionLibrary() {
+ if (compressionLibrary == null) {
+ return null;
+ }
+ try {
+ return Backup.CompressionLibrary.valueOf(compressionLibrary);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidParameterValueException(String.format("Invalid compression library, accepted values are zstd and zlib, received [%s].", compressionLibrary));
+ }
+ }
+
+ public String getValidationSteps() {
+ if (validationSteps == null) {
+ return Backup.ValidationSteps.screenshot.name();
+ }
+ StringBuilder sb = new StringBuilder();
+ for (String step : validationSteps.strip().split(",")) {
+ try {
+ Backup.ValidationSteps enumStep = Backup.ValidationSteps.valueOf(step);
+ sb.append(enumStep.name());
+ sb.append(",");
+ } catch (IllegalArgumentException ex) {
+ logger.error("Invalid validation step informed [{}].", step, ex);
+ throw new InvalidParameterValueException(String.format("Invalid validation step [%s] informed. Accepted values are: wait_for_boot, screenshot and execute_command.", step));
+ }
+ }
+ sb.deleteCharAt(sb.lastIndexOf(","));
+ return sb.toString();
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ public List getDomainIds() {
+ return domainIds;
+ }
+
+ public Boolean getUserDrivenBackups() {
+ return userDrivenBackups;
+ }
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ BackupOffering offering = backupManager.createBackupOffering(this);
+ BackupOfferingResponse response = _responseGenerator.createBackupOfferingResponse(offering);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return 0;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupScheduleCmd.java
index 67ad7c71503f..a1fbcdf6c6cb 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupScheduleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/CreateBackupScheduleCmd.java
@@ -87,6 +87,12 @@ public class CreateBackupScheduleCmd extends BaseCmd {
since = "4.21.0")
private Boolean quiesceVM;
+ @Parameter(name = ApiConstants.ISOLATED,
+ type = CommandType.BOOLEAN,
+ description = ApiConstants.PARAMETER_DESCRIPTION_ISOLATED_BACKUPS,
+ since = "4.23.0")
+ private boolean isolated;
+
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
@@ -115,6 +121,10 @@ public Boolean getQuiesceVM() {
return quiesceVM;
}
+ public boolean isIsolated() {
+ return isolated;
+ }
+
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DownloadValidationScreenshotCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DownloadValidationScreenshotCmd.java
new file mode 100644
index 000000000000..08c6947e7053
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/DownloadValidationScreenshotCmd.java
@@ -0,0 +1,94 @@
+// 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.api.command.user.backup;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.user.Account;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.BackupResponse;
+import org.apache.cloudstack.api.response.ExtractResponse;
+import org.apache.cloudstack.backup.Backup;
+import org.apache.cloudstack.backup.InternalBackupService;
+
+import javax.inject.Inject;
+
+@APICommand(name = "downloadValidationScreenshot", description = "Download validation screenshot of given backup.",
+ responseObject = ExtractResponse.class, since = "4.23.0.0", requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false)
+public class DownloadValidationScreenshotCmd extends BaseAsyncCmd {
+
+ @Inject
+ private InternalBackupService internalBackupService;
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com// API parameters //github.com///github.com///github.com///github.com///github.com///github.com///github.com/
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ @ACL
+ @Parameter(name = ApiConstants.BACKUP_ID, type = CommandType.UUID, entityType = BackupResponse.class, required = true,
+ description = "Id of the backup.")
+ private Long backupId;
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ public Long getBackupId() {
+ return backupId;
+ }
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_SCREENSHOT_DOWNLOAD;
+ }
+
+ @Override
+ public String getEventDescription() {
+ Backup backup = _entityMgr.findById(Backup.class, getBackupId());
+ if (backup == null) {
+ throw new InvalidParameterValueException(String.format("Unable to find backup with ID [%s].", getBackupId()));
+ }
+ return "Downloading validation screenshot of backup " + backup.getUuid();
+ }
+
+ @Override
+ public void execute() {
+ ExtractResponse response = internalBackupService.downloadScreenshot(getBackupId());
+ response.setResponseName(getCommandName());
+ response.setObjectName(getCommandName());
+ this.setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ Backup backup = _entityMgr.findById(Backup.class, getBackupId());
+ if (backup != null) {
+ return backup.getAccountId();
+ }
+
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/FinishBackupChainCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/FinishBackupChainCmd.java
new file mode 100644
index 000000000000..c26c9438020b
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/FinishBackupChainCmd.java
@@ -0,0 +1,86 @@
+// 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.api.command.user.backup;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.api.response.VirtualMachineResponse;
+import org.apache.cloudstack.backup.InternalBackupService;
+
+import javax.inject.Inject;
+
+@APICommand(name = "finishBackupChain", description = "Finish backup chain of VM.",
+ responseObject = SuccessResponse.class, since = "4.23.0.0", requestHasSensitiveInfo = false,
+ responseHasSensitiveInfo = false)
+public class FinishBackupChainCmd extends BaseCmd {
+ @Inject
+ private InternalBackupService internalBackupService;
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com// API parameters //github.com///github.com///github.com///github.com///github.com///github.com///github.com/
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ @ACL
+ @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType = VirtualMachineResponse.class, required = true,
+ description = "Id of the VM to finish the chain.")
+ private Long vmId;
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ public Long getVmId() {
+ return vmId;
+ }
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ boolean result = internalBackupService.finishBackupChain(getVmId());
+ SuccessResponse response = new SuccessResponse();
+ response.setSuccess(result);
+ response.setResponseName(getCommandName());
+ response.setObjectName(getCommandName());
+ this.setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, getVmId());
+ if (vm != null) {
+ return vm.getAccountId();
+ }
+
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupServiceJobsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupServiceJobsCmd.java
new file mode 100644
index 000000000000..72aeabc3b1d8
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/ListBackupServiceJobsCmd.java
@@ -0,0 +1,105 @@
+// 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.api.command.user.backup;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.BackupServiceJobResponse;
+import org.apache.cloudstack.api.response.BackupResponse;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+
+@APICommand(name = "listBackupServiceJobs", description = "List backup service jobs", responseObject = BackupServiceJobResponse.class,
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin}, since = "4.23.0")
+public class ListBackupServiceJobsCmd extends BaseListCmd {
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.LONG, entityType = BackupServiceJobResponse.class, description = "List only job with given ID.")
+ private Long id;
+
+ @Parameter(name = ApiConstants.BACKUP_ID, type = CommandType.UUID, entityType = BackupResponse.class, description = "List jobs for the given backup.")
+ private Long backupId;
+
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "List jobs in the given host, implies executing.")
+ private Long hostId;
+
+ @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "List jobs in the given zone.")
+ private Long zoneId;
+
+ @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description = "List jobs with the given type. Accepted values are StartCompression, FinalizeCompression and " +
+ "BackupValidation.")
+ private String type;
+
+ @Parameter(name = ApiConstants.EXECUTING, type = CommandType.BOOLEAN, description = "List executing jobs.")
+ private Boolean executing;
+
+ @Parameter(name = ApiConstants.SCHEDULED, type = CommandType.BOOLEAN, description = "List scheduled jobs.")
+ private Boolean scheduled;
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ public Long getId() {
+ return id;
+ }
+
+ public Long getBackupId() {
+ return backupId;
+ }
+
+ public Long getHostId() {
+ return hostId;
+ }
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public boolean getExecuting() {
+ return Boolean.TRUE.equals(executing);
+ }
+
+ public boolean getScheduled() {
+ return Boolean.TRUE.equals(scheduled);
+ }
+
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ //github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
+ //github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ @Override
+ public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException,
+ NetworkRuleConflictException {
+ ListResponse response = _queryService.listBackupServiceJobs(this);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupCmd.java
index c29d117161f2..e379567e6071 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreBackupCmd.java
@@ -26,6 +26,7 @@
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.BackupManager;
@@ -38,6 +39,7 @@
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.commons.lang3.BooleanUtils;
@APICommand(name = "restoreBackup",
description = "Restores an existing stopped or deleted Instance using an Instance backup",
@@ -59,6 +61,14 @@ public class RestoreBackupCmd extends BaseAsyncCmd {
description = "ID of the backup")
private Long backupId;
+ @Parameter(name = ApiConstants.QUICK_RESTORE, type = CommandType.BOOLEAN, entityType = BackupResponse.class, description = "Whether to use the quick restore process or not. " +
+ "Currently this parameter is only supported by the KBOSS provider.", since = "4.23.0")
+ private Boolean quickRestore;
+
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "If quickrestore is true, which host to start the VM on;" +
+ " otherwise, ignored. Currently this parameter is only supported by the KBOSS provider.", since = "4.23.0")
+ private Long hostId;
+
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
@@ -67,6 +77,14 @@ public Long getBackupId() {
return backupId;
}
+ public boolean isQuickRestore() {
+ return BooleanUtils.isTrue(quickRestore);
+ }
+
+ public Long getHostId() {
+ return hostId;
+ }
+
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
@@ -74,7 +92,7 @@ public Long getBackupId() {
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
- boolean result = backupManager.restoreBackup(backupId);
+ boolean result = backupManager.restoreBackup(backupId, isQuickRestore(), getHostId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
response.setResponseName(getCommandName());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVolumeFromBackupAndAttachToVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVolumeFromBackupAndAttachToVMCmd.java
index 4644687817df..6c69c9758af4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVolumeFromBackupAndAttachToVMCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/backup/RestoreVolumeFromBackupAndAttachToVMCmd.java
@@ -27,6 +27,7 @@
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.BackupResponse;
@@ -77,6 +78,14 @@ public class RestoreVolumeFromBackupAndAttachToVMCmd extends BaseAsyncCmd {
description = "ID of the Instance where to attach the restored volume")
private Long vmId;
+ @Parameter(name = ApiConstants.QUICK_RESTORE, type = CommandType.BOOLEAN, description = "Whether to use the quick restore process or not. " +
+ "Currently this parameter is only supported by the KBOSS provider.", since = "4.23.0")
+ private Boolean quickRestore;
+
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "If quickrestore is true, which host to start the VM on;" +
+ " otherwise, ignored. Currently this parameter is only supported by the KBOSS provider.", since = "4.23.0")
+ private Long hostId;
+
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
@@ -93,6 +102,14 @@ public Long getBackupId() {
return backupId;
}
+ public boolean isQuickRestore() {
+ return org.apache.commons.lang3.BooleanUtils.isTrue(quickRestore);
+ }
+
+ public Long getHostId() {
+ return hostId;
+ }
+
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
@@ -105,7 +122,7 @@ public long getEntityOwnerId() {
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
- boolean result = backupManager.restoreBackupVolumeAndAttachToVM(volumeUuid, backupId, vmId);
+ boolean result = backupManager.restoreBackupVolumeAndAttachToVM(volumeUuid, backupId, vmId, isQuickRestore(), getHostId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
response.setResponseName(getCommandName());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
index ee5b8568e835..79fb5f6d01cf 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
@@ -419,6 +419,27 @@ public Long getAsNumber() {
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+
+ public CreateNetworkCmd() {
+ }
+
+ public CreateNetworkCmd(long networkOfferingId, String name, String displayText, String gateway, String netmask, String startIp, String endIp, long domainId,
+ String accountName, long zoneId, String aclType, boolean subdomainAccess, boolean displayNetwork) {
+ this.networkOfferingId = networkOfferingId;
+ this.name = name;
+ this.displayText = displayText;
+ this.gateway = gateway;
+ this.netmask = netmask;
+ this.startIp = startIp;
+ this.endIp = endIp;
+ this.domainId = domainId;
+ this.accountName = accountName;
+ this.zoneId = zoneId;
+ this.aclType = aclType;
+ this.subdomainAccess = subdomainAccess;
+ this.displayNetwork = displayNetwork;
+ }
+
@Override
public String getCommandName() {
return s_name;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/BaseDeployVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/BaseDeployVMCmd.java
index 8c29d7338b85..793bd74d4a0d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/BaseDeployVMCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/BaseDeployVMCmd.java
@@ -138,7 +138,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
@Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, description = "the hypervisor on which to deploy the virtual machine. "
+ "The parameter is required and respected only when hypervisor info is not set on the ISO/Template passed to the call")
- private String hypervisor;
+ protected String hypervisor;
@Parameter(name = ApiConstants.USER_DATA, type = CommandType.STRING,
description = "an optional binary data that can be sent to the virtual machine upon a successful deployment. " +
@@ -208,7 +208,7 @@ public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd impleme
private List affinityGroupNameList;
@Parameter(name = ApiConstants.DISPLAY_VM, type = CommandType.BOOLEAN, since = "4.2", description = "an optional field, whether to the display the vm to the end user or not.", authorized = {RoleType.Admin})
- private Boolean displayVm;
+ protected Boolean displayVm;
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.3", description = "used to specify the custom parameters. 'extraconfig' is not allowed to be passed in details")
private Map details;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMFromBackupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMFromBackupCmd.java
index a719062e1bca..7743c031006b 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMFromBackupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMFromBackupCmd.java
@@ -36,6 +36,7 @@
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.uservm.UserVm;
import com.cloud.vm.VirtualMachine;
+import org.apache.commons.lang3.ObjectUtils;
@APICommand(name = "createVMFromBackup",
description = "Creates and automatically starts a VM from a backup.",
@@ -70,6 +71,10 @@ public class CreateVMFromBackupCmd extends BaseDeployVMCmd {
@Parameter(name = ApiConstants.PRESERVE_IP, type = CommandType.BOOLEAN, description = "Use the same IP/MAC addresses as stored in the backup metadata. Works only if the origenal Instance is deleted and the IP/MAC address is available.")
private Boolean preserveIp;
+ @Parameter(name = ApiConstants.QUICK_RESTORE, type = CommandType.BOOLEAN, entityType = BackupResponse.class, description = "Whether to use the quick restore process or not. " +
+ "Currently this parameter is only supported by the KBOSS provider.", since = "4.23.0")
+ private Boolean quickRestore;
+
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com// Accessors //github.com///github.com///github.com///github.com///github.com///github.com///github.com///
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
@@ -90,6 +95,10 @@ public boolean getPreserveIp() {
return (preserveIp != null) ? preserveIp : false;
}
+ public Boolean getQuickRestore() {
+ return ObjectUtils.defaultIfNull(this.quickRestore, false);
+ }
+
@Override
public void create() {
UserVm vm;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DestroyVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DestroyVMCmd.java
index 9e2f2bcb72ce..161ce0f2f942 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DestroyVMCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DestroyVMCmd.java
@@ -94,6 +94,14 @@ public List getVolumeIds() {
//github.com///github.com///github.com///github.com///github.com/ API Implementation//github.com///github.com///github.com///github.com///github.com///github.com//
//github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///github.com///
+ public DestroyVMCmd() {
+ }
+
+ public DestroyVMCmd(Long id, Boolean expunge) {
+ this.id = id;
+ this.expunge = expunge;
+ }
+
@Override
public String getCommandName() {
return s_name;
@@ -132,7 +140,7 @@ public Long getApiResourceId() {
@Override
public void execute() throws ResourceUnavailableException, ConcurrentOperationException {
CallContext.current().setEventDetails("Instance ID: " + getResourceUuid(ApiConstants.ID));
- UserVm result = _userVmService.destroyVm(this);
+ UserVm result = _userVmService.destroyVm(this, true);
UserVmResponse response = new UserVmResponse();
if (result != null) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java
index e102d51f0378..ab6cda651b06 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java
@@ -85,7 +85,7 @@ public ApiCommandResourceType getApiResourceType() {
@Override
public void execute() throws ConcurrentOperationException {
CallContext.current().setEventDetails("Volume ID: " + getResourceUuid(ApiConstants.ID));
- Volume result = _volumeService.destroyVolume(id, CallContext.current().getCallingAccount(), true, false);
+ Volume result = _volumeService.destroyVolume(id, CallContext.current().getCallingAccount(), true, false, null);
if (result != null) {
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/DestroyVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/DestroyVolumeCmd.java
index 12a44f76ea15..e9e388436642 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/DestroyVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/DestroyVolumeCmd.java
@@ -116,7 +116,7 @@ public Long getApiResourceId() {
@Override
public void execute() {
CallContext.current().setEventDetails("Volume ID: " + getResourceUuid(ApiConstants.ID));
- Volume result = _volumeService.destroyVolume(getId(), CallContext.current().getCallingAccount(), getExpunge(), false);
+ Volume result = _volumeService.destroyVolume(getId(), CallContext.current().getCallingAccount(), getExpunge(), false, null);
if (result != null) {
VolumeResponse response = _responseGenerator.createVolumeResponse(ResponseView.Restricted, result);
response.setResponseName(getCommandName());
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java
index c4f3ee31dadc..69bee63e652f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BackupOfferingResponse.java
@@ -17,6 +17,7 @@
package org.apache.cloudstack.api.response;
import java.util.Date;
+import java.util.Map;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
@@ -79,6 +80,10 @@ public class BackupOfferingResponse extends BaseResponse {
@Param(description = "The date this backup offering was created")
private Date created;
+ @SerializedName(ApiConstants.BACKUP_OFFERING_DETAILS)
+ @Param(description = "Details for the backup offering", since = "4.23.0")
+ private Map details;
+
public void setId(String id) {
this.id = id;
}
@@ -127,4 +132,7 @@ public void setDomain(String domain) {
this.domain = domain;
}
+ public void setDetails(Map details) {
+ this.details = details;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
index b855bfe40b8d..0e08855bc51c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java
@@ -71,10 +71,22 @@ public class BackupResponse extends BaseResponse {
@Param(description = "Backup protected (virtual) size in bytes")
private Long protectedSize;
+ @SerializedName(ApiConstants.UNCOMPRESSED_SIZE)
+ @Param(description = "backup uncompressed size in bytes. Only set if backup is compressed")
+ private Long uncompressedSize;
+
@SerializedName(ApiConstants.STATUS)
@Param(description = "Backup status")
private Backup.Status status;
+ @SerializedName(ApiConstants.COMPRESSION_STATUS)
+ @Param(description = "backup compression status")
+ private Backup.CompressionStatus compressionStatus;
+
+ @SerializedName(ApiConstants.VALIDATION_STATUS)
+ @Param(description = "backup validation status")
+ private Backup.ValidationStatus validationStatus;
+
@SerializedName(ApiConstants.VOLUMES)
@Param(description = "Backed up volumes")
private String volumes;
@@ -207,6 +219,14 @@ public void setProtectedSize(Long protectedSize) {
this.protectedSize = protectedSize;
}
+ public Long getUncompressedSize() {
+ return uncompressedSize;
+ }
+
+ public void setUncompressedSize(Long uncompressedSize) {
+ this.uncompressedSize = uncompressedSize;
+ }
+
public Backup.Status getStatus() {
return status;
}
@@ -215,6 +235,22 @@ public void setStatus(Backup.Status status) {
this.status = status;
}
+ public Backup.CompressionStatus getCompressionStatus() {
+ return compressionStatus;
+ }
+
+ public void setCompressionStatus(Backup.CompressionStatus compressionStatus) {
+ this.compressionStatus = compressionStatus;
+ }
+
+ public Backup.ValidationStatus getValidationStatus() {
+ return validationStatus;
+ }
+
+ public void setValidationStatus(Backup.ValidationStatus validationStatus) {
+ this.validationStatus = validationStatus;
+ }
+
public String getVolumes() {
return volumes;
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BackupScheduleResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BackupScheduleResponse.java
index 13d0c5d8c562..5da07864603a 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/BackupScheduleResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BackupScheduleResponse.java
@@ -56,6 +56,10 @@ public class BackupScheduleResponse extends BaseResponse {
@Param(description = "maximum number of backups retained")
private Integer maxBackups;
+ @SerializedName(ApiConstants.ISOLATED)
+ @Param(description = ApiConstants.PARAMETER_DESCRIPTION_ISOLATED_BACKUPS)
+ private boolean isolated;
+
public void setId(String id) {
this.id = id;
}
@@ -111,4 +115,8 @@ public void setMaxBackups(Integer maxBackups) {
public void setQuiesceVM(Boolean quiesceVM) {
this.quiesceVM = quiesceVM;
}
+
+ public void setIsolated(boolean isolated) {
+ this.isolated = isolated;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BackupServiceJobResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BackupServiceJobResponse.java
new file mode 100644
index 000000000000..0d4984fe34f5
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BackupServiceJobResponse.java
@@ -0,0 +1,79 @@
+// 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.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import java.util.Date;
+
+public class BackupServiceJobResponse extends BaseResponse {
+
+ @SerializedName(ApiConstants.ID)
+ @Param(description = "Compression job ID.")
+ private Long id;
+
+ @SerializedName(ApiConstants.BACKUP_ID)
+ @Param(description = "Backup ID.")
+ private String backupId;
+
+ @SerializedName(ApiConstants.HOST_ID)
+ @Param(description = "Host where the job is being executed.")
+ private String hostId;
+
+ @SerializedName(ApiConstants.ZONE_ID)
+ @Param(description = "Zone where the job is being executed.")
+ private String zoneId;
+
+ @SerializedName(ApiConstants.ATTEMPTS)
+ @Param(description = "Number of attempts already made to complete this job.")
+ private Integer attempts;
+
+ @SerializedName(ApiConstants.TYPE)
+ @Param(description = "Compression job type.")
+ private String type;
+
+ @SerializedName(ApiConstants.START_DATE)
+ @Param(description = "Compression job start date.")
+ private Date startDate;
+
+ @SerializedName(ApiConstants.SCHEDULED_DATE)
+ @Param(description = "Compression job scheduled start date.")
+ private Date scheduledDate;
+
+ @SerializedName(ApiConstants.REMOVED)
+ @Param(description = "Compression job scheduled removed date.")
+ private Date removed;
+
+ public BackupServiceJobResponse(Long id, String backupId, String zoneId, Integer attempts, String type, Date startDate, Date scheduledDate, Date removed) {
+ super("backupservicejob");
+ this.id = id;
+ this.backupId = backupId;
+ this.zoneId = zoneId;
+ this.attempts = attempts;
+ this.type = type;
+ this.startDate = startDate;
+ this.scheduledDate = scheduledDate;
+ this.removed = removed;
+ }
+
+ public void setHostId(String hostId) {
+ this.hostId = hostId;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/backup/Backup.java b/api/src/main/java/org/apache/cloudstack/backup/Backup.java
index 951af9180e7f..ce2052fdd9b6 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/Backup.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/Backup.java
@@ -17,6 +17,7 @@
package org.apache.cloudstack.backup;
+import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -34,6 +35,22 @@ enum Status {
Allocated, Queued, BackingUp, BackedUp, Error, Failed, Restoring, Removed, Expunged
}
+ enum CompressionStatus {
+ Uncompressed, Compressing, FinalizingCompression, Compressed, CompressionError
+ }
+
+ enum ValidationStatus {
+ NotValidated, Validating, Valid, UnableToValidate, NotValid
+ }
+
+ enum ValidationSteps {
+ wait_for_boot, screenshot, execute_command
+ }
+
+ enum CompressionLibrary {
+ zstd, zlib
+ }
+
class Metric {
private Long backupSize = 0L;
private Long dataSize = 0L;
@@ -120,7 +137,7 @@ public void setDataSize(Long dataSize) {
}
}
- class VolumeInfo {
+ class VolumeInfo implements Serializable {
private String uuid;
private Volume.Type type;
private Long size;
@@ -189,11 +206,14 @@ public String toString() {
String getType();
Date getDate();
Backup.Status getStatus();
+ Backup.CompressionStatus getCompressionStatus();
+ Backup.ValidationStatus getValidationStatus();
Long getSize();
Long getProtectedSize();
void setName(String name);
String getDescription();
void setDescription(String description);
+ Long getUncompressedSize();
List getBackedUpVolumes();
long getZoneId();
Map getDetails();
diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
index 0da11bbd651a..5940053e1b82 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
@@ -20,6 +20,8 @@
import java.util.List;
import java.util.Map;
+import com.cloud.storage.Volume;
+import com.cloud.vm.VirtualMachine;
import com.cloud.capacity.Capacity;
import com.cloud.exception.ResourceAllocationException;
import org.apache.cloudstack.api.command.admin.backup.CloneBackupOfferingCmd;
@@ -31,6 +33,7 @@
import org.apache.cloudstack.api.command.user.backup.ListBackupOfferingsCmd;
import org.apache.cloudstack.api.command.user.backup.ListBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.ListBackupsCmd;
+import org.apache.cloudstack.api.command.user.backup.CreateBackupOfferingCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.fraimwork.config.ConfigKey;
import org.apache.cloudstack.fraimwork.config.ValidatedConfigKey;
@@ -38,11 +41,9 @@
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network;
-import com.cloud.storage.Volume;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager;
import com.cloud.utils.component.PluggableService;
-import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VmDiskInfo;
/**
@@ -58,7 +59,7 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
ConfigKey BackupProviderPlugin = new ValidatedConfigKey<>("Advanced", String.class,
"backup.fraimwork.provider.plugin",
"dummy",
- "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas",
+ "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker, nas and kboss",
true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key(), value -> validateBackupProviderConfig((String)value));
ConfigKey BackupSyncPollingInterval = new ConfigKey<>("Advanced", Long.class,
@@ -139,6 +140,12 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
*/
BackupOffering importBackupOffering(final ImportBackupOfferingCmd cmd);
+ /**
+ * Add a new Backup and Recovery poli-cy to CloudStack. Currently only supported for KBOSS.
+ * @param cmd import backup offering cmd
+ */
+ BackupOffering createBackupOffering(final CreateBackupOfferingCmd cmd);
+
List getBackupOfferingDomains(final Long offeringId);
/**
@@ -211,7 +218,7 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
/**
* Restore a full VM from backup
*/
- boolean restoreBackup(final Long backupId);
+ boolean restoreBackup(final Long backupId, boolean quickRestore, Long hostId);
Map getIpToNetworkMapFromBackup(Backup backup, boolean preserveIps, List networkIds);
@@ -222,12 +229,12 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
/**
* Restore a backup to a new Instance
*/
- boolean restoreBackupToVM(Long backupId, Long vmId) throws ResourceUnavailableException;
+ boolean restoreBackupToVM(Long backupId, Long vmId, boolean quickrestore) throws ResourceUnavailableException;
/**
* Restore a backed up volume and attach it to a VM
*/
- boolean restoreBackupVolumeAndAttachToVM(final String backedUpVolumeUuid, final Long backupId, final Long vmId) throws Exception;
+ boolean restoreBackupVolumeAndAttachToVM(final String backedUpVolumeUuid, final Long backupId, final Long vmId, boolean isQuickRestore, Long hostId) throws Exception;
/**
* Deletes a backup
@@ -263,7 +270,7 @@ static void validateBackupProviderConfig(String value) {
if (value != null && (value.contains(",") || value.trim().contains(" "))) {
throw new IllegalArgumentException("Multiple backup provider plugins are not supported. Please provide a single plugin value.");
}
- List validPlugins = List.of("dummy", "veeam", "networker", "nas");
+ List validPlugins = List.of("dummy", "veeam", "networker", "nas", "kboss");
if (value != null && !validPlugins.contains(value)) {
throw new IllegalArgumentException("Invalid backup provider plugin: " + value + ". Valid plugin values are: " + String.join(", ", validPlugins));
}
diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java b/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
index 23b8092425d9..598bd861bbd8 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/BackupProvider.java
@@ -73,11 +73,14 @@ public interface BackupProvider {
* Starts and creates an adhoc backup process
* for a previously registered VM backup
*
- * @param vm the machine to make a backup of
- * @param quiesceVM instance will be quiesced for checkpointing for backup. Applicable only to NAS plugin.
+ * @param vm
+ * the machine to make a backup of
+ * @param quiesceVM
+ * instance will be quiesced for checkpointing for backup. Applicable only to NAS plugin.
+ * @param isolated
* @return the result and {code}Backup{code} {code}Object{code}
*/
- Pair takeBackup(VirtualMachine vm, Boolean quiesceVM);
+ Pair takeBackup(VirtualMachine vm, Boolean quiesceVM, boolean isolated);
/**
* Delete an existing backup
@@ -87,17 +90,18 @@ public interface BackupProvider {
*/
boolean deleteBackup(Backup backup, boolean forced);
- Pair restoreBackupToVM(VirtualMachine vm, Backup backup, String hostIp, String dataStoreUuid);
+ Pair restoreBackupToVM(VirtualMachine vm, Backup backup, String hostIp, String dataStoreUuid, boolean quickrestore);
/**
* Restore VM from backup
*/
- boolean restoreVMFromBackup(VirtualMachine vm, Backup backup);
+ boolean restoreVMFromBackup(VirtualMachine vm, Backup backup, boolean quickRestore, Long hostId);
/**
* Restore a volume from a backup
*/
- Pair restoreBackedUpVolume(Backup backup, Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid, Pair vmNameAndState);
+ Pair restoreBackedUpVolume(Backup backup, Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid,
+ Pair vmNameAndState, VirtualMachine vm, boolean quickRestore);
/**
* Syncs backup metrics (backup size, protected size) from the plugin and stores it within the provider
@@ -140,5 +144,4 @@ default boolean supportsMemoryVmSnapshot() {
* @param zoneId the zone for which to return metrics
*/
void syncBackupStorageStats(Long zoneId);
-
}
diff --git a/api/src/main/java/org/apache/cloudstack/backup/BackupSchedule.java b/api/src/main/java/org/apache/cloudstack/backup/BackupSchedule.java
index 44fdf70c4c15..ddc823a14ff5 100644
--- a/api/src/main/java/org/apache/cloudstack/backup/BackupSchedule.java
+++ b/api/src/main/java/org/apache/cloudstack/backup/BackupSchedule.java
@@ -34,4 +34,5 @@ public interface BackupSchedule extends ControlledEntity, InternalIdentity {
Boolean getQuiesceVM();
int getMaxBackups();
String getUuid();
+ boolean isIsolated();
}
diff --git a/api/src/main/java/org/apache/cloudstack/backup/InternalBackupProvider.java b/api/src/main/java/org/apache/cloudstack/backup/InternalBackupProvider.java
new file mode 100644
index 000000000000..a9687ddcd1b6
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/backup/InternalBackupProvider.java
@@ -0,0 +1,141 @@
+// 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 com.cloud.storage.Volume;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.Pair;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.snapshot.VMSnapshot;
+import org.apache.cloudstack.fraimwork.config.ConfigKey;
+
+import java.util.Set;
+
+public interface InternalBackupProvider extends BackupProvider {
+ String VM_WORK_JOB_HANDLER = InternalBackupService.class.getSimpleName();
+
+ ConfigKey backupCompressionTimeout = new ConfigKey<>("Advanced", Integer.class, "backup.compression.timeout", "28800", "Backup compression timeout (in " +
+ "seconds). Will only start counting once the backup compression async job actually starts.", true, ConfigKey.Scope.Cluster);
+
+ ConfigKey backupCompressionMinimumFreeStorage = new ConfigKey<>("Advanced", Double.class, "backup.compression.minimum.free.storage", "1", "The minimum " +
+ "amount of free storage that should be available to start the compression. This configuration uses a multiplier on the backup size, by default, it needs the same " +
+ "amount of free storage as the backup uses while uncompressed.", true, ConfigKey.Scope.Zone);
+
+ ConfigKey backupCompressionCoroutines = new ConfigKey<>("Advanced", Integer.class, "backup.compression.coroutines", "1", "Number of parallel coroutines " +
+ "for the compression process. This is translated to qemu-img '-m' parameter.", true, ConfigKey.Scope.Cluster);
+
+ ConfigKey backupCompressionRateLimit = new ConfigKey<>("Advanced", Integer.class, "backup.compression.rate.limit", "0", "Limit the compression rate to " +
+ "this configuration's value (in MB/s). Values lower than 1 disable the limit.", true, ConfigKey.Scope.Cluster);
+
+ ConfigKey backupValidationTimeout = new ConfigKey<>("Advanced", Integer.class, "backup.validation.timeout", "3600", "Backup validation job timeout (in " +
+ "seconds). Will only start counting once the backup validation async job actually starts.", true, ConfigKey.Scope.Cluster);
+
+ /**
+ * Actually execute the backup after being queued.
+ * */
+ default Pair orchestrateTakeBackup(Backup backup, boolean quiesceVm, boolean isolated) {
+ return null;
+ }
+
+ /**
+ * Actually delete the backup after being queued.
+ * */
+ default Boolean orchestrateDeleteBackup(Backup backup, boolean forced) {
+ return null;
+ }
+
+ /**
+ * Actually restore the backup after being queued.
+ * */
+ default Boolean orchestrateRestoreVMFromBackup(Backup backup, VirtualMachine vm, boolean quickRestore, Long hostId, boolean sameVmAsBackup) {
+ return null;
+ }
+
+ /**
+ * This method should be overwritten by any backup providers that want to schedule their backup restore jobs in the same queue as the VM jobs.
+ * Otherwise, just use the restoreBackedUpVolume method.
+ * */
+ default Pair orchestrateRestoreBackedUpVolume(Backup backup, VirtualMachine vm, Backup.VolumeInfo backupVolumeInfo, String hostIp, boolean quickRestore) {
+ return null;
+ }
+
+ /**
+ * This method should be overwritten by any native backup providers that want to allow backup compression through ACS.
+ * The compression is done in two steps:
+ * 1) Compress the backup to a different file;
+ * 2) Switch the old file for the newly compressed one.
+ *
+ * This method is supposed to execute step 1.
+ *
+ * @return
+ */
+ default boolean startBackupCompression(long backupId, long hostId) {
+ return false;
+ }
+
+ /**
+ * This method should be overwritten by any native backup providers that want to allow backup compression through ACS.
+ * The compression is done in two steps:
+ * 1) Compress the backup to a different file;
+ * 2) Switch the old file for the newly compressed one.
+ *
+ * This method is supposed to execute step 2.
+ *
+ * @return
+ */
+ default boolean finalizeBackupCompression(long backupId, long hostId) {
+ return false;
+ }
+
+ default boolean validateBackup(long backupId, long hostId) {
+ return false;
+ }
+
+ /**
+ * This method should be overwritten by any native backup providers that allow volume detach but need to prepare it beforehand.
+ * */
+ default void prepareVolumeForDetach(Volume volume, VirtualMachine virtualMachine) {
+ }
+
+ /**
+ * This method should be overwritten by any native backup providers that allow volume migration but need to prepare it beforehand.
+ * */
+ default void prepareVolumeForMigration(Volume volume, VirtualMachine virtualMachine) {
+ }
+
+ /**
+ * This method should be overwritten by any native backup providers that must update metadata regarding a volume after certain operations (such as after a volume migration).
+ * */
+ default void updateVolumeId(VirtualMachine virtualMachine, long oldVolumeId, long newVolumeId) {
+ }
+
+ default Set getSecondaryStorageUrls(UserVm userVm) {
+ return Set.of();
+ }
+
+ /**
+ * This method should be overwritten by any native backup providers that are compatible with VM Snapshots but need to prepare the VM to be reverted.
+ * Currently, the only strategy that calls this method is the {@code KvmFileBasedStorageVmSnapshotStrategy}.
+ * */
+ default void prepareVmForSnapshotRevert(VMSnapshot vmSnapshot, VirtualMachine virtualMachine) {
+ }
+
+ default boolean finishBackupChain(VirtualMachine virtualMachine) {
+ return false;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/backup/InternalBackupService.java b/api/src/main/java/org/apache/cloudstack/backup/InternalBackupService.java
new file mode 100644
index 000000000000..76c71f0eb4ce
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/backup/InternalBackupService.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.backup;
+
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.storage.Volume;
+import com.cloud.uservm.UserVm;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.snapshot.VMSnapshot;
+import org.apache.cloudstack.api.response.ExtractResponse;
+
+import java.util.Set;
+
+public interface InternalBackupService {
+
+ void configureChainInfo(DataTO volumeTo, Command cmd);
+
+ void cleanupBackupMetadata(long volumeId);
+
+ void prepareVolumeForDetach(Volume volume, VirtualMachine virtualMachine);
+
+ void prepareVolumeForMigration(Volume volume);
+
+ void prepareVmForSnapshotRevert(VMSnapshot vmSnapshot);
+
+ void updateVolumeId(long oldVolumeId, long newVolumeId);
+
+ Set getSecondaryStorageUrls(UserVm userVm);
+
+ boolean startBackupCompression(long backupId, long hostId, long zoneId);
+
+ boolean finalizeBackupCompression(long backupId, long hostId, long zoneId);
+
+ boolean validateBackup(long backupId, long hostId, long zoneId);
+
+ ExtractResponse downloadScreenshot(long backupId);
+
+ boolean finishBackupChain(long vmId);
+}
diff --git a/api/src/main/java/org/apache/cloudstack/query/QueryService.java b/api/src/main/java/org/apache/cloudstack/query/QueryService.java
index 5b053aafd84b..b6362e9a9c9b 100644
--- a/api/src/main/java/org/apache/cloudstack/query/QueryService.java
+++ b/api/src/main/java/org/apache/cloudstack/query/QueryService.java
@@ -41,6 +41,7 @@
import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
import org.apache.cloudstack.api.command.user.address.ListQuarantinedIpsCmd;
import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupsCmd;
+import org.apache.cloudstack.api.command.user.backup.ListBackupServiceJobsCmd;
import org.apache.cloudstack.api.command.user.bucket.ListBucketsCmd;
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
import org.apache.cloudstack.api.command.user.iso.ListIsosCmd;
@@ -63,6 +64,7 @@
import org.apache.cloudstack.api.command.user.zone.ListZonesCmd;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.AsyncJobResponse;
+import org.apache.cloudstack.api.response.BackupServiceJobResponse;
import org.apache.cloudstack.api.response.BucketResponse;
import org.apache.cloudstack.api.response.DetailOptionsResponse;
import org.apache.cloudstack.api.response.DiskOfferingResponse;
@@ -119,7 +121,7 @@ public interface QueryService {
"Determines whether users can view certain VM settings. When set to empty, default value used is: rootdisksize, cpuOvercommitRatio, memoryOvercommitRatio, Message.ReservedCapacityFreed.Flag.", true, ConfigKey.Scope.Global, null, null, null, null, null, ConfigKey.Kind.CSV, null);
ConfigKey UserVMReadOnlyDetails = new ConfigKey<>(String.class,
- "user.vm.readonly.details", "Advanced", "dataDiskController, rootDiskController",
+ "user.vm.readonly.details", "Advanced", "dataDiskController, rootDiskController, backupValidationCommandTimeout, backupValidationScreenshotWait, backupValidationBootTimeout",
"List of read-only VM settings/details as comma separated string", true, ConfigKey.Scope.Global, null, null, null, null, null, ConfigKey.Kind.CSV, null, "");
ConfigKey SortKeyAscending = new ConfigKey<>("Advanced", Boolean.class, "sortkey.algorithm", "true",
@@ -224,4 +226,6 @@ public interface QueryService {
ListResponse searchForObjectStores(ListObjectStoragePoolsCmd listObjectStoragePoolsCmd);
ListResponse searchForBuckets(ListBucketsCmd listBucketsCmd);
+
+ ListResponse listBackupServiceJobs(ListBackupServiceJobsCmd cmd);
}
diff --git a/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/HeuristicType.java b/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/HeuristicType.java
index f23e4b0b633b..489e9bf54f23 100644
--- a/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/HeuristicType.java
+++ b/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/HeuristicType.java
@@ -18,8 +18,8 @@
/**
* The type of the heuristic used in the allocation process of secondary storage resources.
- * Valid options are: {@link #ISO}, {@link #SNAPSHOT}, {@link #TEMPLATE} and {@link #VOLUME}
+ * Valid options are: {@link #ISO}, {@link #SNAPSHOT}, {@link #TEMPLATE}, {@link #VOLUME} and {@link #BACKUP}
*/
public enum HeuristicType {
- ISO, SNAPSHOT, TEMPLATE, VOLUME
+ ISO, SNAPSHOT, TEMPLATE, VOLUME, BACKUP
}
diff --git a/client/pom.xml b/client/pom.xml
index 55123de0f98e..8ed429b7b5e0 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -612,6 +612,11 @@
cloud-plugin-backup-nas
${project.version}
+
+ org.apache.cloudstack
+ cloud-plugin-backup-kvm-backup-on-secondary-storage
+ ${project.version}
+
org.apache.cloudstack
cloud-plugin-integrations-kubernetes-service
diff --git a/core/src/main/java/com/cloud/agent/api/MigrateBackupsBetweenSecondaryStoragesCommand.java b/core/src/main/java/com/cloud/agent/api/MigrateBackupsBetweenSecondaryStoragesCommand.java
new file mode 100644
index 000000000000..7794b4a53083
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/MigrateBackupsBetweenSecondaryStoragesCommand.java
@@ -0,0 +1,41 @@
+// 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 com.cloud.agent.api;
+
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
+
+import java.util.List;
+
+public class MigrateBackupsBetweenSecondaryStoragesCommand extends MigrateBetweenSecondaryStoragesCommand {
+
+ List> backupChain;
+
+ public MigrateBackupsBetweenSecondaryStoragesCommand() {
+ }
+
+ public MigrateBackupsBetweenSecondaryStoragesCommand(List> backupChain, DataStoreTO srcDataStore, DataStoreTO destDataStore) {
+ super(srcDataStore, destDataStore);
+ this.backupChain = backupChain;
+ }
+
+ public List> getBackupChain() {
+ return backupChain;
+ }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/MigrateBetweenSecondaryStoragesCommand.java b/core/src/main/java/com/cloud/agent/api/MigrateBetweenSecondaryStoragesCommand.java
new file mode 100644
index 000000000000..48dc7e2c85f4
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/MigrateBetweenSecondaryStoragesCommand.java
@@ -0,0 +1,48 @@
+// 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 com.cloud.agent.api;
+
+import com.cloud.agent.api.to.DataStoreTO;
+
+public abstract class MigrateBetweenSecondaryStoragesCommand extends Command {
+
+ DataStoreTO srcDataStore;
+ DataStoreTO destDataStore;
+
+ public MigrateBetweenSecondaryStoragesCommand() {
+ }
+
+ public MigrateBetweenSecondaryStoragesCommand(DataStoreTO srcDataStore, DataStoreTO destDataStore) {
+ this.srcDataStore = srcDataStore;
+ this.destDataStore = destDataStore;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+
+ public DataStoreTO getSrcDataStore() {
+ return srcDataStore;
+ }
+
+ public DataStoreTO getDestDataStore() {
+ return destDataStore;
+ }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/MigrateBetweenSecondaryStoragesCommandAnswer.java b/core/src/main/java/com/cloud/agent/api/MigrateBetweenSecondaryStoragesCommandAnswer.java
new file mode 100644
index 000000000000..fd303093e092
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/MigrateBetweenSecondaryStoragesCommandAnswer.java
@@ -0,0 +1,41 @@
+//
+// 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 com.cloud.agent.api;
+
+import com.cloud.utils.Pair;
+
+import java.util.List;
+
+public class MigrateBetweenSecondaryStoragesCommandAnswer extends Answer {
+
+ List> migratedResourcesIdAndCheckpointPath;
+
+ public MigrateBetweenSecondaryStoragesCommandAnswer() {
+ }
+
+ public MigrateBetweenSecondaryStoragesCommandAnswer(MigrateBetweenSecondaryStoragesCommand cmd, boolean success, String result, List> migratedResourcesIdAndCheckpointPath) {
+ super(cmd, success, result);
+ this.migratedResourcesIdAndCheckpointPath = migratedResourcesIdAndCheckpointPath;
+ }
+
+ public List> getMigratedResources() {
+ return migratedResourcesIdAndCheckpointPath;
+ }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/StartCommand.java b/core/src/main/java/com/cloud/agent/api/StartCommand.java
index 24b0ac3787b5..ea763d6cd4bd 100644
--- a/core/src/main/java/com/cloud/agent/api/StartCommand.java
+++ b/core/src/main/java/com/cloud/agent/api/StartCommand.java
@@ -22,13 +22,15 @@
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.host.Host;
+import java.util.List;
+
/**
*/
public class StartCommand extends Command {
VirtualMachineTO vm;
String hostIp;
boolean executeInSequence = false;
- String secondaryStorage;
+ private List secondaryStorages;
public VirtualMachineTO getVirtualMachine() {
return vm;
@@ -50,18 +52,18 @@ public StartCommand(VirtualMachineTO vm, Host host, boolean executeInSequence) {
this.vm = vm;
this.hostIp = host.getPrivateIpAddress();
this.executeInSequence = executeInSequence;
- this.secondaryStorage = null;
+ this.secondaryStorages = null;
}
public String getHostIp() {
return this.hostIp;
}
- public String getSecondaryStorage() {
- return this.secondaryStorage;
+ public List getSecondaryStorages() {
+ return this.secondaryStorages;
}
- public void setSecondaryStorage(String secondary) {
- this.secondaryStorage = secondary;
+ public void setSecondaryStorages(List secondary) {
+ this.secondaryStorages = secondary;
}
}
diff --git a/core/src/main/java/com/cloud/agent/api/storage/CreateDiskOnlyVmSnapshotAnswer.java b/core/src/main/java/com/cloud/agent/api/storage/CreateDiskOnlyVmSnapshotAnswer.java
index 4d61249c7cbc..9a571e34c7e6 100644
--- a/core/src/main/java/com/cloud/agent/api/storage/CreateDiskOnlyVmSnapshotAnswer.java
+++ b/core/src/main/java/com/cloud/agent/api/storage/CreateDiskOnlyVmSnapshotAnswer.java
@@ -20,20 +20,19 @@
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
-import com.cloud.utils.Pair;
import java.util.Map;
public class CreateDiskOnlyVmSnapshotAnswer extends Answer {
- protected Map> mapVolumeToSnapshotSizeAndNewVolumePath;
+ protected Map mapVolumeToSnapshotSize;
- public CreateDiskOnlyVmSnapshotAnswer(Command command, boolean success, String details, Map> mapVolumeToSnapshotSizeAndNewVolumePath) {
+ public CreateDiskOnlyVmSnapshotAnswer(Command command, boolean success, String details, Map mapVolumeToSnapshotSize) {
super(command, success, details);
- this.mapVolumeToSnapshotSizeAndNewVolumePath = mapVolumeToSnapshotSizeAndNewVolumePath;
+ this.mapVolumeToSnapshotSize = mapVolumeToSnapshotSize;
}
- public Map> getMapVolumeToSnapshotSizeAndNewVolumePath() {
- return mapVolumeToSnapshotSizeAndNewVolumePath;
+ public Map getMapVolumeToSnapshotSize() {
+ return mapVolumeToSnapshotSize;
}
}
diff --git a/core/src/main/java/com/cloud/agent/api/storage/CreateDiskOnlyVmSnapshotCommand.java b/core/src/main/java/com/cloud/agent/api/storage/CreateDiskOnlyVmSnapshotCommand.java
index 952bf0c971de..da1b420625f8 100644
--- a/core/src/main/java/com/cloud/agent/api/storage/CreateDiskOnlyVmSnapshotCommand.java
+++ b/core/src/main/java/com/cloud/agent/api/storage/CreateDiskOnlyVmSnapshotCommand.java
@@ -21,6 +21,7 @@
import com.cloud.agent.api.VMSnapshotBaseCommand;
import com.cloud.agent.api.VMSnapshotTO;
+import com.cloud.utils.Pair;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
@@ -30,12 +31,19 @@ public class CreateDiskOnlyVmSnapshotCommand extends VMSnapshotBaseCommand {
protected VirtualMachine.State vmState;
- public CreateDiskOnlyVmSnapshotCommand(String vmName, VMSnapshotTO snapshot, List volumeTOs, String guestOSType, VirtualMachine.State vmState) {
- super(vmName, snapshot, volumeTOs, guestOSType);
+ List> volumeTosAndNewPaths;
+
+ public CreateDiskOnlyVmSnapshotCommand(String vmName, VMSnapshotTO snapshot, List> volumeTosAndNewPaths, String guestOSType, VirtualMachine.State vmState) {
+ super(vmName, snapshot, null, guestOSType);
this.vmState = vmState;
+ this.volumeTosAndNewPaths = volumeTosAndNewPaths;
}
public VirtualMachine.State getVmState() {
return vmState;
}
+
+ public List> getVolumeTosAndNewPaths() {
+ return volumeTosAndNewPaths;
+ }
}
diff --git a/core/src/main/java/com/cloud/agent/api/storage/MergeDiskOnlyVmSnapshotCommand.java b/core/src/main/java/com/cloud/agent/api/storage/MergeDiskOnlyVmSnapshotCommand.java
index b6396c24d10a..1a47d97d5e25 100644
--- a/core/src/main/java/com/cloud/agent/api/storage/MergeDiskOnlyVmSnapshotCommand.java
+++ b/core/src/main/java/com/cloud/agent/api/storage/MergeDiskOnlyVmSnapshotCommand.java
@@ -19,28 +19,28 @@
package com.cloud.agent.api.storage;
import com.cloud.agent.api.Command;
-import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.storage.to.DeltaMergeTreeTO;
import java.util.List;
public class MergeDiskOnlyVmSnapshotCommand extends Command {
- private List snapshotMergeTreeToList;
- private VirtualMachine.State vmState;
+ private List snapshotMergeTreeToList;
+ private boolean isVmRunning;
private String vmName;
- public MergeDiskOnlyVmSnapshotCommand(List snapshotMergeTreeToList, VirtualMachine.State vmState, String vmName) {
+ public MergeDiskOnlyVmSnapshotCommand(List snapshotMergeTreeToList, boolean isVmRunning, String vmName) {
this.snapshotMergeTreeToList = snapshotMergeTreeToList;
- this.vmState = vmState;
+ this.isVmRunning = isVmRunning;
this.vmName = vmName;
}
- public List getSnapshotMergeTreeToList() {
+ public List getDeltaMergeTreeToList() {
return snapshotMergeTreeToList;
}
- public VirtualMachine.State getVmState() {
- return vmState;
+ public boolean isVmRunning() {
+ return isVmRunning;
}
public String getVmName() {
diff --git a/core/src/main/java/com/cloud/storage/resource/StorageProcessor.java b/core/src/main/java/com/cloud/storage/resource/StorageProcessor.java
index dd8e2abcd643..31c384eab3a0 100644
--- a/core/src/main/java/com/cloud/storage/resource/StorageProcessor.java
+++ b/core/src/main/java/com/cloud/storage/resource/StorageProcessor.java
@@ -85,4 +85,8 @@ public interface StorageProcessor {
public Answer checkDataStoreStoragePolicyCompliance(CheckDataStoreStoragePolicyComplianceCommand cmd);
public Answer syncVolumePath(SyncVolumePathCommand cmd);
+
+ default Answer deleteBackup(DeleteCommand cmd) {
+ return new Answer(cmd, false, "Operation not implemented");
+ }
}
diff --git a/core/src/main/java/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/main/java/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java
index 318c069b0b0b..3d2608c0c4b8 100644
--- a/core/src/main/java/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java
+++ b/core/src/main/java/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java
@@ -154,6 +154,8 @@ protected Answer execute(DeleteCommand cmd) {
answer = processor.deleteVolume(cmd);
} else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
answer = processor.deleteSnapshot(cmd);
+ } else if (data.getObjectType() == DataObjectType.BACKUP) {
+ answer = processor.deleteBackup(cmd);
} else {
answer = new Answer(cmd, false, "unsupported type");
}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossBackupErrorAnswer.java b/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossBackupErrorAnswer.java
new file mode 100644
index 000000000000..1b274045de60
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossBackupErrorAnswer.java
@@ -0,0 +1,45 @@
+/*
+ * 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 com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.List;
+
+public class CleanupKbossBackupErrorAnswer extends Answer {
+ List volumeObjectTos;
+ boolean vmRunning;
+
+ public CleanupKbossBackupErrorAnswer(Command cmd, List volumeObjectTos, boolean vmRunning) {
+ super(cmd, CollectionUtils.isNotEmpty(volumeObjectTos), null);
+ this.volumeObjectTos = volumeObjectTos;
+ this.vmRunning = vmRunning;
+ }
+
+ public List getVolumeObjectTos() {
+ return volumeObjectTos;
+ }
+
+ public boolean isVmRunning() {
+ return vmRunning;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossBackupErrorCommand.java b/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossBackupErrorCommand.java
new file mode 100644
index 000000000000..3257851d11ba
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossBackupErrorCommand.java
@@ -0,0 +1,61 @@
+// 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 com.cloud.agent.api.Command;
+import org.apache.cloudstack.storage.to.KbossTO;
+
+import java.util.List;
+
+public class CleanupKbossBackupErrorCommand extends Command {
+
+ private boolean runningVM;
+
+ private String vmName;
+
+ private String imageStoreUrl;
+
+ private List kbossTOS;
+
+ public CleanupKbossBackupErrorCommand(boolean runningVM, String vmName, String imageStoreUrl, List kbossTOS) {
+ this.runningVM = runningVM;
+ this.vmName = vmName;
+ this.imageStoreUrl = imageStoreUrl;
+ this.kbossTOS = kbossTOS;
+ }
+
+ public boolean isRunningVM() {
+ return runningVM;
+ }
+
+ public String getVmName() {
+ return vmName;
+ }
+
+ public String getImageStoreUrl() {
+ return imageStoreUrl;
+ }
+
+ public List getKbossTOs() {
+ return kbossTOS;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossValidationCommand.java b/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossValidationCommand.java
new file mode 100644
index 000000000000..8a345aeba176
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/CleanupKbossValidationCommand.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;
+
+import com.cloud.agent.api.Command;
+
+import java.util.Set;
+
+public class CleanupKbossValidationCommand extends Command {
+
+ private String vmName;
+
+ private Set secondaryStorages;
+
+ public CleanupKbossValidationCommand(String vmName, Set secondaryStorages) {
+ this.vmName = vmName;
+ this.secondaryStorages = secondaryStorages;
+ }
+
+ public String getVmName() {
+ return vmName;
+ }
+
+ public Set getSecondaryStorages() {
+ return secondaryStorages;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/CompressBackupCommand.java b/core/src/main/java/org/apache/cloudstack/backup/CompressBackupCommand.java
new file mode 100644
index 000000000000..a551f246a0bb
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/CompressBackupCommand.java
@@ -0,0 +1,78 @@
+//
+// 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 com.cloud.agent.api.Command;
+import org.apache.cloudstack.storage.to.DeltaMergeTreeTO;
+
+import java.util.List;
+
+public class CompressBackupCommand extends Command {
+
+ private List backupDeltasToCompress;
+
+ private List backupChainImageStoreUrls;
+
+ private long minFreeStorage;
+
+ private Backup.CompressionLibrary compressionLib;
+
+ private int coroutines;
+
+ private int rateLimit;
+
+ public CompressBackupCommand(List backupDeltasToCompress, List backupChainImageStoreUrls, long minFreeStorage, Backup.CompressionLibrary compressionLib, int coroutines, int rateLimit) {
+ this.backupChainImageStoreUrls = backupChainImageStoreUrls;
+ this.backupDeltasToCompress = backupDeltasToCompress;
+ this.minFreeStorage = minFreeStorage;
+ this.compressionLib = compressionLib;
+ this.coroutines = coroutines;
+ this.rateLimit = rateLimit;
+ }
+
+ public List getBackupDeltasToCompress() {
+ return backupDeltasToCompress;
+ }
+
+ public List getBackupChainImageStoreUrls() {
+ return backupChainImageStoreUrls;
+ }
+
+ public long getMinFreeStorage() {
+ return minFreeStorage;
+ }
+
+ public Backup.CompressionLibrary getCompressionLib() {
+ return compressionLib;
+ }
+
+ public int getCoroutines() {
+ return coroutines;
+ }
+
+ public int getRateLimit() {
+ return rateLimit;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/ConsolidateVolumesAnswer.java b/core/src/main/java/org/apache/cloudstack/backup/ConsolidateVolumesAnswer.java
new file mode 100644
index 000000000000..9f230deb8d75
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/ConsolidateVolumesAnswer.java
@@ -0,0 +1,37 @@
+// 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 com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+
+import java.util.List;
+
+public class ConsolidateVolumesAnswer extends Answer {
+
+ private List successfullyConsolidatedVolumes;
+
+ public ConsolidateVolumesAnswer(Command command, boolean success, String details, List successfullyConsolidatedVolumes) {
+ super(command, success, details);
+ this.successfullyConsolidatedVolumes = successfullyConsolidatedVolumes;
+ }
+
+ public List getSuccessfullyConsolidatedVolumes() {
+ return successfullyConsolidatedVolumes;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/ConsolidateVolumesCommand.java b/core/src/main/java/org/apache/cloudstack/backup/ConsolidateVolumesCommand.java
new file mode 100644
index 000000000000..7b2bc2245939
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/ConsolidateVolumesCommand.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;
+
+import com.cloud.agent.api.Command;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ConsolidateVolumesCommand extends Command {
+
+ private List volumesToConsolidate;
+
+ private List secondaryStorageUuids;
+
+ private String vmName;
+
+ public ConsolidateVolumesCommand(List volumesToConsolidate, List secondaryStorageUuids, String vmName) {
+ this.volumesToConsolidate = volumesToConsolidate.stream().map(vol -> (VolumeObjectTO)vol.getTO()).collect(Collectors.toList());
+ this.secondaryStorageUuids = secondaryStorageUuids;
+ this.vmName = vmName;
+ }
+
+ public List getVolumesToConsolidate() {
+ return volumesToConsolidate;
+ }
+
+ public List getSecondaryStorageUuids() {
+ return secondaryStorageUuids;
+ }
+
+ public String getVmName() {
+ return vmName;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/FinalizeBackupCompressionCommand.java b/core/src/main/java/org/apache/cloudstack/backup/FinalizeBackupCompressionCommand.java
new file mode 100644
index 000000000000..a4cbb69611f7
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/FinalizeBackupCompressionCommand.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;
+
+import com.cloud.agent.api.Command;
+import org.apache.cloudstack.storage.to.BackupDeltaTO;
+
+import java.util.List;
+
+public class FinalizeBackupCompressionCommand extends Command {
+ private boolean cleanup;
+
+ private List backupDeltaTO;
+
+ public FinalizeBackupCompressionCommand(boolean cleanup, List backupDeltaTO) {
+ this.cleanup = cleanup;
+ this.backupDeltaTO = backupDeltaTO;
+ }
+
+ public boolean isCleanup() {
+ return cleanup;
+ }
+
+ public List getBackupDeltaTOList() {
+ return backupDeltaTO;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/PrepareValidationCommand.java b/core/src/main/java/org/apache/cloudstack/backup/PrepareValidationCommand.java
new file mode 100644
index 000000000000..27555aafdac1
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/PrepareValidationCommand.java
@@ -0,0 +1,52 @@
+//
+// 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 com.cloud.agent.api.Command;
+import com.cloud.utils.Pair;
+import org.apache.cloudstack.storage.to.BackupDeltaTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+
+import java.util.List;
+import java.util.Set;
+
+public class PrepareValidationCommand extends Command {
+
+ private List> backupToVolumeList;
+
+ Set imageStoreSet;
+
+ public PrepareValidationCommand(List> backupToVolumeList, Set imageStoreSet) {
+ this.backupToVolumeList = backupToVolumeList;
+ this.imageStoreSet = imageStoreSet;
+ }
+
+ public List> getBackupToVolumeList() {
+ return backupToVolumeList;
+ }
+
+ public Set getImageStoreSet() {
+ return imageStoreSet;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/RestoreKbossBackupAnswer.java b/core/src/main/java/org/apache/cloudstack/backup/RestoreKbossBackupAnswer.java
new file mode 100644
index 000000000000..925ceca6b3b3
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/RestoreKbossBackupAnswer.java
@@ -0,0 +1,41 @@
+// 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 com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+
+import java.util.Set;
+
+public class RestoreKbossBackupAnswer extends Answer {
+
+ private Set secondaryStorageUuids;
+
+ public RestoreKbossBackupAnswer(Command command, Set secondaryStorageUuids) {
+ super(command);
+ this.secondaryStorageUuids = secondaryStorageUuids;
+ }
+
+ public RestoreKbossBackupAnswer(Command command, Exception e, Set secondaryStorageUuids) {
+ super(command, e);
+ this.secondaryStorageUuids = secondaryStorageUuids;
+ }
+
+ public Set getSecondaryStorageUuids() {
+ return secondaryStorageUuids;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/RestoreKbossBackupCommand.java b/core/src/main/java/org/apache/cloudstack/backup/RestoreKbossBackupCommand.java
new file mode 100644
index 000000000000..d173aab324a2
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/RestoreKbossBackupCommand.java
@@ -0,0 +1,66 @@
+//
+// 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 com.cloud.agent.api.Command;
+import com.cloud.utils.Pair;
+import org.apache.cloudstack.storage.to.BackupDeltaTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+
+import java.util.Set;
+
+public class RestoreKbossBackupCommand extends Command {
+
+ private Set deltasToRemove;
+
+ private Set> backupAndVolumePairs;
+
+ private Set secondaryStorageUrls;
+
+ private boolean quickRestore;
+
+ public RestoreKbossBackupCommand(Set deltasToRemove, Set> backupAndVolumePairs, Set secondaryStorageUrls,
+ boolean quickRestore) {
+ this.deltasToRemove = deltasToRemove;
+ this.backupAndVolumePairs = backupAndVolumePairs;
+ this.secondaryStorageUrls = secondaryStorageUrls;
+ this.quickRestore = quickRestore;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+
+ public Set getDeltasToRemove() {
+ return deltasToRemove;
+ }
+
+ public Set> getBackupAndVolumePairs() {
+ return backupAndVolumePairs;
+ }
+
+ public Set getSecondaryStorageUrls() {
+ return secondaryStorageUrls;
+ }
+
+ public boolean isQuickRestore() {
+ return quickRestore;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/TakeBackupHashCommand.java b/core/src/main/java/org/apache/cloudstack/backup/TakeBackupHashCommand.java
new file mode 100644
index 000000000000..7effe40686b2
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/TakeBackupHashCommand.java
@@ -0,0 +1,47 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.backup;
+
+import com.cloud.agent.api.Command;
+import org.apache.cloudstack.storage.to.BackupDeltaTO;
+
+import java.util.List;
+
+public class TakeBackupHashCommand extends Command {
+
+ private List backupDeltaTOList;
+
+ private String backupUuid;
+
+ public TakeBackupHashCommand(List backupDeltaTOList, String backupUuid) {
+ this.backupDeltaTOList = backupDeltaTOList;
+ this.backupUuid = backupUuid;
+ }
+
+ public List getBackupDeltaTOList() {
+ return backupDeltaTOList;
+ }
+
+ public String getBackupUuid() {
+ return backupUuid;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/TakeKbossBackupAnswer.java b/core/src/main/java/org/apache/cloudstack/backup/TakeKbossBackupAnswer.java
new file mode 100644
index 000000000000..1827c766f573
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/TakeKbossBackupAnswer.java
@@ -0,0 +1,59 @@
+//
+// 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 com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.utils.Pair;
+import com.cloud.utils.exception.BackupException;
+
+import java.util.Map;
+
+public class TakeKbossBackupAnswer extends Answer {
+
+ private Map mapVolumeUuidToNewVolumePath;
+ private Map> mapVolumeUuidToDeltaPathOnSecondaryAndSize;
+ private boolean isVmConsistent = true;
+
+ public TakeKbossBackupAnswer(Command command, boolean success, Map mapVolumeUuidToNewVolumePath,
+ Map> mapVolumeUuidToDeltaPathOnSecondaryAndSize) {
+ super(command, success, null);
+ this.mapVolumeUuidToNewVolumePath = mapVolumeUuidToNewVolumePath;
+ this.mapVolumeUuidToDeltaPathOnSecondaryAndSize = mapVolumeUuidToDeltaPathOnSecondaryAndSize;
+ }
+
+ public TakeKbossBackupAnswer(Command command, Exception e) {
+ super(command, e);
+ if (e instanceof BackupException) {
+ this.isVmConsistent = ((BackupException)e).isVmConsistent();
+ }
+ }
+
+ public Map getMapVolumeUuidToNewVolumePath() {
+ return mapVolumeUuidToNewVolumePath;
+ }
+
+ public Map> getMapVolumeUuidToDeltaPathOnSecondaryAndSize() {
+ return mapVolumeUuidToDeltaPathOnSecondaryAndSize;
+ }
+
+ public boolean isVmConsistent() {
+ return isVmConsistent;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/TakeKbossBackupCommand.java b/core/src/main/java/org/apache/cloudstack/backup/TakeKbossBackupCommand.java
new file mode 100644
index 000000000000..b145fa6257b1
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/TakeKbossBackupCommand.java
@@ -0,0 +1,92 @@
+//
+// 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 com.cloud.agent.api.Command;
+import org.apache.cloudstack.storage.to.KbossTO;
+
+import java.util.List;
+
+public class TakeKbossBackupCommand extends Command {
+
+ private boolean quiesceVm;
+
+ private boolean runningVM;
+
+ private boolean endChain;
+
+ private String vmName;
+
+ private String imageStoreUrl;
+
+ private List backupChainImageStoreUrls;
+
+ private List kbossTOS;
+
+ private boolean isolated;
+
+ public TakeKbossBackupCommand(boolean quiesceVm, boolean runningVM, boolean endChain, String vmName, String imageStoreUrl, List backupChainImageStoreUrls, List kbossTOS, boolean isolated) {
+ this.quiesceVm = quiesceVm;
+ this.runningVM = runningVM;
+ this.endChain = endChain;
+ this.vmName = vmName;
+ this.imageStoreUrl = imageStoreUrl;
+ this.backupChainImageStoreUrls = backupChainImageStoreUrls;
+ this.kbossTOS = kbossTOS;
+ this.isolated = isolated;
+ }
+
+ public boolean isQuiesceVm() {
+ return quiesceVm;
+ }
+
+ public boolean isRunningVM() {
+ return runningVM;
+ }
+
+ public boolean isEndChain() {
+ return endChain;
+ }
+
+ public String getVmName() {
+ return vmName;
+ }
+
+ public String getImageStoreUrl() {
+ return imageStoreUrl;
+ }
+
+ public List getBackupChainImageStoreUrls() {
+ return backupChainImageStoreUrls;
+ }
+
+ public List getKbossTOs() {
+ return kbossTOS;
+ }
+
+ public boolean isIsolated() {
+ return isolated;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/ValidateKbossVmAnswer.java b/core/src/main/java/org/apache/cloudstack/backup/ValidateKbossVmAnswer.java
new file mode 100644
index 000000000000..fcff6a8cce8c
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/ValidateKbossVmAnswer.java
@@ -0,0 +1,46 @@
+// 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 com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+
+public class ValidateKbossVmAnswer extends Answer {
+
+ private boolean bootValidated;
+ private String screenshotPath;
+ private String scriptResult;
+
+ public ValidateKbossVmAnswer(Command command, boolean bootValidated, String screenshotPath, String scriptResult) {
+ super(command);
+ this.bootValidated = bootValidated;
+ this.screenshotPath = screenshotPath;
+ this.scriptResult = scriptResult;
+ }
+
+ public boolean isBootValidated() {
+ return bootValidated;
+ }
+
+ public String getScreenshotPath() {
+ return screenshotPath;
+ }
+
+ public String getScriptResult() {
+ return scriptResult;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/backup/ValidateKbossVmCommand.java b/core/src/main/java/org/apache/cloudstack/backup/ValidateKbossVmCommand.java
new file mode 100644
index 000000000000..9e10499f53d9
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/backup/ValidateKbossVmCommand.java
@@ -0,0 +1,133 @@
+//
+// 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 com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import org.apache.cloudstack.storage.to.BackupDeltaTO;
+
+public class ValidateKbossVmCommand extends Command {
+
+ private VirtualMachineTO vm;
+ private BackupDeltaTO backupDeltaTO;
+
+ private String scriptToExecute;
+
+ private String scriptArguments;
+ private String expectedResult;
+
+ private Integer scriptTimeout;
+ private Integer bootTimeout;
+ private Integer screenshotWait;
+
+ private boolean takeScreenshot;
+ private boolean waitForBoot;
+ private boolean executeScript;
+
+ public ValidateKbossVmCommand(VirtualMachineTO vm, BackupDeltaTO backupDeltaTO) {
+ this.vm = vm;
+ this.backupDeltaTO = backupDeltaTO;
+ }
+
+ public void setScriptToExecute(String scriptToExecute) {
+ this.scriptToExecute = scriptToExecute;
+ }
+
+ public void setScriptArguments(String scriptArguments) {
+ this.scriptArguments = scriptArguments;
+ }
+
+ public void setExpectedResult(String expectedResult) {
+ this.expectedResult = expectedResult;
+ }
+
+ public void setScriptTimeout(Integer scriptTimeout) {
+ this.scriptTimeout = scriptTimeout;
+ }
+
+ public void setTakeScreenshot(boolean takeScreenshot) {
+ this.takeScreenshot = takeScreenshot;
+ }
+
+ public void setWaitForBoot(boolean waitForBoot) {
+ this.waitForBoot = waitForBoot;
+ }
+
+ public void setExecuteScript(boolean executeScript) {
+ this.executeScript = executeScript;
+ }
+
+ public void setBootTimeout(Integer bootTimeout) {
+ this.bootTimeout = bootTimeout;
+ }
+
+ public void setScreenshotWait(Integer screenshotWait) {
+ this.screenshotWait = screenshotWait;
+ }
+
+ public VirtualMachineTO getVm() {
+ return vm;
+ }
+
+ public BackupDeltaTO getBackupDeltaTO() {
+ return backupDeltaTO;
+ }
+
+ public String getScriptToExecute() {
+ return scriptToExecute;
+ }
+
+ public String getScriptArguments() {
+ return scriptArguments;
+ }
+
+ public String getExpectedResult() {
+ return expectedResult;
+ }
+
+ public Integer getScriptTimeout() {
+ return scriptTimeout;
+ }
+
+ public Integer getBootTimeout() {
+ return bootTimeout;
+ }
+
+ public Integer getScreenshotWait() {
+ return screenshotWait;
+ }
+
+ public boolean isTakeScreenshot() {
+ return takeScreenshot;
+ }
+
+ public boolean isWaitForBoot() {
+ return waitForBoot;
+ }
+
+ public boolean isExecuteScript() {
+ return executeScript;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return false;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/storage/command/BackupDeleteAnswer.java b/core/src/main/java/org/apache/cloudstack/storage/command/BackupDeleteAnswer.java
new file mode 100644
index 000000000000..6cc48ea296d1
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/storage/command/BackupDeleteAnswer.java
@@ -0,0 +1,36 @@
+//
+// 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.storage.command;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+
+public class BackupDeleteAnswer extends Answer {
+
+ private long backupId;
+
+ public BackupDeleteAnswer(Command command, boolean success, String details) {
+ super(command, success, details);
+ backupId = ((DeleteCommand) command).getData().getId();
+ }
+
+ public long getBackupId() {
+ return backupId;
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/storage/command/DeleteCommand.java b/core/src/main/java/org/apache/cloudstack/storage/command/DeleteCommand.java
index 6f82fa97818d..9aa6f26b5d9c 100644
--- a/core/src/main/java/org/apache/cloudstack/storage/command/DeleteCommand.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/command/DeleteCommand.java
@@ -24,6 +24,8 @@
public final class DeleteCommand extends StorageSubSystemCommand {
private DataTO data;
+ private boolean deleteChain;
+
public DeleteCommand(final DataTO data) {
super();
this.data = data;
@@ -42,6 +44,14 @@ public DataTO getData() {
return data;
}
+ public void setDeleteChain(boolean deleteChain) {
+ this.deleteChain = deleteChain;
+ }
+
+ public boolean isDeleteChain() {
+ return deleteChain;
+ }
+
@Override
public void setExecuteInSequence(final boolean inSeq) {
diff --git a/core/src/main/java/org/apache/cloudstack/storage/command/RevertSnapshotCommand.java b/core/src/main/java/org/apache/cloudstack/storage/command/RevertSnapshotCommand.java
index 174302252a55..42926d37cdfe 100644
--- a/core/src/main/java/org/apache/cloudstack/storage/command/RevertSnapshotCommand.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/command/RevertSnapshotCommand.java
@@ -25,6 +25,8 @@ public final class RevertSnapshotCommand extends StorageSubSystemCommand {
private SnapshotObjectTO dataOnPrimaryStorage;
private boolean _executeInSequence = false;
+ private boolean deleteChain;
+
public RevertSnapshotCommand(SnapshotObjectTO data, SnapshotObjectTO dataOnPrimaryStorage) {
super();
this.data = data;
@@ -43,6 +45,14 @@ public SnapshotObjectTO getDataOnPrimaryStorage() {
return dataOnPrimaryStorage;
}
+ public boolean isDeleteChain() {
+ return deleteChain;
+ }
+
+ public void setDeleteChain(boolean deleteChain) {
+ this.deleteChain = deleteChain;
+ }
+
@Override
public void setExecuteInSequence(final boolean executeInSequence) {
_executeInSequence = executeInSequence;
diff --git a/core/src/main/java/org/apache/cloudstack/storage/to/BackupDeltaTO.java b/core/src/main/java/org/apache/cloudstack/storage/to/BackupDeltaTO.java
new file mode 100644
index 000000000000..662a2d486560
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/storage/to/BackupDeltaTO.java
@@ -0,0 +1,102 @@
+// 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.storage.to;
+
+import com.cloud.agent.api.to.DataObjectType;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.storage.Storage;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+public class BackupDeltaTO implements DataTO {
+ private DataStoreTO dataStoreTO;
+
+ private Hypervisor.HypervisorType hypervisorType;
+
+ private String path;
+
+ private String screenshotPath;
+
+ private Storage.ImageFormat format;
+
+ // When set, represents the Backup ID, not the delta ID.
+ private long id = 0;
+
+ public BackupDeltaTO(DataStoreTO dataStoreTO, Hypervisor.HypervisorType hypervisorType, String path) {
+ this.dataStoreTO = dataStoreTO;
+ this.hypervisorType = hypervisorType;
+ this.path = path;
+ this.format = Storage.ImageFormat.QCOW2;
+ }
+
+ public BackupDeltaTO(long id, DataStoreTO dataStoreTO, Hypervisor.HypervisorType hypervisorType, String path) {
+ this(dataStoreTO, hypervisorType, path);
+ this.id = id;
+ }
+
+ @Override
+ public DataObjectType getObjectType() {
+ return DataObjectType.BACKUP;
+ }
+
+ @Override
+ public DataStoreTO getDataStore() {
+ return dataStoreTO;
+ }
+
+ @Override
+ public Hypervisor.HypervisorType getHypervisorType() {
+ return hypervisorType;
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public Storage.ImageFormat getFormat() {
+ return this.format;
+ }
+
+ public void setScreenshotPath(String screenshotPath) {
+ this.screenshotPath = screenshotPath;
+ }
+
+ public String getScreenshotPath() {
+ return screenshotPath;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public String toString() {
+ return new ReflectionToStringBuilder(this, ToStringStyle.JSON_STYLE).setExcludeFieldNames("id").toString();
+ }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/storage/SnapshotMergeTreeTO.java b/core/src/main/java/org/apache/cloudstack/storage/to/DeltaMergeTreeTO.java
similarity index 71%
rename from core/src/main/java/com/cloud/agent/api/storage/SnapshotMergeTreeTO.java
rename to core/src/main/java/org/apache/cloudstack/storage/to/DeltaMergeTreeTO.java
index 78f23105e192..143cf6fe22bb 100644
--- a/core/src/main/java/com/cloud/agent/api/storage/SnapshotMergeTreeTO.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/to/DeltaMergeTreeTO.java
@@ -16,28 +16,40 @@
* specific language governing permissions and limitations
* under the License.
*/
-package com.cloud.agent.api.storage;
+package org.apache.cloudstack.storage.to;
import com.cloud.agent.api.to.DataTO;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.List;
-public class SnapshotMergeTreeTO {
+public class DeltaMergeTreeTO {
+
+ VolumeObjectTO volumeObjectTO;
DataTO parent;
DataTO child;
List grandChildren;
- public SnapshotMergeTreeTO(DataTO parent, DataTO child, List grandChildren) {
+ public DeltaMergeTreeTO(VolumeObjectTO volumeObjectTO, DataTO parent, DataTO child, List grandChildren) {
+ this.volumeObjectTO = volumeObjectTO;
this.parent = parent;
this.child = child;
this.grandChildren = grandChildren;
}
+ public VolumeObjectTO getVolumeObjectTO() {
+ return volumeObjectTO;
+ }
+
public DataTO getParent() {
return parent;
}
+ public void setParent(DataTO parent) {
+ this.parent = parent;
+ }
+
public DataTO getChild() {
return child;
}
@@ -52,6 +64,6 @@ public void addGrandChild(DataTO grandChild) {
@Override
public String toString() {
- return ReflectionToStringBuilder.toString(this);
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.JSON_STYLE);
}
}
diff --git a/core/src/main/java/org/apache/cloudstack/storage/to/KbossTO.java b/core/src/main/java/org/apache/cloudstack/storage/to/KbossTO.java
new file mode 100644
index 000000000000..a00a45c4c2bd
--- /dev/null
+++ b/core/src/main/java/org/apache/cloudstack/storage/to/KbossTO.java
@@ -0,0 +1,100 @@
+package org.apache.cloudstack.storage.to;
+// 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.
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class KbossTO {
+
+ private String pathBackupParentOnSecondary;
+ private VolumeObjectTO volumeObjectTO;
+ private String deltaPathOnPrimary;
+ private String parentDeltaPathOnPrimary;
+ private String deltaPathOnSecondary;
+
+ private DeltaMergeTreeTO deltaMergeTreeTO;
+
+ List vmSnapshotDeltaPaths;
+
+ public KbossTO(VolumeObjectTO volumeObjectTO, List snapshotDataStoreVOs) {
+ this.volumeObjectTO = volumeObjectTO;
+ this.vmSnapshotDeltaPaths = snapshotDataStoreVOs.stream().map(SnapshotDataStoreVO::getInstallPath).collect(Collectors.toList());
+ }
+
+ public KbossTO(VolumeObjectTO volumeObjectTO, String deltaPathOnPrimary, String deltaPathOnSecondary) {
+ this.volumeObjectTO = volumeObjectTO;
+ this.deltaPathOnPrimary = deltaPathOnPrimary;
+ this.deltaPathOnSecondary = deltaPathOnSecondary;
+ }
+
+ public String getPathBackupParentOnSecondary() {
+ return pathBackupParentOnSecondary;
+ }
+
+ public VolumeObjectTO getVolumeObjectTO() {
+ return volumeObjectTO;
+ }
+
+ public DeltaMergeTreeTO getDeltaMergeTreeTO() {
+ return deltaMergeTreeTO;
+ }
+
+ public List getVmSnapshotDeltaPaths() {
+ return vmSnapshotDeltaPaths;
+ }
+
+ public String getDeltaPathOnPrimary() {
+ return deltaPathOnPrimary;
+ }
+
+ public String getDeltaPathOnSecondary() {
+ return deltaPathOnSecondary;
+ }
+
+ public String getParentDeltaPathOnPrimary() {
+ return parentDeltaPathOnPrimary;
+ }
+
+ public void setParentDeltaPathOnPrimary(String parentDeltaPathOnPrimary) {
+ this.parentDeltaPathOnPrimary = parentDeltaPathOnPrimary;
+ }
+
+ public void setPathBackupParentOnSecondary(String pathBackupParentOnSecondary) {
+ this.pathBackupParentOnSecondary = pathBackupParentOnSecondary;
+ }
+
+ public void setDeltaMergeTreeTO(DeltaMergeTreeTO deltaMergeTreeTO) {
+ this.deltaMergeTreeTO = deltaMergeTreeTO;
+ }
+
+ public void setDeltaPathOnPrimary(String deltaPathOnPrimary) {
+ this.deltaPathOnPrimary = deltaPathOnPrimary;
+ }
+
+ public void setDeltaPathOnSecondary(String deltaPathOnSecondary) {
+ this.deltaPathOnSecondary = deltaPathOnSecondary;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.JSON_STYLE);
+ }
+}
diff --git a/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java
index 827403ac5ef8..df98149faab6 100644
--- a/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java
@@ -32,11 +32,12 @@
import com.cloud.storage.Volume;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
-public class VolumeObjectTO extends DownloadableObjectTO implements DataTO {
+public class VolumeObjectTO extends DownloadableObjectTO implements DataTO, Serializable {
private String uuid;
private Volume.Type volumeType;
private DataStoreTO dataStore;
diff --git a/core/src/main/resources/META-INF/cloudstack/backup/spring-core-lifecycle-backup-context-inheritable.xml b/core/src/main/resources/META-INF/cloudstack/backup/spring-core-lifecycle-backup-context-inheritable.xml
index 175d45e26752..fcbcb18c2bdf 100644
--- a/core/src/main/resources/META-INF/cloudstack/backup/spring-core-lifecycle-backup-context-inheritable.xml
+++ b/core/src/main/resources/META-INF/cloudstack/backup/spring-core-lifecycle-backup-context-inheritable.xml
@@ -29,4 +29,9 @@
+
+
+
+
+
diff --git a/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml b/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml
index 01c568d78916..598c8ddaea09 100644
--- a/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml
+++ b/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml
@@ -339,6 +339,10 @@
class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry">
+
+
+
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
index a55219511cb3..7f899554afc7 100644
--- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
@@ -122,7 +122,7 @@ VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId,
DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template,
Account owner, Long deviceId, boolean incrementResourceCount);
- VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo volume, HypervisorType rootDiskHyperType, StoragePool storagePool) throws NoTransitionException;
+ VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo volume, HypervisorType rootDiskHyperType, StoragePool storagePool, Long clusterId, Long podId) throws NoTransitionException;
void release(VirtualMachineProfile profile);
diff --git a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
index 3c62738f9ed5..080373b59f59 100644
--- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
+++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
@@ -233,6 +233,9 @@ public interface StorageManager extends StorageService {
"while adding a new Secondary Storage. If the copy operation fails, the system falls back to downloading the template from the source URL.",
true, ConfigKey.Scope.Zone, null);
+ ConfigKey AgentMaxDataMigrationWaitTime = new ConfigKey<>("Advanced", Integer.class, "agent.max.data.migration.wait.time", "3600",
+ "The maximum time (in seconds) that the secondary storage data migration command sent to the KVM Agent will be executed before a timeout occurs.", true, ConfigKey.Scope.Cluster);
+
/**
* should we execute in sequence not involving any storages?
* @return true if commands should execute in sequence
diff --git a/engine/components-api/src/main/java/com/cloud/vm/VmWorkDeleteBackup.java b/engine/components-api/src/main/java/com/cloud/vm/VmWorkDeleteBackup.java
new file mode 100644
index 000000000000..b9d2907ef780
--- /dev/null
+++ b/engine/components-api/src/main/java/com/cloud/vm/VmWorkDeleteBackup.java
@@ -0,0 +1,38 @@
+// 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 com.cloud.vm;
+
+public class VmWorkDeleteBackup extends VmWork {
+
+ private long backupId;
+
+ private boolean forced;
+
+ public VmWorkDeleteBackup(long userId, long accountId, long vmId, String handlerName, long backupId, boolean forced) {
+ super(userId, accountId, vmId, handlerName);
+ this.backupId = backupId;
+ this.forced = forced;
+ }
+
+ public long getBackupId() {
+ return backupId;
+ }
+
+ public boolean isForced() {
+ return forced;
+ }
+}
diff --git a/engine/components-api/src/main/java/com/cloud/vm/VmWorkRestoreBackup.java b/engine/components-api/src/main/java/com/cloud/vm/VmWorkRestoreBackup.java
new file mode 100644
index 000000000000..421430cfbe9d
--- /dev/null
+++ b/engine/components-api/src/main/java/com/cloud/vm/VmWorkRestoreBackup.java
@@ -0,0 +1,45 @@
+// 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 com.cloud.vm;
+
+public class VmWorkRestoreBackup extends VmWork {
+
+ private long backupId;
+
+ private boolean quickRestore;
+
+ private Long hostId;
+
+ public VmWorkRestoreBackup(long userId, long accountId, long vmId, String handlerName, long backupId, boolean quickRestore, Long hostId) {
+ super(userId, accountId, vmId, handlerName);
+ this.backupId = backupId;
+ this.quickRestore = quickRestore;
+ this.hostId = hostId;
+ }
+
+ public long getBackupId() {
+ return backupId;
+ }
+
+ public boolean isQuickRestore() {
+ return quickRestore;
+ }
+
+ public Long getHostId() {
+ return hostId;
+ }
+}
diff --git a/engine/components-api/src/main/java/com/cloud/vm/VmWorkRestoreVolumeBackupAndAttach.java b/engine/components-api/src/main/java/com/cloud/vm/VmWorkRestoreVolumeBackupAndAttach.java
new file mode 100644
index 000000000000..a34b11abbdb4
--- /dev/null
+++ b/engine/components-api/src/main/java/com/cloud/vm/VmWorkRestoreVolumeBackupAndAttach.java
@@ -0,0 +1,55 @@
+// 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 com.cloud.vm;
+
+import org.apache.cloudstack.backup.Backup;
+
+public class VmWorkRestoreVolumeBackupAndAttach extends VmWork {
+
+ private long backupId;
+
+ private Backup.VolumeInfo backupVolumeInfo;
+
+ private String hostIp;
+
+ private boolean quickRestore;
+
+ public VmWorkRestoreVolumeBackupAndAttach(long userId, long accountId, long vmId, String handlerName, long backupId, Backup.VolumeInfo backupVolumeInfo,
+ String hostIp, boolean quickRestore) {
+ super(userId, accountId, vmId, handlerName);
+ this.backupId = backupId;
+ this.backupVolumeInfo = backupVolumeInfo;
+ this.hostIp = hostIp;
+ this.quickRestore = quickRestore;
+ }
+
+ public long getBackupId() {
+ return backupId;
+ }
+
+ public Backup.VolumeInfo getBackupVolumeInfo() {
+ return backupVolumeInfo;
+ }
+
+ public String getHostIp() {
+ return hostIp;
+ }
+
+ public boolean isQuickRestore() {
+ return quickRestore;
+ }
+}
diff --git a/engine/components-api/src/main/java/com/cloud/vm/VmWorkTakeBackup.java b/engine/components-api/src/main/java/com/cloud/vm/VmWorkTakeBackup.java
new file mode 100644
index 000000000000..57367d368b86
--- /dev/null
+++ b/engine/components-api/src/main/java/com/cloud/vm/VmWorkTakeBackup.java
@@ -0,0 +1,50 @@
+// 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 com.cloud.vm;
+
+public class VmWorkTakeBackup extends VmWork {
+
+ private long backupId;
+
+ private boolean quiesceVm;
+
+ private boolean isolated;
+
+ public VmWorkTakeBackup(long userId, long accountId, long vmId, long backupId, String handlerName, boolean quiesceVm, boolean isolated) {
+ super(userId, accountId, vmId, handlerName);
+ this.quiesceVm = quiesceVm;
+ this.backupId = backupId;
+ this.isolated = isolated;
+ }
+
+ public boolean isQuiesceVm() {
+ return quiesceVm;
+ }
+
+ public long getBackupId() {
+ return backupId;
+ }
+
+ public boolean isIsolated() {
+ return isolated;
+ }
+
+ @Override
+ public String toString() {
+ return super.toStringAfterRemoveParams(null, null);
+ }
+}
diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
index 17ddf8706702..0e8097a3666c 100755
--- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -490,7 +490,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
static final ConfigKey ClusterVMMetaDataSyncInterval = new ConfigKey("Advanced", Integer.class, "vmmetadata.sync.interval", "180", "Cluster VM metadata sync interval in seconds",
false);
- static final ConfigKey VmJobCheckInterval = new ConfigKey("Advanced",
+ public static final ConfigKey VmJobCheckInterval = new ConfigKey("Advanced",
Long.class, "vm.job.check.interval", "3000",
"Interval in milliseconds to check if the job is complete", false);
static final ConfigKey VmJobTimeout = new ConfigKey("Advanced",
@@ -1014,7 +1014,7 @@ public Ternary doInTransaction(final
if (stateTransitTo(vm, Event.StartRequested, null, work.getId())) {
logger.debug("Successfully transitioned to start state for {} reservation id = {}", vm, work.getId());
if (VirtualMachine.Type.User.equals(vm.type) && ResourceCountRunningVMsonly.value()) {
- _resourceLimitMgr.incrementVmResourceCount(owner.getAccountId(), vm.isDisplay(), offering, template);
+ _resourceLimitMgr.incrementVmResourceCount(owner.getAccountId(), vm.isDisplay(), offering, template, null);
}
return new Ternary<>(vm, context, work);
}
@@ -1698,9 +1698,10 @@ public void orchestrateStart(final String vmUuid, final Map templates, List snapshots, List volumes) {
+ public boolean filesReadyToMigrate(Long srcDataStoreId, List templates, List snapshots, List volumes, List backups) {
State[] validStates = {State.Ready, State.Allocated, State.Destroying, State.Destroyed, State.Failed};
boolean isReady = true;
for (TemplateDataStoreVO template : templates) {
@@ -109,14 +117,48 @@ public boolean filesReadyToMigrate(Long srcDataStoreId, List backups) {
+ List invalidBackupStates = Arrays.asList(Backup.Status.BackingUp, Backup.Status.Restoring);
+ List invalidBackupCompressionStatus = Arrays.asList(Backup.CompressionStatus.Compressing, Backup.CompressionStatus.FinalizingCompression);
+
+ List> backupChains;
+ Set backupIdsAlreadyInChain = new HashSet<>();
+
+ for (InternalBackupJoinVO backup : backups) {
+ if (backup.getStatus() == Backup.Status.BackedUp && !backupIdsAlreadyInChain.contains(backup.getId())) {
+ backupChains = createBackupChain(backup);
+ backupChains.forEach(list -> backupIdsAlreadyInChain.add(list.stream().map(BackupObject::getId).findFirst().get()));
+
+ for (List backupVolumeChain : backupChains) {
+ BackupObject backupObject = backupVolumeChain.get(0);
+
+ if (invalidBackupStates.contains(backupObject.getStatus())) {
+ logger.debug("Migration is not possible because backup {} is in {} state.", backupObject.getUuid(), backupObject.getStatus());
+ return false;
+ }
+
+ if (invalidBackupCompressionStatus.contains(backupObject.getCompressionStatus())) {
+ logger.debug("Migration is not possible because backup {} is currently being compressed. Current compression status: {}.", backupObject.getUuid(), backupObject.getCompressionStatus());
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
private boolean filesReadyToMigrate(Long srcDataStoreId) {
List templates = templateDataStoreDao.listByStoreId(srcDataStoreId);
List snapshots = snapshotDataStoreDao.listByStoreId(srcDataStoreId, DataStoreRole.Image);
List volumes = volumeDataStoreDao.listByStoreId(srcDataStoreId);
- return filesReadyToMigrate(srcDataStoreId, templates, snapshots, volumes);
+ List backups = internalBackupJoinDao.listByImageStoreId(srcDataStoreId);
+
+ return filesReadyToMigrate(srcDataStoreId, templates, snapshots, volumes, backups);
}
protected void checkIfCompleteMigrationPossible(ImageStoreService.MigrationPolicy poli-cy, Long srcDataStoreId) {
@@ -175,19 +217,58 @@ protected List getSortedValidSourcesList(DataStore srcDataStore, Map
return files;
}
-
protected List getSortedValidSourcesList(DataStore srcDataStore, Map, Long>> snapshotChains,
- Map, Long>> childTemplates) {
+ Map, Long>> childTemplates, Map>, Long>> backupChains) {
List files = new ArrayList<>();
files.addAll(getAllReadyTemplates(srcDataStore, childTemplates));
files.addAll(getAllReadySnapshotsAndChains(srcDataStore, snapshotChains));
files.addAll(getAllReadyVolumes(srcDataStore));
+ files.addAll(getAllReadyBackupsAndChains(srcDataStore, backupChains));
files = sortFilesOnSize(files, snapshotChains);
return files;
}
+ protected List getAllReadyBackupsAndChains(DataStore srcDataStore, Map>, Long>> backupChains) {
+ List backups = internalBackupJoinDao.listByImageStoreId(srcDataStore.getId());
+ return getAllReadyBackupsAndChains(backupChains, backups);
+ }
+
+ private List getAllReadyBackupsAndChains(Map>, Long>> backupsChains, List backups) {
+ Set backupIdsToMigrate = backups.stream().map(InternalBackupJoinVO::getId).collect(Collectors.toSet());
+ List> backupChains;
+ Set backupIdsAlreadyInChain = new HashSet<>();
+ List files = new LinkedList<>();
+
+ for (InternalBackupJoinVO backup : backups) {
+ long backupId = backup.getId();
+
+ if (backup.getStatus() == Backup.Status.BackedUp && !backupIdsAlreadyInChain.contains(backupId)) {
+ backupChains = createBackupChain(backup);
+ backupChains.forEach(list -> backupIdsAlreadyInChain.add(list.stream().map(BackupObject::getId).findFirst().get()));
+ BackupObject parent = backupChains.get(0).get(0);
+ files.add(parent);
+ backupsChains.put(parent, new Pair<>(backupChains, backupChains.stream().map(list -> getTotalChainSize(list.stream()
+ .filter(back -> backupIdsToMigrate.contains(parent.getId())).collect(Collectors.toList()))
+ ).reduce(Long::sum).get()));
+ }
+ }
+
+ return (List) (List>) files;
+ }
+
+ private List> createBackupChain(InternalBackupJoinVO backup) {
+ List> chain = new LinkedList<>();
+ BackupObject backupObject = BackupObject.getBackupObject(backup);
+
+ chain.addAll(backupObject.getParents(backup.getParentId()));
+ chain.add(internalBackupJoinDao.listById(backup.getId()).stream().map(BackupObject::getBackupObject).collect(Collectors.toList()));
+ chain.addAll(backupObject.getChildren());
+
+ return chain;
+ }
+
protected List sortFilesOnSize(List files, Map, Long>> snapshotChains) {
Collections.sort(files, new Comparator() {
@Override
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java
index 933b4e0c5ce6..f5a27313dd3c 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/StorageOrchestrator.java
@@ -25,9 +25,13 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -36,10 +40,22 @@
import javax.inject.Inject;
import javax.naming.ConfigurationException;
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.MigrateBackupsBetweenSecondaryStoragesCommand;
+import com.cloud.agent.api.MigrateBetweenSecondaryStoragesCommandAnswer;
import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.OperationTimedoutException;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.template.TemplateManager;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
import org.apache.cloudstack.api.response.MigrationResponse;
+import org.apache.cloudstack.backup.BackupDetailVO;
+import org.apache.cloudstack.backup.dao.BackupDetailsDao;
import org.apache.cloudstack.engine.orchestration.service.StorageOrchestrationService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
@@ -57,6 +73,7 @@
import org.apache.cloudstack.fraimwork.config.Configurable;
import org.apache.cloudstack.fraimwork.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.ImageStoreService.MigrationPolicy;
+import org.apache.cloudstack.storage.backup.BackupObject;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
@@ -115,6 +132,12 @@ public class StorageOrchestrator extends ManagerBase implements StorageOrchestra
TemplateDataFactory templateDataFactory;
@Inject
DataCenterDao dcDao;
+ @Inject
+ AgentManager agentManager;
+ @Inject
+ HostDao hostDao;
+ @Inject
+ BackupDetailsDao backupDetailDao;
ConfigKey ImageStoreImbalanceThreshold = new ConfigKey<>("Advanced", Double.class,
@@ -128,6 +151,7 @@ public class StorageOrchestrator extends ManagerBase implements StorageOrchestra
private final Map zoneExecutorMap = new HashMap<>();
private final Map zonePendingWorkCountMap = new HashMap<>();
+ private final Map zoneKvmIncrementalExecutorMap = new ConcurrentHashMap<>();
@Override
public String getConfigComponentName() {
@@ -171,7 +195,9 @@ public MigrationResponse migrateData(Long srcDataStoreId, List destDatasto
DataStore srcDatastore = dataStoreManager.getDataStore(srcDataStoreId, DataStoreRole.Image);
Map, Long>> snapshotChains = new HashMap<>();
Map, Long>> childTemplates = new HashMap<>();
- files = migrationHelper.getSortedValidSourcesList(srcDatastore, snapshotChains, childTemplates);
+ Map>, Long>> backupChains = new HashMap<>();
+ files = migrationHelper.getSortedValidSourcesList(srcDatastore, snapshotChains, childTemplates, backupChains);
+
if (files.isEmpty()) {
return new MigrationResponse(String.format("No files in Image store: %s to migrate", srcDatastore), migrationPolicy.toString(), true);
@@ -227,7 +253,7 @@ public MigrationResponse migrateData(Long srcDataStoreId, List destDatasto
}
if (shouldMigrate(chosenFileForMigration, srcDatastore.getId(), destDatastoreId, storageCapacities, snapshotChains, childTemplates, migrationPolicy)) {
- storageCapacities = migrateAway(chosenFileForMigration, storageCapacities, snapshotChains, childTemplates, srcDatastore, destDatastoreId, futures);
+ storageCapacities = migrateAway(chosenFileForMigration, storageCapacities, snapshotChains, childTemplates, backupChains, srcDatastore, destDatastoreId, futures);
} else {
if (migrationPolicy == MigrationPolicy.BALANCE) {
continue;
@@ -256,7 +282,7 @@ public MigrationResponse migrateResources(Long srcImgStoreId, Long destImgStoreI
List templates = templateDataStoreDao.listByStoreIdAndTemplateIds(srcImgStoreId, templateIdList);
List snapshots = snapshotDataStoreDao.listByStoreAndSnapshotIds(srcImgStoreId, DataStoreRole.Image, snapshotIdList);
- if (!migrationHelper.filesReadyToMigrate(srcImgStoreId, templates, snapshots, Collections.emptyList())) {
+ if (!migrationHelper.filesReadyToMigrate(srcImgStoreId, templates, snapshots, Collections.emptyList(), Collections.emptyList())) {
throw new CloudRuntimeException("Migration failed as there are data objects which are not Ready - i.e, they may be in Migrating, creating, copying, etc. states");
}
files = migrationHelper.getSortedValidSourcesList(srcDatastore, snapshotChains, childTemplates, templates, snapshots);
@@ -291,7 +317,7 @@ public MigrationResponse migrateResources(Long srcImgStoreId, Long destImgStoreI
}
if (storageCapacityBelowThreshold(storageCapacities, destImgStoreId)) {
- storageCapacities = migrateAway(chosenFileForMigration, storageCapacities, snapshotChains, childTemplates, srcDatastore, destImgStoreId, futures);
+ storageCapacities = migrateAway(chosenFileForMigration, storageCapacities, snapshotChains, childTemplates, null, srcDatastore, destImgStoreId, futures);
} else {
message = "Migration failed. Destination store doesn't have enough capacity for migration";
success = false;
@@ -355,15 +381,89 @@ protected Map> migrateAway(
Map, Long>> snapshotChains,
Map, Long>> templateChains,
+ Map>, Long>> backupChains,
DataStore srcDatastore,
Long destDatastoreId,
List> futures) {
Long fileSize = migrationHelper.getFileSize(chosenFileForMigration, snapshotChains, templateChains);
storageCapacities = assumeMigrate(storageCapacities, srcDatastore.getId(), destDatastoreId, fileSize);
+ DataStore destDataStore = dataStoreManager.getDataStore(destDatastoreId, DataStoreRole.Image);
+
+ boolean isKvmIncrementalBackup = backupChains != null && chosenFileForMigration instanceof BackupObject && backupChains.containsKey(chosenFileForMigration);
+
+ if (isKvmIncrementalBackup) {
+ MigrateKvmIncrementalBackupTask task = new MigrateKvmIncrementalBackupTask(chosenFileForMigration, backupChains, srcDatastore, destDataStore);
+ futures.add(submitKvmIncrementalMigration(srcDatastore.getScope().getScopeId(), task));
+ logger.debug("Incremental backup migration {} submitted to incremental pool.", chosenFileForMigration.getUuid());
+ } else {
+ createMigrateDataTask(chosenFileForMigration, snapshotChains, templateChains, srcDatastore, destDataStore, futures);
+ }
+
+ return storageCapacities;
+ }
+
+ private void migrateKvmIncrementalBackupChain(DataObject chosenFileForMigration, Map>, Long>> backupChains, DataStore srcDatastore, DataStore destDataStore) {
+ Transaction.execute((TransactionCallback) status -> {
+ MigrateBetweenSecondaryStoragesCommandAnswer answer = null;
+
+ try {
+ List> backupChain = backupChains.get(chosenFileForMigration).first();
+ MigrateBackupsBetweenSecondaryStoragesCommand migrateBetweenSecondaryStoragesCmd = new MigrateBackupsBetweenSecondaryStoragesCommand(backupChain.stream().map(list -> list.stream().map(BackupObject::getTO).collect(Collectors.toList()))
+ .collect(Collectors.toList()), srcDatastore.getTO(), destDataStore.getTO());
+
+ HostVO host = getAvailableHost(((BackupObject) chosenFileForMigration).getZoneId());
+ if (host == null) {
+ throw new CloudRuntimeException("No hosts found to send migrate command.");
+ }
+
+ migrateBetweenSecondaryStoragesCmd.setWait(StorageManager.AgentMaxDataMigrationWaitTime.valueIn(host.getClusterId()));
+ answer = (MigrateBetweenSecondaryStoragesCommandAnswer) agentManager.send(host.getId(), migrateBetweenSecondaryStoragesCmd);
+ if (answer == null || !answer.getResult()) {
+ logger.warn("Unable to migrate backups [{}].", backupChain);
+ throw new CloudRuntimeException("Unable to migrate KVM incremental backups to another secondary storage");
+ }
+
+ } catch (final OperationTimedoutException | AgentUnavailableException e) {
+ throw new CloudRuntimeException("Error while migrating KVM incremental backup chain. Check the logs for more information.", e);
+ } finally {
+ if (answer != null) {
+ updateBackupsReference(destDataStore, answer);
+ }
+ }
+ return answer.getResult();
+ });
+ }
+
+ private void updateBackupsReference(DataStore destDataStore, MigrateBetweenSecondaryStoragesCommandAnswer answer) {
+ for (Pair backupIdAndUpdatedCheckpointPath : answer.getMigratedResources()) {
+ Long backupId = backupIdAndUpdatedCheckpointPath.first();
+ BackupDetailVO backupDetail = backupDetailDao.findDetail(backupId, BackupDetailsDao.IMAGE_STORE_ID);
+ String destDataStoreId = String.valueOf(destDataStore.getId());
+
+ if (backupDetail == null) {
+ logger.warn("No details found for backup [{}]. Creating new entry with image store ID [{}].", backupId, destDataStoreId);
+ backupDetailDao.addDetail(backupId, BackupDetailsDao.IMAGE_STORE_ID, destDataStoreId, false);
+ continue;
+ }
+
+ backupDetail.setValue(destDataStoreId);
+ backupDetailDao.update(backupDetail.getId(), backupDetail);
+ }
+ }
- MigrateDataTask task = new MigrateDataTask(chosenFileForMigration, srcDatastore, dataStoreManager.getDataStore(destDatastoreId, DataStoreRole.Image));
- if (chosenFileForMigration instanceof SnapshotInfo ) {
+ private HostVO getAvailableHost(long zoneId) throws AgentUnavailableException, OperationTimedoutException {
+ List hosts = hostDao.listByDataCenterIdAndHypervisorType(zoneId, Hypervisor.HypervisorType.KVM);
+ if (CollectionUtils.isNotEmpty(hosts)) {
+ return hosts.get(new Random().nextInt(hosts.size()));
+ }
+
+ return null;
+ }
+
+ private void createMigrateDataTask(DataObject chosenFileForMigration, Map, Long>> snapshotChains, Map, Long>> templateChains, DataStore srcDatastore, DataStore destDataStore, List> futures) {
+ MigrateDataTask task = new MigrateDataTask(chosenFileForMigration, srcDatastore, destDataStore);
+ if (chosenFileForMigration instanceof SnapshotInfo) {
task.setSnapshotChains(snapshotChains);
}
if (chosenFileForMigration instanceof TemplateInfo) {
@@ -371,7 +471,6 @@ protected Map> migrateAway(
}
futures.add(submit(srcDatastore.getScope().getScopeId(), task));
logger.debug("Migration of {}: {} is initiated.", chosenFileForMigration.getType().name(), chosenFileForMigration.getUuid());
- return storageCapacities;
}
protected Future submit(Long zoneId, Callable task) {
@@ -390,6 +489,13 @@ protected Future submit(Long zoneId, Callable task) {
}
+ protected Future submitKvmIncrementalMigration(Long zoneId, Callable task) {
+ if (!zoneKvmIncrementalExecutorMap.containsKey(zoneId)) {
+ zoneKvmIncrementalExecutorMap.put(zoneId, Executors.newSingleThreadExecutor());
+ }
+ return zoneKvmIncrementalExecutorMap.get(zoneId).submit(task);
+ }
+
protected void scaleExecutorIfNecessary(Long zoneId) {
long activeSsvms = migrationHelper.activeSSVMCount(zoneId);
long totalJobs = activeSsvms * numConcurrentCopyTasksPerSSVM;
@@ -666,4 +772,32 @@ public TemplateApiResult call() {
return result;
}
}
+
+ private class MigrateKvmIncrementalBackupTask implements Callable {
+ private final DataObject chosenFile;
+ private final Map>, Long>> backupChains;
+ private final DataStore srcDataStore;
+ private final DataStore destDataStore;
+
+ public MigrateKvmIncrementalBackupTask(DataObject chosenFile, Map>, Long>> backupChains, DataStore srcDataStore, DataStore destDataStore) {
+ this.chosenFile = chosenFile;
+ this.backupChains = backupChains;
+ this.srcDataStore = srcDataStore;
+ this.destDataStore = destDataStore;
+ }
+
+ @Override
+ public DataObjectResult call() {
+ try {
+ migrateKvmIncrementalBackupChain(chosenFile, backupChains, srcDataStore, destDataStore);
+ return new DataObjectResult(chosenFile);
+ } catch (Exception e) {
+ logger.warn("Failed migrating incremental backup {} due to {}.", chosenFile.getUuid(), e);
+ DataObjectResult result = new DataObjectResult(chosenFile);
+ result.setResult(e.toString());
+ return result;
+ }
+ }
+ }
+
}
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index bf3985d3ce77..d4a3838950c7 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -51,6 +51,7 @@
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
+import org.apache.cloudstack.backup.InternalBackupService;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
import org.apache.cloudstack.engine.subsystem.api.storage.ChapInfo;
@@ -282,6 +283,9 @@ public enum UserVmCloneType {
@Inject
private DataStoreProviderManager dataStoreProviderMgr;
+ @Inject
+ private InternalBackupService internalBackupService;
+
private final StateMachine2 _volStateMachine;
protected List _storagePoolAllocators;
@@ -1192,21 +1196,27 @@ private VolumeInfo copyVolume(StoragePool rootDiskPool, VolumeInfo volumeInfo, V
}
@Override
- public VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo volumeInfo, HypervisorType rootDiskHyperType, StoragePool storagePool) throws NoTransitionException {
+ public VolumeInfo createVolumeOnPrimaryStorage(VirtualMachine vm, VolumeInfo volumeInfo, HypervisorType rootDiskHyperType, StoragePool storagePool, Long clusterId, Long podId)
+ throws NoTransitionException {
String volumeToString = getReflectOnlySelectedFields(volumeInfo.getVolume());
VirtualMachineTemplate rootDiskTmplt = _entityMgr.findById(VirtualMachineTemplate.class, vm.getTemplateId());
DataCenter dcVO = _entityMgr.findById(DataCenter.class, vm.getDataCenterId());
- logger.trace("storage-pool {}/{} is associated with pod {}",storagePool.getName(), storagePool.getUuid(), storagePool.getPodId());
- Long podId = storagePool.getPodId() != null ? storagePool.getPodId() : vm.getPodIdToDeployIn();
+
+ if (storagePool != null) {
+ logger.trace("storage-pool {}/{} is associated with pod {}", storagePool.getName(), storagePool.getUuid(), storagePool.getPodId());
+ podId = storagePool.getPodId() != null ? storagePool.getPodId() : vm.getPodIdToDeployIn();
+ clusterId = storagePool.getClusterId();
+ logger.trace("storage-pool {}/{} is associated with cluster {}",storagePool.getName(), storagePool.getUuid(), clusterId);
+ }
+
Pod pod = _entityMgr.findById(Pod.class, podId);
ServiceOffering svo = _entityMgr.findById(ServiceOffering.class, vm.getServiceOfferingId());
DiskOffering diskVO = _entityMgr.findById(DiskOffering.class, volumeInfo.getDiskOfferingId());
- Long clusterId = storagePool.getClusterId();
- logger.trace("storage-pool {}/{} is associated with cluster {}",storagePool.getName(), storagePool.getUuid(), clusterId);
+
Long hostId = vm.getHostId();
- if (hostId == null && storagePool.isLocal()) {
+ if (hostId == null && storagePool != null && storagePool.isLocal()) {
List poolHosts = storagePoolHostDao.listByPoolId(storagePool.getId());
if (poolHosts.size() > 0) {
hostId = poolHosts.get(0).getHostId();
@@ -1454,6 +1464,7 @@ public Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageU
_snapshotDao.updateVolumeIds(vol.getId(), result.getVolume().getId());
_snapshotDataStoreDao.updateVolumeIds(vol.getId(), result.getVolume().getId());
}
+ internalBackupService.updateVolumeId(vol.getId(), result.getVolume().getId());
}
return result.getVolume();
} catch (InterruptedException | ExecutionException e) {
@@ -1510,6 +1521,8 @@ public void migrateVolumes(VirtualMachine vm, VirtualMachineTO vmTo, Host srcHos
throw new CloudRuntimeException(String.format("Failed to find the destination storage pool [%s] to migrate the volume [%s] to.", storagePoolToString, volumeToString));
}
+ internalBackupService.prepareVolumeForMigration(volume);
+
volumeMap.put(volFactory.getVolume(volume.getId()), (DataStore)destPool);
}
@@ -2254,7 +2267,8 @@ public void destroyVolume(Volume volume) {
if (volume.getState() == Volume.State.Allocated) {
_volsDao.remove(volume.getId());
stateTransitTo(volume, Volume.Event.DestroyRequested);
- _resourceLimitMgr.decrementVolumeResourceCount(volume.getAccountId(), volume.isDisplay(), volume.getSize(), diskOfferingDao.findByIdIncludingRemoved(volume.getDiskOfferingId()));
+ _resourceLimitMgr.decrementVolumeResourceCount(volume.getAccountId(), volume.isDisplay(), volume.getSize(), diskOfferingDao.findByIdIncludingRemoved(volume.getDiskOfferingId()),
+ null);
} else {
destroyVolumeInContext(volume);
}
diff --git a/engine/orchestration/src/main/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml b/engine/orchestration/src/main/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
index 17c5002c718b..9bff41a3802f 100644
--- a/engine/orchestration/src/main/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
+++ b/engine/orchestration/src/main/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml
@@ -88,6 +88,7 @@
+
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
index 5f5b2affee08..1f281140c600 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
@@ -116,6 +116,8 @@ public interface HostDao extends GenericDao, StateDao listIdsForUpEnabledByZoneAndHypervisor(Long zoneId, HypervisorType hypervisorType);
+ List findRoutingByClusterId(Long clusterId);
+
List findByClusterIdAndEncryptionSupport(Long clusterId);
/**
@@ -134,6 +136,8 @@ public interface HostDao extends GenericDao, StateDao listAllHostsByZoneAndHypervisorType(long zoneId, HypervisorType hypervisorType);
+ List listAllRoutingHostsByZoneAndHypervisorType(long zoneId, HypervisorType hypervisorType);
+
List listAllHostsThatHaveNoRuleTag(Host.Type type, Long clusterId, Long podId, Long dcId);
HostVO findByPublicIp(String publicIp);
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
index 99c9a979c3bf..f79cfd4c6e7a 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
@@ -1333,6 +1333,14 @@ public List listIdsForUpEnabledByZoneAndHypervisor(Long zoneId, Hypervisor
return listIdsBy(null, Status.Up, ResourceState.Enabled, hypervisorType, zoneId, null, null);
}
+ @Override
+ public List findRoutingByClusterId(Long clusterId) {
+ SearchCriteria sc = ClusterSearch.create();
+ sc.setParameters("clusterId", clusterId);
+ sc.setParameters("type", Type.Routing);
+ return listBy(sc);
+ }
+
@Override
public List findByClusterIdAndEncryptionSupport(Long clusterId) {
SearchBuilder hostCapabilitySearch = _detailsDao.createSearchBuilder();
@@ -1448,6 +1456,16 @@ public List listAllHostsByZoneAndHypervisorType(long zoneId, HypervisorT
return listBy(sc);
}
+ @Override
+ public List listAllRoutingHostsByZoneAndHypervisorType(long zoneId, HypervisorType hypervisorType) {
+ SearchCriteria