mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Create new Instance from VM backup (#10140)
This feature adds the ability to create a new instance from a VM backup for dummy, NAS and Veeam backup providers. It works even if the original instance used to create the backup was expunged or unmanaged. There are two parts to this functionality: Saving all configuration details that the VM had at the time of taking the backup. And using them to create an instance from backup. Enabling a user to expunge/unmanage an instance that has backups.
This commit is contained in:
parent
b9febe4b4f
commit
a87c5c2b3a
@ -34,13 +34,17 @@ public interface Capacity extends InternalIdentity, Identity {
|
|||||||
public static final short CAPACITY_TYPE_LOCAL_STORAGE = 9;
|
public static final short CAPACITY_TYPE_LOCAL_STORAGE = 9;
|
||||||
public static final short CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET = 10;
|
public static final short CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET = 10;
|
||||||
public static final short CAPACITY_TYPE_GPU = 19;
|
public static final short CAPACITY_TYPE_GPU = 19;
|
||||||
|
public static final short CAPACITY_TYPE_OBJECT_STORAGE = 20;
|
||||||
|
public static final short CAPACITY_TYPE_BACKUP_STORAGE = 21;
|
||||||
|
|
||||||
public static final short CAPACITY_TYPE_CPU_CORE = 90;
|
public static final short CAPACITY_TYPE_CPU_CORE = 90;
|
||||||
|
|
||||||
public static final List<Short> STORAGE_CAPACITY_TYPES = List.of(CAPACITY_TYPE_STORAGE,
|
public static final List<Short> STORAGE_CAPACITY_TYPES = List.of(CAPACITY_TYPE_STORAGE,
|
||||||
CAPACITY_TYPE_STORAGE_ALLOCATED,
|
CAPACITY_TYPE_STORAGE_ALLOCATED,
|
||||||
CAPACITY_TYPE_SECONDARY_STORAGE,
|
CAPACITY_TYPE_SECONDARY_STORAGE,
|
||||||
CAPACITY_TYPE_LOCAL_STORAGE);
|
CAPACITY_TYPE_LOCAL_STORAGE,
|
||||||
|
CAPACITY_TYPE_BACKUP_STORAGE,
|
||||||
|
CAPACITY_TYPE_OBJECT_STORAGE);
|
||||||
|
|
||||||
public Long getHostOrPoolId();
|
public Long getHostOrPoolId();
|
||||||
|
|
||||||
|
|||||||
@ -632,11 +632,13 @@ public class EventTypes {
|
|||||||
public static final String EVENT_VM_BACKUP_CREATE = "BACKUP.CREATE";
|
public static final String EVENT_VM_BACKUP_CREATE = "BACKUP.CREATE";
|
||||||
public static final String EVENT_VM_BACKUP_RESTORE = "BACKUP.RESTORE";
|
public static final String EVENT_VM_BACKUP_RESTORE = "BACKUP.RESTORE";
|
||||||
public static final String EVENT_VM_BACKUP_DELETE = "BACKUP.DELETE";
|
public static final String EVENT_VM_BACKUP_DELETE = "BACKUP.DELETE";
|
||||||
|
public static final String EVENT_VM_BACKUP_OFFERING_REMOVED_AND_BACKUPS_DELETED = "BACKUP.OFFERING.BACKUPS.DEL";
|
||||||
public static final String EVENT_VM_BACKUP_RESTORE_VOLUME_TO_VM = "BACKUP.RESTORE.VOLUME.TO.VM";
|
public static final String EVENT_VM_BACKUP_RESTORE_VOLUME_TO_VM = "BACKUP.RESTORE.VOLUME.TO.VM";
|
||||||
public static final String EVENT_VM_BACKUP_SCHEDULE_CONFIGURE = "BACKUP.SCHEDULE.CONFIGURE";
|
public static final String EVENT_VM_BACKUP_SCHEDULE_CONFIGURE = "BACKUP.SCHEDULE.CONFIGURE";
|
||||||
public static final String EVENT_VM_BACKUP_SCHEDULE_DELETE = "BACKUP.SCHEDULE.DELETE";
|
public static final String EVENT_VM_BACKUP_SCHEDULE_DELETE = "BACKUP.SCHEDULE.DELETE";
|
||||||
public static final String EVENT_VM_BACKUP_USAGE_METRIC = "BACKUP.USAGE.METRIC";
|
public static final String EVENT_VM_BACKUP_USAGE_METRIC = "BACKUP.USAGE.METRIC";
|
||||||
public static final String EVENT_VM_BACKUP_EDIT = "BACKUP.OFFERING.EDIT";
|
public static final String EVENT_VM_BACKUP_EDIT = "BACKUP.OFFERING.EDIT";
|
||||||
|
public static final String EVENT_VM_CREATE_FROM_BACKUP = "VM.CREATE.FROM.BACKUP";
|
||||||
|
|
||||||
// external network device events
|
// external network device events
|
||||||
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_ADD = "PHYSICAL.NVPCONTROLLER.ADD";
|
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_ADD = "PHYSICAL.NVPCONTROLLER.ADD";
|
||||||
|
|||||||
@ -272,5 +272,7 @@ public interface NetworkService {
|
|||||||
|
|
||||||
boolean handleCksIsoOnNetworkVirtualRouter(Long virtualRouterId, boolean mount) throws ResourceUnavailableException;
|
boolean handleCksIsoOnNetworkVirtualRouter(Long virtualRouterId, boolean mount) throws ResourceUnavailableException;
|
||||||
|
|
||||||
|
IpAddresses getIpAddressesFromIps(String ipAddress, String ip6Address, String macAddress);
|
||||||
|
|
||||||
String getNicVlanValueForExternalVm(NicTO nic);
|
String getNicVlanValueForExternalVm(NicTO nic);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,13 @@ public class DiskOfferingInfo {
|
|||||||
_diskOffering = diskOffering;
|
_diskOffering = diskOffering;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DiskOfferingInfo(DiskOffering diskOffering, Long size, Long minIops, Long maxIops) {
|
||||||
|
_diskOffering = diskOffering;
|
||||||
|
_size = size;
|
||||||
|
_minIops = minIops;
|
||||||
|
_maxIops = maxIops;
|
||||||
|
}
|
||||||
|
|
||||||
public void setDiskOffering(DiskOffering diskOffering) {
|
public void setDiskOffering(DiskOffering diskOffering) {
|
||||||
_diskOffering = diskOffering;
|
_diskOffering = diskOffering;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,7 +134,7 @@ public interface StorageService {
|
|||||||
|
|
||||||
void removeSecondaryStorageHeuristic(RemoveSecondaryStorageSelectorCmd cmd);
|
void removeSecondaryStorageHeuristic(RemoveSecondaryStorageSelectorCmd cmd);
|
||||||
|
|
||||||
ObjectStore discoverObjectStore(String name, String url, String providerName, Map details) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException;
|
ObjectStore discoverObjectStore(String name, String url, Long size, String providerName, Map details) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException;
|
||||||
|
|
||||||
boolean deleteObjectStore(DeleteObjectStoragePoolCmd cmd);
|
boolean deleteObjectStore(DeleteObjectStoragePoolCmd cmd);
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
|
|||||||
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.CreateVMFromBackupCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
|
||||||
@ -220,7 +221,7 @@ public interface UserVmService {
|
|||||||
* available.
|
* available.
|
||||||
*/
|
*/
|
||||||
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
|
UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
|
||||||
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
|
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
|
||||||
String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
|
String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIp, Boolean displayVm, String keyboard,
|
||||||
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
List<Long> affinityGroupIdList, Map<String, String> customParameter, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||||
@ -297,7 +298,7 @@ public interface UserVmService {
|
|||||||
* available.
|
* available.
|
||||||
*/
|
*/
|
||||||
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
|
UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
|
||||||
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
|
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, String group, HypervisorType hypervisor,
|
||||||
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
||||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
|
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException;
|
||||||
@ -369,7 +370,7 @@ public interface UserVmService {
|
|||||||
* available.
|
* available.
|
||||||
*/
|
*/
|
||||||
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
|
UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
|
||||||
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
|
String hostName, String displayName, Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
|
||||||
Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
||||||
Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||||
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot)
|
Map<String, String> templateOvfPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot)
|
||||||
@ -516,4 +517,8 @@ public interface UserVmService {
|
|||||||
* @return true if the VM is successfully unmanaged, false if not.
|
* @return true if the VM is successfully unmanaged, false if not.
|
||||||
*/
|
*/
|
||||||
boolean unmanageUserVM(Long vmId);
|
boolean unmanageUserVM(Long vmId);
|
||||||
|
|
||||||
|
UserVm allocateVMFromBackup(CreateVMFromBackupCmd cmd) throws InsufficientCapacityException, ResourceAllocationException, ResourceUnavailableException;
|
||||||
|
|
||||||
|
UserVm restoreVMFromBackup(CreateVMFromBackupCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -128,7 +128,6 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Partition,
|
|||||||
s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging, null));
|
s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging, null));
|
||||||
s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging, null));
|
s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging, null));
|
||||||
s_fsm.addTransition(new Transition<State, Event>(State.Stopped, Event.RestoringRequested, State.Restoring, null));
|
s_fsm.addTransition(new Transition<State, Event>(State.Stopped, Event.RestoringRequested, State.Restoring, null));
|
||||||
s_fsm.addTransition(new Transition<State, Event>(State.Expunging, Event.RestoringRequested, State.Restoring, null));
|
|
||||||
s_fsm.addTransition(new Transition<State, Event>(State.Destroyed, Event.RestoringRequested, State.Restoring, null));
|
s_fsm.addTransition(new Transition<State, Event>(State.Destroyed, Event.RestoringRequested, State.Restoring, null));
|
||||||
s_fsm.addTransition(new Transition<State, Event>(State.Restoring, Event.RestoringSuccess, State.Stopped, null));
|
s_fsm.addTransition(new Transition<State, Event>(State.Restoring, Event.RestoringSuccess, State.Stopped, null));
|
||||||
s_fsm.addTransition(new Transition<State, Event>(State.Restoring, Event.RestoringFailed, State.Stopped, null));
|
s_fsm.addTransition(new Transition<State, Event>(State.Restoring, Event.RestoringFailed, State.Stopped, null));
|
||||||
|
|||||||
39
api/src/main/java/com/cloud/vm/VmDiskInfo.java
Normal file
39
api/src/main/java/com/cloud/vm/VmDiskInfo.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package com.cloud.vm;
|
||||||
|
|
||||||
|
import com.cloud.offering.DiskOffering;
|
||||||
|
import com.cloud.offering.DiskOfferingInfo;
|
||||||
|
|
||||||
|
public class VmDiskInfo extends DiskOfferingInfo {
|
||||||
|
private Long _deviceId;
|
||||||
|
|
||||||
|
public VmDiskInfo(DiskOffering diskOffering, Long size, Long minIops, Long maxIops) {
|
||||||
|
super(diskOffering, size, minIops, maxIops);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VmDiskInfo(DiskOffering diskOffering, Long size, Long minIops, Long maxIops, Long deviceId) {
|
||||||
|
super(diskOffering, size, minIops, maxIops);
|
||||||
|
_deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDeviceId() {
|
||||||
|
return _deviceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -74,6 +74,8 @@ public interface AlertService {
|
|||||||
public static final AlertType ALERT_TYPE_VR_PUBLIC_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PUBLIC.IFACE.MTU", true);
|
public static final AlertType ALERT_TYPE_VR_PUBLIC_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PUBLIC.IFACE.MTU", true);
|
||||||
public static final AlertType ALERT_TYPE_VR_PRIVATE_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PRIVATE.IFACE.MTU", true);
|
public static final AlertType ALERT_TYPE_VR_PRIVATE_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PRIVATE.IFACE.MTU", true);
|
||||||
public static final AlertType ALERT_TYPE_EXTENSION_PATH_NOT_READY = new AlertType((short)33, "ALERT.TYPE.EXTENSION.PATH.NOT.READY", true);
|
public static final AlertType ALERT_TYPE_EXTENSION_PATH_NOT_READY = new AlertType((short)33, "ALERT.TYPE.EXTENSION.PATH.NOT.READY", 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 short getType() {
|
public short getType() {
|
||||||
return type;
|
return type;
|
||||||
|
|||||||
@ -29,6 +29,7 @@ public class ApiConstants {
|
|||||||
public static final String ADDRESS = "address";
|
public static final String ADDRESS = "address";
|
||||||
public static final String ALGORITHM = "algorithm";
|
public static final String ALGORITHM = "algorithm";
|
||||||
public static final String ALIAS = "alias";
|
public static final String ALIAS = "alias";
|
||||||
|
public static final String ALLOCATED = "allocated";
|
||||||
public static final String ALLOCATED_DATE = "allocateddate";
|
public static final String ALLOCATED_DATE = "allocateddate";
|
||||||
public static final String ALLOCATED_ONLY = "allocatedonly";
|
public static final String ALLOCATED_ONLY = "allocatedonly";
|
||||||
public static final String ALLOCATED_TIME = "allocated";
|
public static final String ALLOCATED_TIME = "allocated";
|
||||||
@ -60,6 +61,7 @@ public class ApiConstants {
|
|||||||
public static final String BACKUP_STORAGE_AVAILABLE = "backupstorageavailable";
|
public static final String BACKUP_STORAGE_AVAILABLE = "backupstorageavailable";
|
||||||
public static final String BACKUP_STORAGE_LIMIT = "backupstoragelimit";
|
public static final String BACKUP_STORAGE_LIMIT = "backupstoragelimit";
|
||||||
public static final String BACKUP_STORAGE_TOTAL = "backupstoragetotal";
|
public static final String BACKUP_STORAGE_TOTAL = "backupstoragetotal";
|
||||||
|
public static final String BACKUP_VM_OFFERING_REMOVED = "vmbackupofferingremoved";
|
||||||
public static final String BACKUP_TOTAL = "backuptotal";
|
public static final String BACKUP_TOTAL = "backuptotal";
|
||||||
public static final String BASE64_IMAGE = "base64image";
|
public static final String BASE64_IMAGE = "base64image";
|
||||||
public static final String BGP_PEERS = "bgppeers";
|
public static final String BGP_PEERS = "bgppeers";
|
||||||
@ -155,6 +157,7 @@ public class ApiConstants {
|
|||||||
public static final String MAX_IOPS = "maxiops";
|
public static final String MAX_IOPS = "maxiops";
|
||||||
public static final String HYPERVISOR_SNAPSHOT_RESERVE = "hypervisorsnapshotreserve";
|
public static final String HYPERVISOR_SNAPSHOT_RESERVE = "hypervisorsnapshotreserve";
|
||||||
public static final String DATACENTER_NAME = "datacentername";
|
public static final String DATACENTER_NAME = "datacentername";
|
||||||
|
public static final String DATADISKS_DETAILS = "datadisksdetails";
|
||||||
public static final String DATADISK_OFFERING_LIST = "datadiskofferinglist";
|
public static final String DATADISK_OFFERING_LIST = "datadiskofferinglist";
|
||||||
public static final String DEFAULT_VALUE = "defaultvalue";
|
public static final String DEFAULT_VALUE = "defaultvalue";
|
||||||
public static final String DELETE_PROTECTION = "deleteprotection";
|
public static final String DELETE_PROTECTION = "deleteprotection";
|
||||||
@ -163,6 +166,7 @@ public class ApiConstants {
|
|||||||
public static final String DESTINATION_ZONE_ID = "destzoneid";
|
public static final String DESTINATION_ZONE_ID = "destzoneid";
|
||||||
public static final String DETAILS = "details";
|
public static final String DETAILS = "details";
|
||||||
public static final String DEVICE_ID = "deviceid";
|
public static final String DEVICE_ID = "deviceid";
|
||||||
|
public static final String DEVICE_IDS = "deviceids";
|
||||||
public static final String DEVICE_NAME = "devicename";
|
public static final String DEVICE_NAME = "devicename";
|
||||||
public static final String DIRECT_DOWNLOAD = "directdownload";
|
public static final String DIRECT_DOWNLOAD = "directdownload";
|
||||||
public static final String DISK = "disk";
|
public static final String DISK = "disk";
|
||||||
@ -305,6 +309,7 @@ public class ApiConstants {
|
|||||||
public static final String IP_ADDRESS = "ipaddress";
|
public static final String IP_ADDRESS = "ipaddress";
|
||||||
public static final String IP_ADDRESSES = "ipaddresses";
|
public static final String IP_ADDRESSES = "ipaddresses";
|
||||||
public static final String IP6_ADDRESS = "ip6address";
|
public static final String IP6_ADDRESS = "ip6address";
|
||||||
|
public static final String IP6_ADDRESSES = "ip6addresses";
|
||||||
public static final String IP_ADDRESS_ID = "ipaddressid";
|
public static final String IP_ADDRESS_ID = "ipaddressid";
|
||||||
public static final String IS_2FA_ENABLED = "is2faenabled";
|
public static final String IS_2FA_ENABLED = "is2faenabled";
|
||||||
public static final String IS_2FA_VERIFIED = "is2faverified";
|
public static final String IS_2FA_VERIFIED = "is2faverified";
|
||||||
@ -356,6 +361,7 @@ public class ApiConstants {
|
|||||||
public static final String LBID = "lbruleid";
|
public static final String LBID = "lbruleid";
|
||||||
public static final String LB_PROVIDER = "lbprovider";
|
public static final String LB_PROVIDER = "lbprovider";
|
||||||
public static final String MAC_ADDRESS = "macaddress";
|
public static final String MAC_ADDRESS = "macaddress";
|
||||||
|
public static final String MAC_ADDRESSES = "macaddresses";
|
||||||
public static final String MANUAL_UPGRADE = "manualupgrade";
|
public static final String MANUAL_UPGRADE = "manualupgrade";
|
||||||
public static final String MAX = "max";
|
public static final String MAX = "max";
|
||||||
public static final String MAX_SNAPS = "maxsnaps";
|
public static final String MAX_SNAPS = "maxsnaps";
|
||||||
@ -383,6 +389,7 @@ public class ApiConstants {
|
|||||||
public static final String NETMASK = "netmask";
|
public static final String NETMASK = "netmask";
|
||||||
public static final String NEW_NAME = "newname";
|
public static final String NEW_NAME = "newname";
|
||||||
public static final String NIC = "nic";
|
public static final String NIC = "nic";
|
||||||
|
public static final String NICS = "nics";
|
||||||
public static final String NIC_NETWORK_LIST = "nicnetworklist";
|
public static final String NIC_NETWORK_LIST = "nicnetworklist";
|
||||||
public static final String NIC_IP_ADDRESS_LIST = "nicipaddresslist";
|
public static final String NIC_IP_ADDRESS_LIST = "nicipaddresslist";
|
||||||
public static final String NIC_MULTIQUEUE_NUMBER = "nicmultiqueuenumber";
|
public static final String NIC_MULTIQUEUE_NUMBER = "nicmultiqueuenumber";
|
||||||
@ -459,6 +466,7 @@ public class ApiConstants {
|
|||||||
public static final String POWER_STATE = "powerstate";
|
public static final String POWER_STATE = "powerstate";
|
||||||
public static final String PRECEDENCE = "precedence";
|
public static final String PRECEDENCE = "precedence";
|
||||||
public static final String PREPARE_VM = "preparevm";
|
public static final String PREPARE_VM = "preparevm";
|
||||||
|
public static final String PRESERVE_IP = "preserveip";
|
||||||
public static final String PRIVATE_INTERFACE = "privateinterface";
|
public static final String PRIVATE_INTERFACE = "privateinterface";
|
||||||
public static final String PRIVATE_IP = "privateip";
|
public static final String PRIVATE_IP = "privateip";
|
||||||
public static final String PRIVATE_PORT = "privateport";
|
public static final String PRIVATE_PORT = "privateport";
|
||||||
@ -494,6 +502,7 @@ public class ApiConstants {
|
|||||||
public static final String REGISTERED = "registered";
|
public static final String REGISTERED = "registered";
|
||||||
public static final String QUALIFIERS = "qualifiers";
|
public static final String QUALIFIERS = "qualifiers";
|
||||||
public static final String QUERY_FILTER = "queryfilter";
|
public static final String QUERY_FILTER = "queryfilter";
|
||||||
|
public static final String QUIESCE_VM = "quiescevm";
|
||||||
public static final String SCHEDULE = "schedule";
|
public static final String SCHEDULE = "schedule";
|
||||||
public static final String SCHEDULE_ID = "scheduleid";
|
public static final String SCHEDULE_ID = "scheduleid";
|
||||||
public static final String SCOPE = "scope";
|
public static final String SCOPE = "scope";
|
||||||
@ -509,6 +518,7 @@ public class ApiConstants {
|
|||||||
public static final String SERIAL = "serial";
|
public static final String SERIAL = "serial";
|
||||||
public static final String SERVICE_IP = "serviceip";
|
public static final String SERVICE_IP = "serviceip";
|
||||||
public static final String SERVICE_OFFERING_ID = "serviceofferingid";
|
public static final String SERVICE_OFFERING_ID = "serviceofferingid";
|
||||||
|
public static final String SERVICE_OFFERING_NAME = "serviceofferingname";
|
||||||
public static final String SESSIONKEY = "sessionkey";
|
public static final String SESSIONKEY = "sessionkey";
|
||||||
public static final String SHOW_CAPACITIES = "showcapacities";
|
public static final String SHOW_CAPACITIES = "showcapacities";
|
||||||
public static final String SHOW_REMOVED = "showremoved";
|
public static final String SHOW_REMOVED = "showremoved";
|
||||||
@ -576,6 +586,7 @@ public class ApiConstants {
|
|||||||
public static final String TRUST_STORE_PASSWORD = "truststorepass";
|
public static final String TRUST_STORE_PASSWORD = "truststorepass";
|
||||||
public static final String URL = "url";
|
public static final String URL = "url";
|
||||||
public static final String USAGE_INTERFACE = "usageinterface";
|
public static final String USAGE_INTERFACE = "usageinterface";
|
||||||
|
public static final String USED = "used";
|
||||||
public static final String USED_SUBNETS = "usedsubnets";
|
public static final String USED_SUBNETS = "usedsubnets";
|
||||||
public static final String USED_IOPS = "usediops";
|
public static final String USED_IOPS = "usediops";
|
||||||
public static final String USER_DATA = "userdata";
|
public static final String USER_DATA = "userdata";
|
||||||
@ -634,8 +645,10 @@ public class ApiConstants {
|
|||||||
public static final String IS_DEDICATED = "isdedicated";
|
public static final String IS_DEDICATED = "isdedicated";
|
||||||
public static final String TAKEN = "taken";
|
public static final String TAKEN = "taken";
|
||||||
public static final String VM_AVAILABLE = "vmavailable";
|
public static final String VM_AVAILABLE = "vmavailable";
|
||||||
|
public static final String VM_DETAILS = "vmdetails";
|
||||||
public static final String VM_LIMIT = "vmlimit";
|
public static final String VM_LIMIT = "vmlimit";
|
||||||
public static final String VM_TOTAL = "vmtotal";
|
public static final String VM_TOTAL = "vmtotal";
|
||||||
|
public static final String VM_SETTINGS = "vmsettings";
|
||||||
public static final String VM_TYPE = "vmtype";
|
public static final String VM_TYPE = "vmtype";
|
||||||
public static final String VNET = "vnet";
|
public static final String VNET = "vnet";
|
||||||
public static final String IS_VOLATILE = "isvolatile";
|
public static final String IS_VOLATILE = "isvolatile";
|
||||||
@ -817,6 +830,7 @@ public class ApiConstants {
|
|||||||
public static final String LIST_ALL = "listall";
|
public static final String LIST_ALL = "listall";
|
||||||
public static final String LIST_ONLY_REMOVED = "listonlyremoved";
|
public static final String LIST_ONLY_REMOVED = "listonlyremoved";
|
||||||
public static final String LIST_SYSTEM_VMS = "listsystemvms";
|
public static final String LIST_SYSTEM_VMS = "listsystemvms";
|
||||||
|
public static final String LIST_VM_DETAILS = "listvmdetails";
|
||||||
public static final String IP_RANGES = "ipranges";
|
public static final String IP_RANGES = "ipranges";
|
||||||
public static final String IPV4_ROUTING = "ip4routing";
|
public static final String IPV4_ROUTING = "ip4routing";
|
||||||
public static final String IPV4_ROUTES = "ip4routes";
|
public static final String IPV4_ROUTES = "ip4routes";
|
||||||
|
|||||||
@ -38,7 +38,6 @@ import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
|||||||
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
|
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupRepositoryResponse;
|
import org.apache.cloudstack.api.response.BackupRepositoryResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupResponse;
|
|
||||||
import org.apache.cloudstack.api.response.BackupScheduleResponse;
|
import org.apache.cloudstack.api.response.BackupScheduleResponse;
|
||||||
import org.apache.cloudstack.api.response.BucketResponse;
|
import org.apache.cloudstack.api.response.BucketResponse;
|
||||||
import org.apache.cloudstack.api.response.CapacityResponse;
|
import org.apache.cloudstack.api.response.CapacityResponse;
|
||||||
@ -142,7 +141,6 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse;
|
|||||||
import org.apache.cloudstack.api.response.VpcResponse;
|
import org.apache.cloudstack.api.response.VpcResponse;
|
||||||
import org.apache.cloudstack.api.response.VpnUsersResponse;
|
import org.apache.cloudstack.api.response.VpnUsersResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.backup.Backup;
|
|
||||||
import org.apache.cloudstack.backup.BackupOffering;
|
import org.apache.cloudstack.backup.BackupOffering;
|
||||||
import org.apache.cloudstack.backup.BackupRepository;
|
import org.apache.cloudstack.backup.BackupRepository;
|
||||||
import org.apache.cloudstack.backup.BackupSchedule;
|
import org.apache.cloudstack.backup.BackupSchedule;
|
||||||
@ -534,8 +532,6 @@ public interface ResponseGenerator {
|
|||||||
|
|
||||||
UserDataResponse createUserDataResponse(UserData userData);
|
UserDataResponse createUserDataResponse(UserData userData);
|
||||||
|
|
||||||
BackupResponse createBackupResponse(Backup backup);
|
|
||||||
|
|
||||||
BackupScheduleResponse createBackupScheduleResponse(BackupSchedule backup);
|
BackupScheduleResponse createBackupScheduleResponse(BackupSchedule backup);
|
||||||
|
|
||||||
BackupOfferingResponse createBackupOfferingResponse(BackupOffering policy);
|
BackupOfferingResponse createBackupOfferingResponse(BackupOffering policy);
|
||||||
|
|||||||
@ -141,7 +141,6 @@ public class ListCapacityCmd extends BaseListCmd {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
response.setResponses(capacityResponses);
|
response.setResponses(capacityResponses);
|
||||||
response.setResponseName(getCommandName());
|
response.setResponseName(getCommandName());
|
||||||
this.setResponseObject(response);
|
this.setResponseObject(response);
|
||||||
|
|||||||
@ -56,6 +56,9 @@ public class AddObjectStoragePoolCmd extends BaseCmd {
|
|||||||
@Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the storage pool")
|
@Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the storage pool")
|
||||||
private String tags;
|
private String tags;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.SIZE, type = CommandType.LONG, description = "the total size of the object store in GiB. Used for tracking capacity and sending alerts", since = "4.21")
|
||||||
|
private Long size;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -68,6 +71,10 @@ public class AddObjectStoragePoolCmd extends BaseCmd {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getTotalSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, String> getDetails() {
|
public Map<String, String> getDetails() {
|
||||||
Map<String, String> detailsMap = null;
|
Map<String, String> detailsMap = null;
|
||||||
if (details != null && !details.isEmpty()) {
|
if (details != null && !details.isEmpty()) {
|
||||||
@ -112,7 +119,7 @@ public class AddObjectStoragePoolCmd extends BaseCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute(){
|
public void execute(){
|
||||||
try{
|
try{
|
||||||
ObjectStore result = _storageService.discoverObjectStore(getName(), getUrl(), getProviderName(), getDetails());
|
ObjectStore result = _storageService.discoverObjectStore(getName(), getUrl(), getTotalSize(), getProviderName(), getDetails());
|
||||||
ObjectStoreResponse storeResponse = null;
|
ObjectStoreResponse storeResponse = null;
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
storeResponse = _responseGenerator.createObjectStoreResponse(result);
|
storeResponse = _responseGenerator.createObjectStoreResponse(result);
|
||||||
|
|||||||
@ -44,6 +44,8 @@ public class UpdateObjectStoragePoolCmd extends BaseCmd {
|
|||||||
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the url for the object store")
|
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the url for the object store")
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.SIZE, type = CommandType.LONG, description = "the total size of the object store in GiB. Used for tracking capacity and sending alerts. Set to 0 to stop tracking.", since = "4.21")
|
||||||
|
private Long size;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
@ -61,6 +63,10 @@ public class UpdateObjectStoragePoolCmd extends BaseCmd {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -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 org.apache.cloudstack.api.command.admin.vm;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject;
|
||||||
|
import org.apache.cloudstack.api.command.admin.AdminCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.CreateVMFromBackupCmd;
|
||||||
|
import org.apache.cloudstack.api.response.ClusterResponse;
|
||||||
|
import org.apache.cloudstack.api.response.PodResponse;
|
||||||
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
|
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
|
||||||
|
@APICommand(name = "createVMFromBackup",
|
||||||
|
description = "Creates and automatically starts a VM from a backup.",
|
||||||
|
responseObject = UserVmResponse.class,
|
||||||
|
responseView = ResponseObject.ResponseView.Full,
|
||||||
|
entityType = {VirtualMachine.class},
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true,
|
||||||
|
since = "4.21.0",
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||||
|
public class CreateVMFromBackupCmdByAdmin extends CreateVMFromBackupCmd implements AdminCmd {
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.POD_ID, type = CommandType.UUID, entityType = PodResponse.class, description = "destination Pod ID to deploy the VM to - parameter available for root admin only", since = "4.21")
|
||||||
|
private Long podId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.UUID, entityType = ClusterResponse.class, description = "destination Cluster ID to deploy the VM to - parameter available for root admin only", since = "4.21")
|
||||||
|
private Long clusterId;
|
||||||
|
|
||||||
|
public Long getPodId() {
|
||||||
|
return podId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getClusterId() {
|
||||||
|
return clusterId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -60,6 +60,27 @@ public class CreateBackupCmd extends BaseAsyncCreateCmd {
|
|||||||
description = "ID of the VM")
|
description = "ID of the VM")
|
||||||
private Long vmId;
|
private Long vmId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NAME,
|
||||||
|
type = CommandType.STRING,
|
||||||
|
description = "the name of the backup",
|
||||||
|
since = "4.21.0")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DESCRIPTION,
|
||||||
|
type = CommandType.STRING,
|
||||||
|
description = "the description for the backup",
|
||||||
|
since = "4.21.0")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.QUIESCE_VM,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
required = false,
|
||||||
|
description = "Quiesce the instance before checkpointing the disks for backup. Applicable only to NAS backup provider. " +
|
||||||
|
"The filesystem is frozen before the backup starts and thawed immediately after. " +
|
||||||
|
"Requires the instance to have the QEMU Guest Agent installed and running.",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Boolean quiesceVM;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -68,6 +89,18 @@ public class CreateBackupCmd extends BaseAsyncCreateCmd {
|
|||||||
return vmId;
|
return vmId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getQuiesceVM() {
|
||||||
|
return quiesceVM;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -75,7 +108,7 @@ public class CreateBackupCmd extends BaseAsyncCreateCmd {
|
|||||||
@Override
|
@Override
|
||||||
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
|
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
|
||||||
try {
|
try {
|
||||||
boolean result = backupManager.createBackup(getVmId(), getJob());
|
boolean result = backupManager.createBackup(this, getJob());
|
||||||
if (result) {
|
if (result) {
|
||||||
SuccessResponse response = new SuccessResponse(getCommandName());
|
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||||
response.setResponseName(getCommandName());
|
response.setResponseName(getCommandName());
|
||||||
|
|||||||
@ -79,6 +79,15 @@ public class CreateBackupScheduleCmd extends BaseCmd {
|
|||||||
since = "4.21.0", description = ApiConstants.PARAMETER_DESCRIPTION_MAX_BACKUPS)
|
since = "4.21.0", description = ApiConstants.PARAMETER_DESCRIPTION_MAX_BACKUPS)
|
||||||
private Integer maxBackups;
|
private Integer maxBackups;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.QUIESCE_VM,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
required = false,
|
||||||
|
description = "Quiesce the instance before checkpointing the disks for backup. Applicable only to NAS backup provider. " +
|
||||||
|
"The filesystem is frozen before the backup starts and thawed immediately after. " +
|
||||||
|
"Requires the instance to have the QEMU Guest Agent installed and running.",
|
||||||
|
since = "4.21.0")
|
||||||
|
private Boolean quiesceVM;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -103,6 +112,10 @@ public class CreateBackupScheduleCmd extends BaseCmd {
|
|||||||
return maxBackups;
|
return maxBackups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getQuiesceVM() {
|
||||||
|
return quiesceVM;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
|||||||
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
|
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
|
||||||
import org.apache.cloudstack.api.Parameter;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupResponse;
|
import org.apache.cloudstack.api.response.BackupResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
@ -75,6 +76,25 @@ public class ListBackupsCmd extends BaseListProjectAndAccountResourcesCmd {
|
|||||||
description = "list backups by zone id")
|
description = "list backups by zone id")
|
||||||
private Long zoneId;
|
private Long zoneId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NAME,
|
||||||
|
type = CommandType.STRING,
|
||||||
|
since = "4.21.0",
|
||||||
|
description = "list backups by name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.BACKUP_OFFERING_ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = BackupOfferingResponse.class,
|
||||||
|
since = "4.21.0",
|
||||||
|
description = "list backups by backup offering")
|
||||||
|
private Long backupOfferingId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.LIST_VM_DETAILS,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
since = "4.21.0",
|
||||||
|
description = "list backups with VM details")
|
||||||
|
private Boolean listVmDetails;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -87,10 +107,22 @@ public class ListBackupsCmd extends BaseListProjectAndAccountResourcesCmd {
|
|||||||
return vmId;
|
return vmId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getBackupOfferingId() {
|
||||||
|
return backupOfferingId;
|
||||||
|
}
|
||||||
|
|
||||||
public Long getZoneId() {
|
public Long getZoneId() {
|
||||||
return zoneId;
|
return zoneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getListVmDetails() {
|
||||||
|
return listVmDetails;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -101,7 +133,7 @@ public class ListBackupsCmd extends BaseListProjectAndAccountResourcesCmd {
|
|||||||
if (backup == null) {
|
if (backup == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BackupResponse backupResponse = _responseGenerator.createBackupResponse(backup);
|
BackupResponse backupResponse = backupManager.createBackupResponse(backup, this.getListVmDetails());
|
||||||
responses.add(backupResponse);
|
responses.add(backupResponse);
|
||||||
}
|
}
|
||||||
final ListResponse<BackupResponse> response = new ListResponse<>();
|
final ListResponse<BackupResponse> response = new ListResponse<>();
|
||||||
|
|||||||
@ -0,0 +1,848 @@
|
|||||||
|
// 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.vm;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
||||||
|
import org.apache.cloudstack.api.ACL;
|
||||||
|
import org.apache.cloudstack.api.ApiArgValidator;
|
||||||
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants.IoDriverPolicy;
|
||||||
|
import org.apache.cloudstack.api.BaseAsyncCreateCustomIdCmd;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.command.user.UserCmd;
|
||||||
|
import org.apache.cloudstack.api.response.DiskOfferingResponse;
|
||||||
|
import org.apache.cloudstack.api.response.DomainResponse;
|
||||||
|
import org.apache.cloudstack.api.response.HostResponse;
|
||||||
|
import org.apache.cloudstack.api.response.NetworkResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ProjectResponse;
|
||||||
|
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
||||||
|
import org.apache.cloudstack.api.response.UserDataResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
import org.apache.cloudstack.vm.lease.VMLeaseManager;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
import org.apache.commons.lang3.EnumUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.LogLevel;
|
||||||
|
import com.cloud.event.EventTypes;
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.Network.IpAddresses;
|
||||||
|
import com.cloud.offering.DiskOffering;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import com.cloud.utils.net.NetUtils;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
|
import com.cloud.vm.VmDiskInfo;
|
||||||
|
import com.cloud.utils.net.Dhcp;
|
||||||
|
|
||||||
|
public abstract class BaseDeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityGroupAction, UserCmd {
|
||||||
|
|
||||||
|
private static final String s_name = "deployvirtualmachineresponse";
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "availability zone for the virtual machine")
|
||||||
|
private Long zoneId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "host name for the virtual machine", validations = {ApiArgValidator.RFCComplianceDomainName})
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DISPLAY_NAME, type = CommandType.STRING, description = "an optional user generated name for the virtual machine")
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="The password of the virtual machine. If null, a random password will be generated for the VM.",
|
||||||
|
since="4.19.0.0")
|
||||||
|
protected String password;
|
||||||
|
|
||||||
|
//Owner information
|
||||||
|
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.")
|
||||||
|
private String accountName;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used. If account is NOT provided then virtual machine will be assigned to the caller account and domain.")
|
||||||
|
private Long domainId;
|
||||||
|
|
||||||
|
//Network information
|
||||||
|
//@ACL(accessType = AccessType.UseEntry)
|
||||||
|
@Parameter(name = ApiConstants.NETWORK_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = NetworkResponse.class, description = "list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter")
|
||||||
|
private List<Long> networkIds;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.BOOT_TYPE, type = CommandType.STRING, required = false, description = "Guest VM Boot option either custom[UEFI] or default boot [BIOS]. Not applicable with VMware if the template is marked as deploy-as-is, as we honour what is defined in the template.", since = "4.14.0.0")
|
||||||
|
private String bootType;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.BOOT_MODE, type = CommandType.STRING, required = false, description = "Boot Mode [Legacy] or [Secure] Applicable when Boot Type Selected is UEFI, otherwise Legacy only for BIOS. Not applicable with VMware if the template is marked as deploy-as-is, as we honour what is defined in the template.", since = "4.14.0.0")
|
||||||
|
private String bootMode;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.BOOT_INTO_SETUP, type = CommandType.BOOLEAN, required = false, description = "Boot into hardware setup or not (ignored if startVm = false, only valid for vmware)", since = "4.15.0.0")
|
||||||
|
private Boolean bootIntoSetup;
|
||||||
|
|
||||||
|
//DataDisk information
|
||||||
|
@ACL
|
||||||
|
@Parameter(name = ApiConstants.DISK_OFFERING_ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, description = "the ID of the disk offering for the virtual machine. If the template is of ISO format,"
|
||||||
|
+ " the diskOfferingId is for the root disk volume. Otherwise this parameter is used to indicate the "
|
||||||
|
+ "offering for the data disk volume. If the templateId parameter passed is from a Template object,"
|
||||||
|
+ " the diskOfferingId refers to a DATA Disk Volume created. If the templateId parameter passed is "
|
||||||
|
+ "from an ISO object, the diskOfferingId refers to a ROOT Disk Volume created.")
|
||||||
|
private Long diskOfferingId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.SIZE, type = CommandType.LONG, description = "the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId")
|
||||||
|
private Long size;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.ROOT_DISK_SIZE,
|
||||||
|
type = CommandType.LONG,
|
||||||
|
description = "Optional field to resize root disk on deploy. Value is in GB. Only applies to template-based deployments. Analogous to details[0].rootdisksize, which takes precedence over this parameter if both are provided",
|
||||||
|
since = "4.4")
|
||||||
|
private Long rootdisksize;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DATADISKS_DETAILS,
|
||||||
|
type = CommandType.MAP,
|
||||||
|
since = "4.21.0",
|
||||||
|
description = "Disk offering details for creating multiple data volumes. Mutually exclusive with diskOfferingId." +
|
||||||
|
" Example: datadisksdetails[0].diskofferingid=a2a73a84-19db-4852-8930-dfddef053341&datadisksdetails[0].size=10&datadisksdetails[0].miniops=100&datadisksdetails[0].maxiops=200")
|
||||||
|
private Map dataDisksDetails;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.GROUP, type = CommandType.STRING, description = "an optional group for the virtual machine")
|
||||||
|
private String group;
|
||||||
|
|
||||||
|
@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;
|
||||||
|
|
||||||
|
@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. " +
|
||||||
|
"This binary data must be base64 encoded before adding it to the request. " +
|
||||||
|
"Using HTTP GET (via querystring), you can send up to 4KB of data after base64 encoding. " +
|
||||||
|
"Using HTTP POST (via POST body), you can send up to 1MB of data after base64 encoding. " +
|
||||||
|
"You also need to change vm.userdata.max.length value",
|
||||||
|
length = 1048576)
|
||||||
|
private String userData;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the Userdata", since = "4.18")
|
||||||
|
private Long userdataId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.USER_DATA_DETAILS, type = CommandType.MAP, description = "used to specify the parameters values for the variables in userdata.", since = "4.18")
|
||||||
|
private Map userdataDetails;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING, description = "name of the ssh key pair used to login to the virtual machine")
|
||||||
|
private String sshKeyPairName;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.SSH_KEYPAIRS, type = CommandType.LIST, collectionType = CommandType.STRING, since="4.17", description = "names of the ssh key pairs used to login to the virtual machine")
|
||||||
|
private List<String> sshKeyPairNames;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "destination Host ID to deploy the VM to - parameter available for root admin only")
|
||||||
|
private Long hostId;
|
||||||
|
|
||||||
|
@ACL
|
||||||
|
@Parameter(name = ApiConstants.SECURITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = SecurityGroupResponse.class, description = "comma separated list of security groups id that going to be applied to the virtual machine. "
|
||||||
|
+ "Should be passed only when vm is created from a zone with Basic Network support." + " Mutually exclusive with securitygroupnames parameter")
|
||||||
|
private List<Long> securityGroupIdList;
|
||||||
|
|
||||||
|
@ACL
|
||||||
|
@Parameter(name = ApiConstants.SECURITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = SecurityGroupResponse.class, description = "comma separated list of security groups names that going to be applied to the virtual machine."
|
||||||
|
+ " Should be passed only when vm is created from a zone with Basic Network support. " + "Mutually exclusive with securitygroupids parameter")
|
||||||
|
private List<String> securityGroupNameList;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, description = "ip to network mapping. Can't be specified with networkIds parameter."
|
||||||
|
+ " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].ipv6=fc00:1234:5678::abcd&iptonetworklist[0].networkid=uuid&iptonetworklist[0].mac=aa:bb:cc:dd:ee::ff - requests to use ip 10.10.10.11 in network id=uuid")
|
||||||
|
private Map ipToNetworkList;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, description = "the ip address for default vm's network")
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IP6_ADDRESS, type = CommandType.STRING, description = "the ipv6 address for default vm's network")
|
||||||
|
private String ip6Address;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.MAC_ADDRESS, type = CommandType.STRING, description = "the mac address for default vm's network")
|
||||||
|
private String macAddress;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.KEYBOARD, type = CommandType.STRING, description = "an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us")
|
||||||
|
private String keyboard;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Deploy vm for the project")
|
||||||
|
private Long projectId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.START_VM, type = CommandType.BOOLEAN, description = "true if start vm after creating; defaulted to true if not specified")
|
||||||
|
private Boolean startVm;
|
||||||
|
|
||||||
|
@ACL
|
||||||
|
@Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are going to be applied to the virtual machine."
|
||||||
|
+ " Mutually exclusive with affinitygroupnames parameter")
|
||||||
|
private List<Long> affinityGroupIdList;
|
||||||
|
|
||||||
|
@ACL
|
||||||
|
@Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are going to be applied to the virtual machine."
|
||||||
|
+ "Mutually exclusive with affinitygroupids parameter")
|
||||||
|
private List<String> 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;
|
||||||
|
|
||||||
|
@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;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "Deployment planner to use for vm allocation. Available to ROOT admin only", since = "4.4", authorized = { RoleType.Admin })
|
||||||
|
private String deploymentPlanner;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DHCP_OPTIONS_NETWORK_LIST, type = CommandType.MAP, description = "DHCP options which are passed to the VM on start up"
|
||||||
|
+ " Example: dhcpoptionsnetworklist[0].dhcp:114=url&dhcpoptionsetworklist[0].networkid=networkid&dhcpoptionsetworklist[0].dhcp:66=www.test.com")
|
||||||
|
private Map dhcpOptionsNetworkList;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DATADISK_OFFERING_LIST, type = CommandType.MAP, since = "4.11", description = "datadisk template to disk-offering mapping;" +
|
||||||
|
" an optional parameter used to create additional data disks from datadisk templates; can't be specified with diskOfferingId parameter")
|
||||||
|
private Map dataDiskTemplateToDiskOfferingList;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.EXTRA_CONFIG, type = CommandType.STRING, since = "4.12", description = "an optional URL encoded string that can be passed to the virtual machine upon successful deployment", length = 5120)
|
||||||
|
private String extraConfig;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.COPY_IMAGE_TAGS, type = CommandType.BOOLEAN, since = "4.13", description = "if true the image tags (if any) will be copied to the VM, default value is false")
|
||||||
|
private Boolean copyImageTags;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.PROPERTIES, type = CommandType.MAP, since = "4.15",
|
||||||
|
description = "used to specify the vApp properties.")
|
||||||
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
|
private Map vAppProperties;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NIC_NETWORK_LIST, type = CommandType.MAP, since = "4.15",
|
||||||
|
description = "VMware only: used to specify network mapping of a vApp VMware template registered \"as-is\"." +
|
||||||
|
" Example nicnetworklist[0].ip=Nic-101&nicnetworklist[0].network=uuid")
|
||||||
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
|
private Map vAppNetworks;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.DYNAMIC_SCALING_ENABLED, type = CommandType.BOOLEAN, since = "4.16",
|
||||||
|
description = "true if virtual machine needs to be dynamically scalable")
|
||||||
|
protected Boolean dynamicScalingEnabled;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.OVERRIDE_DISK_OFFERING_ID, type = CommandType.UUID, since = "4.17", entityType = DiskOfferingResponse.class, description = "the ID of the disk offering for the virtual machine to be used for root volume instead of the disk offering mapped in service offering." +
|
||||||
|
"In case of virtual machine deploying from ISO, then the diskofferingid specified for root volume is ignored and uses this override disk offering id")
|
||||||
|
private Long overrideDiskOfferingId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IOTHREADS_ENABLED, type = CommandType.BOOLEAN, required = false,
|
||||||
|
description = "IOThreads are dedicated event loop threads for supported disk devices to perform block I/O requests in order to improve scalability especially on an SMP host/guest with many LUNs.")
|
||||||
|
private Boolean iothreadsEnabled;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IO_DRIVER_POLICY, type = CommandType.STRING, description = "Controls specific policies on IO")
|
||||||
|
private String ioDriverPolicy;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NIC_MULTIQUEUE_NUMBER, type = CommandType.INTEGER, since = "4.18",
|
||||||
|
description = "The number of queues for multiqueue NICs.")
|
||||||
|
private Integer nicMultiqueueNumber;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.NIC_PACKED_VIRTQUEUES_ENABLED, type = CommandType.BOOLEAN, since = "4.18",
|
||||||
|
description = "Enable packed virtqueues or not.")
|
||||||
|
private Boolean nicPackedVirtQueues;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.INSTANCE_LEASE_DURATION, type = CommandType.INTEGER, since = "4.21.0",
|
||||||
|
description = "Number of days instance is leased for.")
|
||||||
|
private Integer leaseDuration;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.INSTANCE_LEASE_EXPIRY_ACTION, type = CommandType.STRING, since = "4.21.0",
|
||||||
|
description = "Lease expiry action, valid values are STOP and DESTROY")
|
||||||
|
private String leaseExpiryAction;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.EXTERNAL_DETAILS,
|
||||||
|
type = CommandType.MAP,
|
||||||
|
description = "Details in key/value pairs using format externaldetails[i].keyname=keyvalue. Example: externaldetails[0].server.type=typevalue",
|
||||||
|
since = "4.21.0")
|
||||||
|
protected Map externalDetails;
|
||||||
|
|
||||||
|
private List<VmDiskInfo> dataDiskInfoList;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommandName() {
|
||||||
|
return s_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccountName() {
|
||||||
|
if (accountName == null) {
|
||||||
|
return CallContext.current().getCallingAccount().getAccountName();
|
||||||
|
}
|
||||||
|
return accountName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDiskOfferingId() {
|
||||||
|
return diskOfferingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeploymentPlanner() {
|
||||||
|
return deploymentPlanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDomainId() {
|
||||||
|
if (domainId == null) {
|
||||||
|
return CallContext.current().getCallingAccount().getDomainId();
|
||||||
|
}
|
||||||
|
return domainId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiConstants.BootType getBootType() {
|
||||||
|
if (StringUtils.isNotBlank(bootType)) {
|
||||||
|
try {
|
||||||
|
String type = bootType.trim().toUpperCase();
|
||||||
|
return ApiConstants.BootType.valueOf(type);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
String errMesg = "Invalid bootType " + bootType + "Specified for vm " + getName()
|
||||||
|
+ " Valid values are: " + Arrays.toString(ApiConstants.BootType.values());
|
||||||
|
logger.warn(errMesg);
|
||||||
|
throw new InvalidParameterValueException(errMesg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getDetails() {
|
||||||
|
Map<String, String> customparameterMap = convertDetailsToMap(details);
|
||||||
|
|
||||||
|
if (getBootType() != null) {
|
||||||
|
customparameterMap.put(getBootType().toString(), getBootMode().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootdisksize != null && !customparameterMap.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) {
|
||||||
|
customparameterMap.put(VmDetailConstants.ROOT_DISK_SIZE, rootdisksize.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
IoDriverPolicy ioPolicy = getIoDriverPolicy();
|
||||||
|
if (ioPolicy != null) {
|
||||||
|
customparameterMap.put(VmDetailConstants.IO_POLICY, ioPolicy.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BooleanUtils.toBoolean(iothreadsEnabled)) {
|
||||||
|
customparameterMap.put(VmDetailConstants.IOTHREADS, BooleanUtils.toStringTrueFalse(iothreadsEnabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nicMultiqueueNumber != null) {
|
||||||
|
customparameterMap.put(VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BooleanUtils.toBoolean(nicPackedVirtQueues)) {
|
||||||
|
customparameterMap.put(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, BooleanUtils.toStringTrueFalse(nicPackedVirtQueues));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MapUtils.isNotEmpty(externalDetails)) {
|
||||||
|
customparameterMap.putAll(getExternalDetails());
|
||||||
|
}
|
||||||
|
return customparameterMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getExternalDetails() {
|
||||||
|
return convertExternalDetailsToMap(externalDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiConstants.BootMode getBootMode() {
|
||||||
|
if (StringUtils.isNotBlank(bootMode)) {
|
||||||
|
try {
|
||||||
|
String mode = bootMode.trim().toUpperCase();
|
||||||
|
return ApiConstants.BootMode.valueOf(mode);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
String msg = String.format("Invalid %s: %s specified for VM: %s. Valid values are: %s",
|
||||||
|
ApiConstants.BOOT_MODE, bootMode, getName(), Arrays.toString(ApiConstants.BootMode.values()));
|
||||||
|
logger.error(msg);
|
||||||
|
throw new InvalidParameterValueException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ApiConstants.BootType.UEFI.equals(getBootType())) {
|
||||||
|
String msg = String.format("%s must be specified for the VM with boot type: %s. Valid values are: %s",
|
||||||
|
ApiConstants.BOOT_MODE, getBootType(), Arrays.toString(ApiConstants.BootMode.values()));
|
||||||
|
logger.error(msg);
|
||||||
|
throw new InvalidParameterValueException(msg);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getVmProperties() {
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
if (MapUtils.isNotEmpty(vAppProperties)) {
|
||||||
|
Collection parameterCollection = vAppProperties.values();
|
||||||
|
Iterator iterator = parameterCollection.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
HashMap<String, String> entry = (HashMap<String, String>)iterator.next();
|
||||||
|
map.put(entry.get("key"), entry.get("value"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, Long> getVmNetworkMap() {
|
||||||
|
Map<Integer, Long> map = new HashMap<>();
|
||||||
|
if (MapUtils.isNotEmpty(vAppNetworks)) {
|
||||||
|
Collection parameterCollection = vAppNetworks.values();
|
||||||
|
Iterator iterator = parameterCollection.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
HashMap<String, String> entry = (HashMap<String, String>) iterator.next();
|
||||||
|
Integer nic;
|
||||||
|
try {
|
||||||
|
nic = Integer.valueOf(entry.get(VmDetailConstants.NIC));
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
nic = null;
|
||||||
|
}
|
||||||
|
String networkUuid = entry.get(VmDetailConstants.NETWORK);
|
||||||
|
if (logger.isTraceEnabled()) {
|
||||||
|
logger.trace(String.format("nic, '%s', goes on net, '%s'", nic, networkUuid));
|
||||||
|
}
|
||||||
|
if (nic == null || StringUtils.isEmpty(networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic));
|
||||||
|
}
|
||||||
|
map.put(nic, _entityMgr.findByUuid(Network.class, networkUuid).getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroup() {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HypervisorType getHypervisor() {
|
||||||
|
return HypervisorType.getType(hypervisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isDisplayVm() {
|
||||||
|
return displayVm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDisplay() {
|
||||||
|
if(displayVm == null)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return displayVm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getSecurityGroupNameList() {
|
||||||
|
return securityGroupNameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getSecurityGroupIdList() {
|
||||||
|
return securityGroupIdList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserData() {
|
||||||
|
return userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUserdataId() {
|
||||||
|
return userdataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getUserdataDetails() {
|
||||||
|
return convertDetailsToMap(userdataDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLeaseDuration() {
|
||||||
|
return leaseDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VMLeaseManager.ExpiryAction getLeaseExpiryAction() {
|
||||||
|
if (StringUtils.isBlank(leaseExpiryAction)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
VMLeaseManager.ExpiryAction action = EnumUtils.getEnumIgnoreCase(VMLeaseManager.ExpiryAction.class, leaseExpiryAction);
|
||||||
|
if (action == null) {
|
||||||
|
throw new InvalidParameterValueException("Invalid value configured for leaseexpiryaction, valid values are: " +
|
||||||
|
com.cloud.utils.EnumUtils.listValues(VMLeaseManager.ExpiryAction.values()));
|
||||||
|
}
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getNetworkIds() {
|
||||||
|
if (MapUtils.isNotEmpty(vAppNetworks)) {
|
||||||
|
if (CollectionUtils.isNotEmpty(networkIds) || ipAddress != null || getIp6Address() != null || MapUtils.isNotEmpty(ipToNetworkList)) {
|
||||||
|
throw new InvalidParameterValueException(String.format("%s can't be specified along with %s, %s, %s", ApiConstants.NIC_NETWORK_LIST, ApiConstants.NETWORK_IDS, ApiConstants.IP_ADDRESS, ApiConstants.IP_NETWORK_LIST));
|
||||||
|
} else {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) {
|
||||||
|
if ((networkIds != null && !networkIds.isEmpty()) || ipAddress != null || getIp6Address() != null) {
|
||||||
|
throw new InvalidParameterValueException("ipToNetworkMap can't be specified along with networkIds or ipAddress");
|
||||||
|
} else {
|
||||||
|
List<Long> networks = new ArrayList<Long>();
|
||||||
|
networks.addAll(getIpToNetworkMap().keySet());
|
||||||
|
return networks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return networkIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getSSHKeyPairNames() {
|
||||||
|
List<String> sshKeyPairs = new ArrayList<String>();
|
||||||
|
if(sshKeyPairNames != null) {
|
||||||
|
sshKeyPairs = sshKeyPairNames;
|
||||||
|
}
|
||||||
|
if(sshKeyPairName != null && !sshKeyPairName.isEmpty()) {
|
||||||
|
sshKeyPairs.add(sshKeyPairName);
|
||||||
|
}
|
||||||
|
return sshKeyPairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VmDiskInfo> getDataDiskInfoList() {
|
||||||
|
if (this.dataDiskInfoList != null) {
|
||||||
|
return this.dataDiskInfoList;
|
||||||
|
}
|
||||||
|
if (dataDisksDetails == null || dataDisksDetails.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (dataDiskTemplateToDiskOfferingList != null) {
|
||||||
|
throw new InvalidParameterValueException("datadisktemplatetodiskofferinglist parameter can't be specified along with datadisksdetails parameter");
|
||||||
|
}
|
||||||
|
List<VmDiskInfo> vmDiskInfoList = new ArrayList<>();
|
||||||
|
Collection dataDisksCollection = dataDisksDetails.values();
|
||||||
|
Iterator iter = dataDisksCollection.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
HashMap<String, String> dataDisk = (HashMap<String, String>)iter.next();
|
||||||
|
String diskOfferingUuid = dataDisk.get(ApiConstants.DISK_OFFERING_ID);
|
||||||
|
if (diskOfferingUuid == null) {
|
||||||
|
throw new InvalidParameterValueException("diskofferingid parameter is required for datadiskdetails");
|
||||||
|
}
|
||||||
|
DiskOffering diskOffering = _entityMgr.findByUuid(DiskOffering.class, diskOfferingUuid);
|
||||||
|
if (diskOffering == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingUuid);
|
||||||
|
}
|
||||||
|
if (diskOffering.isComputeOnly()) {
|
||||||
|
throw new InvalidParameterValueException(String.format("The disk offering id %d provided is directly mapped to a service offering, please provide an individual disk offering", diskOffering.getUuid()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Long size = null;
|
||||||
|
Long minIops = null;
|
||||||
|
Long maxIops = null;
|
||||||
|
if (dataDisk.get(ApiConstants.DEVICE_ID) == null) {
|
||||||
|
throw new InvalidParameterValueException("deviceid parameter is required for datadiskdetails");
|
||||||
|
}
|
||||||
|
Long deviceId = Long.parseLong(dataDisk.get(ApiConstants.DEVICE_ID));
|
||||||
|
if (diskOffering.isCustomized()) {
|
||||||
|
if (dataDisk.get(ApiConstants.SIZE) == null) {
|
||||||
|
throw new InvalidParameterValueException("Size is required for custom disk offering");
|
||||||
|
}
|
||||||
|
size = Long.parseLong(dataDisk.get(ApiConstants.SIZE));
|
||||||
|
} else {
|
||||||
|
size = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
|
||||||
|
}
|
||||||
|
if (diskOffering.isCustomizedIops() != null && diskOffering.isCustomizedIops()) {
|
||||||
|
if (dataDisk.get(ApiConstants.MIN_IOPS) == null) {
|
||||||
|
throw new InvalidParameterValueException("Min IOPS is required for custom disk offering");
|
||||||
|
}
|
||||||
|
if (dataDisk.get(ApiConstants.MAX_IOPS) == null) {
|
||||||
|
throw new InvalidParameterValueException("Max IOPS is required for custom disk offering");
|
||||||
|
}
|
||||||
|
minIops = Long.parseLong(dataDisk.get(ApiConstants.MIN_IOPS));
|
||||||
|
maxIops = Long.parseLong(dataDisk.get(ApiConstants.MAX_IOPS));
|
||||||
|
}
|
||||||
|
VmDiskInfo vmDiskInfo = new VmDiskInfo(diskOffering, size, minIops, maxIops, deviceId);
|
||||||
|
vmDiskInfoList.add(vmDiskInfo);
|
||||||
|
}
|
||||||
|
this.dataDiskInfoList = vmDiskInfoList;
|
||||||
|
return dataDiskInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getHostId() {
|
||||||
|
return hostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getStartVm() {
|
||||||
|
return startVm == null ? true : startVm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Long, IpAddresses> getIpToNetworkMap() {
|
||||||
|
if ((networkIds != null || ipAddress != null || getIp6Address() != null) && ipToNetworkList != null) {
|
||||||
|
throw new InvalidParameterValueException("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter");
|
||||||
|
}
|
||||||
|
LinkedHashMap<Long, IpAddresses> ipToNetworkMap = null;
|
||||||
|
if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) {
|
||||||
|
ipToNetworkMap = new LinkedHashMap<Long, IpAddresses>();
|
||||||
|
Collection ipsCollection = ipToNetworkList.values();
|
||||||
|
Iterator iter = ipsCollection.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
HashMap<String, String> ips = (HashMap<String, String>)iter.next();
|
||||||
|
Long networkId = getNetworkIdFomIpMap(ips);
|
||||||
|
IpAddresses addrs = getIpAddressesFromIpMap(ips);
|
||||||
|
ipToNetworkMap.put(networkId, addrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipToNetworkMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private IpAddresses getIpAddressesFromIpMap(HashMap<String, String> ips) {
|
||||||
|
String requestedIp = ips.get("ip");
|
||||||
|
String requestedIpv6 = ips.get("ipv6");
|
||||||
|
String requestedMac = ips.get("mac");
|
||||||
|
if (requestedIpv6 != null) {
|
||||||
|
requestedIpv6 = NetUtils.standardizeIp6Address(requestedIpv6);
|
||||||
|
}
|
||||||
|
if (requestedMac != null) {
|
||||||
|
if(!NetUtils.isValidMac(requestedMac)) {
|
||||||
|
throw new InvalidParameterValueException("Mac address is not valid: " + requestedMac);
|
||||||
|
} else if(!NetUtils.isUnicastMac(requestedMac)) {
|
||||||
|
throw new InvalidParameterValueException("Mac address is not unicast: " + requestedMac);
|
||||||
|
}
|
||||||
|
requestedMac = NetUtils.standardizeMacAddress(requestedMac);
|
||||||
|
}
|
||||||
|
return new IpAddresses(requestedIp, requestedIpv6, requestedMac);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private Long getNetworkIdFomIpMap(HashMap<String, String> ips) {
|
||||||
|
Long networkId;
|
||||||
|
final String networkid = ips.get("networkid");
|
||||||
|
Network network = _networkService.getNetwork(networkid);
|
||||||
|
if (network != null) {
|
||||||
|
networkId = network.getId();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
networkId = Long.parseLong(networkid);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new InvalidParameterValueException("Unable to translate and find entity with networkId: " + networkid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return networkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIpAddress() {
|
||||||
|
return ipAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIp6Address() {
|
||||||
|
if (ip6Address == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return NetUtils.standardizeIp6Address(ip6Address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getMacAddress() {
|
||||||
|
if (macAddress == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(!NetUtils.isValidMac(macAddress)) {
|
||||||
|
throw new InvalidParameterValueException("Mac address is not valid: " + macAddress);
|
||||||
|
} else if(!NetUtils.isUnicastMac(macAddress)) {
|
||||||
|
throw new InvalidParameterValueException("Mac address is not unicast: " + macAddress);
|
||||||
|
}
|
||||||
|
return NetUtils.standardizeMacAddress(macAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Long> getAffinityGroupIdList() {
|
||||||
|
if (affinityGroupNameList != null && affinityGroupIdList != null) {
|
||||||
|
throw new InvalidParameterValueException("affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
// transform group names to ids here
|
||||||
|
if (affinityGroupNameList != null) {
|
||||||
|
List<Long> affinityGroupIds = new ArrayList<Long>();
|
||||||
|
for (String groupName : affinityGroupNameList) {
|
||||||
|
Long groupId = _responseGenerator.getAffinityGroupId(groupName, getEntityOwnerId());
|
||||||
|
if (groupId == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to find affinity group by name " + groupName);
|
||||||
|
} else {
|
||||||
|
affinityGroupIds.add(groupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return affinityGroupIds;
|
||||||
|
} else {
|
||||||
|
return affinityGroupIdList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKeyboard() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Map<Integer, String>> getDhcpOptionsMap() {
|
||||||
|
Map<String, Map<Integer, String>> dhcpOptionsMap = new HashMap<>();
|
||||||
|
if (dhcpOptionsNetworkList != null && !dhcpOptionsNetworkList.isEmpty()) {
|
||||||
|
|
||||||
|
Collection<Map<String, String>> paramsCollection = this.dhcpOptionsNetworkList.values();
|
||||||
|
for (Map<String, String> dhcpNetworkOptions : paramsCollection) {
|
||||||
|
String networkId = dhcpNetworkOptions.get(ApiConstants.NETWORK_ID);
|
||||||
|
|
||||||
|
if (networkId == null) {
|
||||||
|
throw new IllegalArgumentException("No networkid specified when providing extra dhcp options.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, String> dhcpOptionsForNetwork = new HashMap<>();
|
||||||
|
dhcpOptionsMap.put(networkId, dhcpOptionsForNetwork);
|
||||||
|
|
||||||
|
for (String key : dhcpNetworkOptions.keySet()) {
|
||||||
|
if (key.startsWith(ApiConstants.DHCP_PREFIX)) {
|
||||||
|
int dhcpOptionValue = Integer.parseInt(key.replaceFirst(ApiConstants.DHCP_PREFIX, ""));
|
||||||
|
dhcpOptionsForNetwork.put(dhcpOptionValue, dhcpNetworkOptions.get(key));
|
||||||
|
} else if (!key.equals(ApiConstants.NETWORK_ID)) {
|
||||||
|
Dhcp.DhcpOptionCode dhcpOptionEnum = Dhcp.DhcpOptionCode.valueOfString(key);
|
||||||
|
dhcpOptionsForNetwork.put(dhcpOptionEnum.getCode(), dhcpNetworkOptions.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dhcpOptionsMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Long, DiskOffering> getDataDiskTemplateToDiskOfferingMap() {
|
||||||
|
if (diskOfferingId != null && dataDiskTemplateToDiskOfferingList != null) {
|
||||||
|
throw new InvalidParameterValueException("diskofferingid parameter can't be specified along with datadisktemplatetodiskofferinglist parameter");
|
||||||
|
}
|
||||||
|
if (MapUtils.isEmpty(dataDiskTemplateToDiskOfferingList)) {
|
||||||
|
return new HashMap<Long, DiskOffering>();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap = new HashMap<Long, DiskOffering>();
|
||||||
|
for (Object objDataDiskTemplates : dataDiskTemplateToDiskOfferingList.values()) {
|
||||||
|
HashMap<String, String> dataDiskTemplates = (HashMap<String, String>) objDataDiskTemplates;
|
||||||
|
Long dataDiskTemplateId;
|
||||||
|
DiskOffering dataDiskOffering = null;
|
||||||
|
VirtualMachineTemplate dataDiskTemplate= _entityMgr.findByUuid(VirtualMachineTemplate.class, dataDiskTemplates.get("datadisktemplateid"));
|
||||||
|
if (dataDiskTemplate == null) {
|
||||||
|
dataDiskTemplate = _entityMgr.findById(VirtualMachineTemplate.class, dataDiskTemplates.get("datadisktemplateid"));
|
||||||
|
if (dataDiskTemplate == null)
|
||||||
|
throw new InvalidParameterValueException("Unable to translate and find entity with datadisktemplateid " + dataDiskTemplates.get("datadisktemplateid"));
|
||||||
|
}
|
||||||
|
dataDiskTemplateId = dataDiskTemplate.getId();
|
||||||
|
dataDiskOffering = _entityMgr.findByUuid(DiskOffering.class, dataDiskTemplates.get("diskofferingid"));
|
||||||
|
if (dataDiskOffering == null) {
|
||||||
|
dataDiskOffering = _entityMgr.findById(DiskOffering.class, dataDiskTemplates.get("diskofferingid"));
|
||||||
|
if (dataDiskOffering == null)
|
||||||
|
throw new InvalidParameterValueException("Unable to translate and find entity with diskofferingId " + dataDiskTemplates.get("diskofferingid"));
|
||||||
|
}
|
||||||
|
dataDiskTemplateToDiskOfferingMap.put(dataDiskTemplateId, dataDiskOffering);
|
||||||
|
}
|
||||||
|
return dataDiskTemplateToDiskOfferingMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExtraConfig() {
|
||||||
|
return extraConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getCopyImageTags() {
|
||||||
|
return copyImageTags == null ? false : copyImageTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getBootIntoSetup() {
|
||||||
|
return bootIntoSetup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDynamicScalingEnabled() {
|
||||||
|
return dynamicScalingEnabled == null ? true : dynamicScalingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getOverrideDiskOfferingId() {
|
||||||
|
return overrideDiskOfferingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IoDriverPolicy getIoDriverPolicy() {
|
||||||
|
if (StringUtils.isNotBlank(ioDriverPolicy)) {
|
||||||
|
try {
|
||||||
|
String policyType = ioDriverPolicy.trim().toUpperCase();
|
||||||
|
return IoDriverPolicy.valueOf(policyType);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
String errMesg = String.format("Invalid io policy %s specified for vm %s. Valid values are: %s", ioDriverPolicy, getName(), Arrays.toString(IoDriverPolicy.values()));
|
||||||
|
logger.warn(errMesg);
|
||||||
|
throw new InvalidParameterValueException(errMesg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////// API Implementation///////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public static String getResultObjectName() {
|
||||||
|
return "virtualmachine";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
|
||||||
|
if (accountId == null) {
|
||||||
|
return CallContext.current().getCallingAccount().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEventType() {
|
||||||
|
return EventTypes.EVENT_VM_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCreateEventType() {
|
||||||
|
return EventTypes.EVENT_VM_CREATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCreateEventDescription() {
|
||||||
|
return "creating Vm";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEventDescription() {
|
||||||
|
if(getStartVm()) {
|
||||||
|
return "starting Vm. Vm Id: " + getEntityUuid();
|
||||||
|
}
|
||||||
|
return "deploying Vm. Vm Id: " + getEntityUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiCommandResourceType getApiResourceType() {
|
||||||
|
return ApiCommandResourceType.VirtualMachine;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,153 @@
|
|||||||
|
// 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.vm;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.ACL;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject;
|
||||||
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.api.response.BackupResponse;
|
||||||
|
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||||
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
|
|
||||||
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
|
import com.cloud.exception.InsufficientServerCapacityException;
|
||||||
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.uservm.UserVm;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
|
||||||
|
@APICommand(name = "createVMFromBackup",
|
||||||
|
description = "Creates and automatically starts a VM from a backup.",
|
||||||
|
responseObject = UserVmResponse.class,
|
||||||
|
responseView = ResponseObject.ResponseView.Restricted,
|
||||||
|
entityType = {VirtualMachine.class},
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true,
|
||||||
|
since = "4.21.0",
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||||
|
public class CreateVMFromBackupCmd extends BaseDeployVMCmd {
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.BACKUP_ID,
|
||||||
|
type = CommandType.UUID,
|
||||||
|
entityType = BackupResponse.class,
|
||||||
|
required = true,
|
||||||
|
description = "backup ID to create the VM from")
|
||||||
|
private Long backupId;
|
||||||
|
|
||||||
|
@ACL
|
||||||
|
@Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class, description = "the ID of the service offering for the virtual machine")
|
||||||
|
private Long serviceOfferingId;
|
||||||
|
|
||||||
|
@ACL
|
||||||
|
@Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the ID of the template for the virtual machine")
|
||||||
|
private Long templateId;
|
||||||
|
|
||||||
|
@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 original Instance is deleted and the IP/MAC address is available.")
|
||||||
|
private Boolean preserveIp;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public Long getBackupId() {
|
||||||
|
return backupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getServiceOfferingId() {
|
||||||
|
return serviceOfferingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTemplateId() {
|
||||||
|
return templateId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getPreserveIp() {
|
||||||
|
return (preserveIp != null) ? preserveIp : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create() {
|
||||||
|
UserVm vm;
|
||||||
|
try {
|
||||||
|
vm = _userVmService.allocateVMFromBackup(this);
|
||||||
|
if (vm != null) {
|
||||||
|
setEntityId(vm.getId());
|
||||||
|
setEntityUuid(vm.getUuid());
|
||||||
|
} else {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to deploy vm");
|
||||||
|
}
|
||||||
|
} catch (InsufficientCapacityException ex) {
|
||||||
|
logger.info(ex);
|
||||||
|
logger.trace(ex.getMessage(), ex);
|
||||||
|
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
|
||||||
|
} catch (ResourceUnavailableException ex) {
|
||||||
|
logger.warn("Exception: ", ex);
|
||||||
|
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
|
||||||
|
} catch (ConcurrentOperationException ex) {
|
||||||
|
logger.warn("Exception: ", ex);
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
|
||||||
|
} catch (ResourceAllocationException ex) {
|
||||||
|
logger.warn("Exception: ", ex);
|
||||||
|
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute () {
|
||||||
|
UserVm vm = null;
|
||||||
|
try {
|
||||||
|
vm = _userVmService.restoreVMFromBackup(this);
|
||||||
|
} catch (ResourceUnavailableException ex) {
|
||||||
|
logger.warn("Exception: ", ex);
|
||||||
|
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
|
||||||
|
} catch (ResourceAllocationException ex) {
|
||||||
|
logger.warn("Exception: ", ex);
|
||||||
|
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
|
||||||
|
} catch (ConcurrentOperationException ex) {
|
||||||
|
logger.warn("Exception: ", ex);
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
|
||||||
|
} catch (InsufficientCapacityException ex) {
|
||||||
|
StringBuilder message = new StringBuilder(ex.getMessage());
|
||||||
|
if (ex instanceof InsufficientServerCapacityException) {
|
||||||
|
if (((InsufficientServerCapacityException)ex).isAffinityApplied()) {
|
||||||
|
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info(String.format("%s: %s", message.toString(), ex.getLocalizedMessage()));
|
||||||
|
logger.debug(message.toString(), ex);
|
||||||
|
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm != null) {
|
||||||
|
UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", vm).get(0);
|
||||||
|
response.setResponseName(getCommandName());
|
||||||
|
setResponseObject(response);
|
||||||
|
} else {
|
||||||
|
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to deploy vm uuid:"+getEntityUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,87 +16,40 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.command.user.vm;
|
package org.apache.cloudstack.api.command.user.vm;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import org.apache.cloudstack.acl.RoleType;
|
|
||||||
import org.apache.cloudstack.affinity.AffinityGroupResponse;
|
|
||||||
import org.apache.cloudstack.api.ACL;
|
import org.apache.cloudstack.api.ACL;
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
import org.apache.cloudstack.api.ApiArgValidator;
|
|
||||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.api.ApiConstants.IoDriverPolicy;
|
|
||||||
import org.apache.cloudstack.api.ApiErrorCode;
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
import org.apache.cloudstack.api.BaseAsyncCreateCustomIdCmd;
|
|
||||||
import org.apache.cloudstack.api.Parameter;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
import org.apache.cloudstack.api.command.user.UserCmd;
|
|
||||||
import org.apache.cloudstack.api.response.DiskOfferingResponse;
|
|
||||||
import org.apache.cloudstack.api.response.DomainResponse;
|
|
||||||
import org.apache.cloudstack.api.response.HostResponse;
|
|
||||||
import org.apache.cloudstack.api.response.NetworkResponse;
|
|
||||||
import org.apache.cloudstack.api.response.ProjectResponse;
|
|
||||||
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
|
||||||
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.SnapshotResponse;
|
import org.apache.cloudstack.api.response.SnapshotResponse;
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
import org.apache.cloudstack.api.response.UserDataResponse;
|
|
||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
import org.apache.cloudstack.api.response.VolumeResponse;
|
import org.apache.cloudstack.api.response.VolumeResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.vm.lease.VMLeaseManager;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.apache.commons.collections.MapUtils;
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
|
||||||
import org.apache.commons.lang3.EnumUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import com.cloud.agent.api.LogLevel;
|
|
||||||
import com.cloud.event.EventTypes;
|
|
||||||
import com.cloud.exception.ConcurrentOperationException;
|
import com.cloud.exception.ConcurrentOperationException;
|
||||||
import com.cloud.exception.InsufficientCapacityException;
|
import com.cloud.exception.InsufficientCapacityException;
|
||||||
import com.cloud.exception.InsufficientServerCapacityException;
|
import com.cloud.exception.InsufficientServerCapacityException;
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
|
||||||
import com.cloud.exception.ResourceAllocationException;
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
import com.cloud.exception.ResourceUnavailableException;
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
|
||||||
import com.cloud.network.Network;
|
|
||||||
import com.cloud.network.Network.IpAddresses;
|
|
||||||
import com.cloud.offering.DiskOffering;
|
|
||||||
import com.cloud.template.VirtualMachineTemplate;
|
|
||||||
import com.cloud.uservm.UserVm;
|
import com.cloud.uservm.UserVm;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.net.Dhcp;
|
|
||||||
import com.cloud.utils.net.NetUtils;
|
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VmDetailConstants;
|
|
||||||
|
|
||||||
@APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
|
@APICommand(name = "deployVirtualMachine", description = "Creates and automatically starts a virtual machine based on a service offering, disk offering, and template.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
|
||||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
|
||||||
public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityGroupAction, UserCmd {
|
public class DeployVMCmd extends BaseDeployVMCmd {
|
||||||
|
|
||||||
private static final String s_name = "deployvirtualmachineresponse";
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
//////////////// API parameters /////////////////////
|
//////////////// API parameters /////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "availability zone for the virtual machine")
|
|
||||||
private Long zoneId;
|
|
||||||
|
|
||||||
@ACL
|
@ACL
|
||||||
@Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class, required = true, description = "the ID of the service offering for the virtual machine")
|
@Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class, required = true, description = "the ID of the service offering for the virtual machine")
|
||||||
private Long serviceOfferingId;
|
private Long serviceOfferingId;
|
||||||
@ -105,672 +58,24 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
@Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the ID of the template for the virtual machine")
|
@Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the ID of the template for the virtual machine")
|
||||||
private Long templateId;
|
private Long templateId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "host name for the virtual machine", validations = {ApiArgValidator.RFCComplianceDomainName})
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DISPLAY_NAME, type = CommandType.STRING, description = "an optional user generated name for the virtual machine")
|
|
||||||
private String displayName;
|
|
||||||
|
|
||||||
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="The password of the virtual machine. If null, a random password will be generated for the VM.",
|
|
||||||
since="4.19.0.0")
|
|
||||||
protected String password;
|
|
||||||
|
|
||||||
//Owner information
|
|
||||||
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.")
|
|
||||||
private String accountName;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used. If account is NOT provided then virtual machine will be assigned to the caller account and domain.")
|
|
||||||
private Long domainId;
|
|
||||||
|
|
||||||
//Network information
|
|
||||||
//@ACL(accessType = AccessType.UseEntry)
|
|
||||||
@Parameter(name = ApiConstants.NETWORK_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = NetworkResponse.class, description = "list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter")
|
|
||||||
private List<Long> networkIds;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.BOOT_TYPE, type = CommandType.STRING, required = false, description = "Guest VM Boot option either custom[UEFI] or default boot [BIOS]. Not applicable with VMware if the template is marked as deploy-as-is, as we honour what is defined in the template.", since = "4.14.0.0")
|
|
||||||
private String bootType;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.BOOT_MODE, type = CommandType.STRING, required = false, description = "Boot Mode [Legacy] or [Secure] Applicable when Boot Type Selected is UEFI, otherwise Legacy only for BIOS. Not applicable with VMware if the template is marked as deploy-as-is, as we honour what is defined in the template.", since = "4.14.0.0")
|
|
||||||
private String bootMode;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.BOOT_INTO_SETUP, type = CommandType.BOOLEAN, required = false, description = "Boot into hardware setup or not (ignored if startVm = false, only valid for vmware)", since = "4.15.0.0")
|
|
||||||
private Boolean bootIntoSetup;
|
|
||||||
|
|
||||||
//DataDisk information
|
|
||||||
@ACL
|
|
||||||
@Parameter(name = ApiConstants.DISK_OFFERING_ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, description = "the ID of the disk offering for the virtual machine. If the template is of ISO format,"
|
|
||||||
+ " the diskOfferingId is for the root disk volume. Otherwise this parameter is used to indicate the "
|
|
||||||
+ "offering for the data disk volume. If the templateId parameter passed is from a Template object,"
|
|
||||||
+ " the diskOfferingId refers to a DATA Disk Volume created. If the templateId parameter passed is "
|
|
||||||
+ "from an ISO object, the diskOfferingId refers to a ROOT Disk Volume created.")
|
|
||||||
private Long diskOfferingId;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.SIZE, type = CommandType.LONG, description = "the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId")
|
|
||||||
private Long size;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.ROOT_DISK_SIZE,
|
|
||||||
type = CommandType.LONG,
|
|
||||||
description = "Optional field to resize root disk on deploy. Value is in GB. Only applies to template-based deployments. Analogous to details[0].rootdisksize, which takes precedence over this parameter if both are provided",
|
|
||||||
since = "4.4")
|
|
||||||
private Long rootdisksize;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.GROUP, type = CommandType.STRING, description = "an optional group for the virtual machine")
|
|
||||||
private String group;
|
|
||||||
|
|
||||||
@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;
|
|
||||||
|
|
||||||
@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. " +
|
|
||||||
"This binary data must be base64 encoded before adding it to the request. " +
|
|
||||||
"Using HTTP GET (via querystring), you can send up to 4KB of data after base64 encoding. " +
|
|
||||||
"Using HTTP POST (via POST body), you can send up to 1MB of data after base64 encoding. " +
|
|
||||||
"You also need to change vm.userdata.max.length value",
|
|
||||||
length = 1048576)
|
|
||||||
private String userData;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.USER_DATA_ID, type = CommandType.UUID, entityType = UserDataResponse.class, description = "the ID of the Userdata", since = "4.18")
|
|
||||||
private Long userdataId;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.USER_DATA_DETAILS, type = CommandType.MAP, description = "used to specify the parameters values for the variables in userdata.", since = "4.18")
|
|
||||||
private Map userdataDetails;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@Parameter(name = ApiConstants.SSH_KEYPAIR, type = CommandType.STRING, description = "name of the ssh key pair used to login to the virtual machine")
|
|
||||||
private String sshKeyPairName;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.SSH_KEYPAIRS, type = CommandType.LIST, collectionType = CommandType.STRING, since="4.17", description = "names of the ssh key pairs used to login to the virtual machine")
|
|
||||||
private List<String> sshKeyPairNames;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "destination Host ID to deploy the VM to - parameter available for root admin only")
|
|
||||||
private Long hostId;
|
|
||||||
|
|
||||||
@ACL
|
|
||||||
@Parameter(name = ApiConstants.SECURITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = SecurityGroupResponse.class, description = "comma separated list of security groups id that going to be applied to the virtual machine. "
|
|
||||||
+ "Should be passed only when vm is created from a zone with Basic Network support." + " Mutually exclusive with securitygroupnames parameter")
|
|
||||||
private List<Long> securityGroupIdList;
|
|
||||||
|
|
||||||
@ACL
|
|
||||||
@Parameter(name = ApiConstants.SECURITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = SecurityGroupResponse.class, description = "comma separated list of security groups names that going to be applied to the virtual machine."
|
|
||||||
+ " Should be passed only when vm is created from a zone with Basic Network support. " + "Mutually exclusive with securitygroupids parameter")
|
|
||||||
private List<String> securityGroupNameList;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, description = "ip to network mapping. Can't be specified with networkIds parameter."
|
|
||||||
+ " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].ipv6=fc00:1234:5678::abcd&iptonetworklist[0].networkid=uuid&iptonetworklist[0].mac=aa:bb:cc:dd:ee::ff - requests to use ip 10.10.10.11 in network id=uuid")
|
|
||||||
private Map ipToNetworkList;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, description = "the ip address for default vm's network")
|
|
||||||
private String ipAddress;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.IP6_ADDRESS, type = CommandType.STRING, description = "the ipv6 address for default vm's network")
|
|
||||||
private String ip6Address;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.MAC_ADDRESS, type = CommandType.STRING, description = "the mac address for default vm's network")
|
|
||||||
private String macAddress;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.KEYBOARD, type = CommandType.STRING, description = "an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr,fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us")
|
|
||||||
private String keyboard;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Deploy vm for the project")
|
|
||||||
private Long projectId;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.START_VM, type = CommandType.BOOLEAN, description = "true if start vm after creating; defaulted to true if not specified")
|
|
||||||
private Boolean startVm;
|
|
||||||
|
|
||||||
@ACL
|
|
||||||
@Parameter(name = ApiConstants.AFFINITY_GROUP_IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups id that are going to be applied to the virtual machine."
|
|
||||||
+ " Mutually exclusive with affinitygroupnames parameter")
|
|
||||||
private List<Long> affinityGroupIdList;
|
|
||||||
|
|
||||||
@ACL
|
|
||||||
@Parameter(name = ApiConstants.AFFINITY_GROUP_NAMES, type = CommandType.LIST, collectionType = CommandType.STRING, entityType = AffinityGroupResponse.class, description = "comma separated list of affinity groups names that are going to be applied to the virtual machine."
|
|
||||||
+ "Mutually exclusive with affinitygroupids parameter")
|
|
||||||
private List<String> 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;
|
|
||||||
|
|
||||||
@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;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DEPLOYMENT_PLANNER, type = CommandType.STRING, description = "Deployment planner to use for vm allocation. Available to ROOT admin only", since = "4.4", authorized = { RoleType.Admin })
|
|
||||||
private String deploymentPlanner;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DHCP_OPTIONS_NETWORK_LIST, type = CommandType.MAP, description = "DHCP options which are passed to the VM on start up"
|
|
||||||
+ " Example: dhcpoptionsnetworklist[0].dhcp:114=url&dhcpoptionsetworklist[0].networkid=networkid&dhcpoptionsetworklist[0].dhcp:66=www.test.com")
|
|
||||||
private Map dhcpOptionsNetworkList;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DATADISK_OFFERING_LIST, type = CommandType.MAP, since = "4.11", description = "datadisk template to disk-offering mapping;" +
|
|
||||||
" an optional parameter used to create additional data disks from datadisk templates; can't be specified with diskOfferingId parameter")
|
|
||||||
private Map dataDiskTemplateToDiskOfferingList;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.EXTRA_CONFIG, type = CommandType.STRING, since = "4.12", description = "an optional URL encoded string that can be passed to the virtual machine upon successful deployment", length = 5120)
|
|
||||||
private String extraConfig;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.COPY_IMAGE_TAGS, type = CommandType.BOOLEAN, since = "4.13", description = "if true the image tags (if any) will be copied to the VM, default value is false")
|
|
||||||
private Boolean copyImageTags;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.PROPERTIES, type = CommandType.MAP, since = "4.15",
|
|
||||||
description = "used to specify the vApp properties.")
|
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
|
||||||
private Map vAppProperties;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.NIC_NETWORK_LIST, type = CommandType.MAP, since = "4.15",
|
|
||||||
description = "VMware only: used to specify network mapping of a vApp VMware template registered \"as-is\"." +
|
|
||||||
" Example nicnetworklist[0].ip=Nic-101&nicnetworklist[0].network=uuid")
|
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
|
||||||
private Map vAppNetworks;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.DYNAMIC_SCALING_ENABLED, type = CommandType.BOOLEAN, since = "4.16",
|
|
||||||
description = "true if virtual machine needs to be dynamically scalable")
|
|
||||||
protected Boolean dynamicScalingEnabled;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.OVERRIDE_DISK_OFFERING_ID, type = CommandType.UUID, since = "4.17", entityType = DiskOfferingResponse.class, description = "the ID of the disk offering for the virtual machine to be used for root volume instead of the disk offering mapped in service offering." +
|
|
||||||
"In case of virtual machine deploying from ISO, then the diskofferingid specified for root volume is ignored and uses this override disk offering id")
|
|
||||||
private Long overrideDiskOfferingId;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.IOTHREADS_ENABLED, type = CommandType.BOOLEAN, required = false,
|
|
||||||
description = "IOThreads are dedicated event loop threads for supported disk devices to perform block I/O requests in order to improve scalability especially on an SMP host/guest with many LUNs.")
|
|
||||||
private Boolean iothreadsEnabled;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.IO_DRIVER_POLICY, type = CommandType.STRING, description = "Controls specific policies on IO")
|
|
||||||
private String ioDriverPolicy;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.NIC_MULTIQUEUE_NUMBER, type = CommandType.INTEGER, since = "4.18",
|
|
||||||
description = "The number of queues for multiqueue NICs.")
|
|
||||||
private Integer nicMultiqueueNumber;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.NIC_PACKED_VIRTQUEUES_ENABLED, type = CommandType.BOOLEAN, since = "4.18",
|
|
||||||
description = "Enable packed virtqueues or not.")
|
|
||||||
private Boolean nicPackedVirtQueues;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.INSTANCE_LEASE_DURATION, type = CommandType.INTEGER, since = "4.21.0",
|
|
||||||
description = "Number of days instance is leased for.")
|
|
||||||
private Integer leaseDuration;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.INSTANCE_LEASE_EXPIRY_ACTION, type = CommandType.STRING, since = "4.21.0",
|
|
||||||
description = "Lease expiry action, valid values are STOP and DESTROY")
|
|
||||||
private String leaseExpiryAction;
|
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.UUID, entityType = VolumeResponse.class, since = "4.21")
|
@Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.UUID, entityType = VolumeResponse.class, since = "4.21")
|
||||||
private Long volumeId;
|
private Long volumeId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.SNAPSHOT_ID, type = CommandType.UUID, entityType = SnapshotResponse.class, since = "4.21")
|
@Parameter(name = ApiConstants.SNAPSHOT_ID, type = CommandType.UUID, entityType = SnapshotResponse.class, since = "4.21")
|
||||||
private Long snapshotId;
|
private Long snapshotId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.EXTERNAL_DETAILS,
|
|
||||||
type = CommandType.MAP,
|
|
||||||
description = "Details in key/value pairs using format externaldetails[i].keyname=keyvalue. Example: externaldetails[0].server.type=typevalue",
|
|
||||||
since = "4.21.0")
|
|
||||||
protected Map externalDetails;
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
public String getAccountName() {
|
|
||||||
if (accountName == null) {
|
|
||||||
return CallContext.current().getCallingAccount().getAccountName();
|
|
||||||
}
|
|
||||||
return accountName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getDiskOfferingId() {
|
|
||||||
return diskOfferingId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeploymentPlanner() {
|
|
||||||
return deploymentPlanner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayName() {
|
|
||||||
return displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getDomainId() {
|
|
||||||
if (domainId == null) {
|
|
||||||
return CallContext.current().getCallingAccount().getDomainId();
|
|
||||||
}
|
|
||||||
return domainId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApiConstants.BootType getBootType() {
|
|
||||||
if (StringUtils.isNotBlank(bootType)) {
|
|
||||||
try {
|
|
||||||
String type = bootType.trim().toUpperCase();
|
|
||||||
return ApiConstants.BootType.valueOf(type);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
String errMesg = "Invalid bootType " + bootType + "Specified for vm " + getName()
|
|
||||||
+ " Valid values are: " + Arrays.toString(ApiConstants.BootType.values());
|
|
||||||
logger.warn(errMesg);
|
|
||||||
throw new InvalidParameterValueException(errMesg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getDetails() {
|
|
||||||
Map<String, String> customparameterMap = convertDetailsToMap(details);
|
|
||||||
|
|
||||||
if (getBootType() != null) {
|
|
||||||
customparameterMap.put(getBootType().toString(), getBootMode().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rootdisksize != null && !customparameterMap.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) {
|
|
||||||
customparameterMap.put(VmDetailConstants.ROOT_DISK_SIZE, rootdisksize.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
IoDriverPolicy ioPolicy = getIoDriverPolicy();
|
|
||||||
if (ioPolicy != null) {
|
|
||||||
customparameterMap.put(VmDetailConstants.IO_POLICY, ioPolicy.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BooleanUtils.toBoolean(iothreadsEnabled)) {
|
|
||||||
customparameterMap.put(VmDetailConstants.IOTHREADS, BooleanUtils.toStringTrueFalse(iothreadsEnabled));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nicMultiqueueNumber != null) {
|
|
||||||
customparameterMap.put(VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BooleanUtils.toBoolean(nicPackedVirtQueues)) {
|
|
||||||
customparameterMap.put(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, BooleanUtils.toStringTrueFalse(nicPackedVirtQueues));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MapUtils.isNotEmpty(externalDetails)) {
|
|
||||||
customparameterMap.putAll(getExternalDetails());
|
|
||||||
}
|
|
||||||
|
|
||||||
return customparameterMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getExternalDetails() {
|
|
||||||
return convertExternalDetailsToMap(externalDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApiConstants.BootMode getBootMode() {
|
|
||||||
if (StringUtils.isNotBlank(bootMode)) {
|
|
||||||
try {
|
|
||||||
String mode = bootMode.trim().toUpperCase();
|
|
||||||
return ApiConstants.BootMode.valueOf(mode);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
String msg = String.format("Invalid %s: %s specified for VM: %s. Valid values are: %s",
|
|
||||||
ApiConstants.BOOT_MODE, bootMode, getName(), Arrays.toString(ApiConstants.BootMode.values()));
|
|
||||||
logger.error(msg);
|
|
||||||
throw new InvalidParameterValueException(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ApiConstants.BootType.UEFI.equals(getBootType())) {
|
|
||||||
String msg = String.format("%s must be specified for the VM with boot type: %s. Valid values are: %s",
|
|
||||||
ApiConstants.BOOT_MODE, getBootType(), Arrays.toString(ApiConstants.BootMode.values()));
|
|
||||||
logger.error(msg);
|
|
||||||
throw new InvalidParameterValueException(msg);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getVmProperties() {
|
|
||||||
Map<String, String> map = new HashMap<>();
|
|
||||||
if (MapUtils.isNotEmpty(vAppProperties)) {
|
|
||||||
Collection parameterCollection = vAppProperties.values();
|
|
||||||
Iterator iterator = parameterCollection.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
HashMap<String, String> entry = (HashMap<String, String>)iterator.next();
|
|
||||||
map.put(entry.get("key"), entry.get("value"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, Long> getVmNetworkMap() {
|
|
||||||
Map<Integer, Long> map = new HashMap<>();
|
|
||||||
if (MapUtils.isNotEmpty(vAppNetworks)) {
|
|
||||||
Collection parameterCollection = vAppNetworks.values();
|
|
||||||
Iterator iterator = parameterCollection.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
HashMap<String, String> entry = (HashMap<String, String>) iterator.next();
|
|
||||||
Integer nic;
|
|
||||||
try {
|
|
||||||
nic = Integer.valueOf(entry.get(VmDetailConstants.NIC));
|
|
||||||
} catch (NumberFormatException nfe) {
|
|
||||||
nic = null;
|
|
||||||
}
|
|
||||||
String networkUuid = entry.get(VmDetailConstants.NETWORK);
|
|
||||||
if (logger.isTraceEnabled()) {
|
|
||||||
logger.trace(String.format("nic, '%s', goes on net, '%s'", nic, networkUuid));
|
|
||||||
}
|
|
||||||
if (nic == null || StringUtils.isEmpty(networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) {
|
|
||||||
throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic));
|
|
||||||
}
|
|
||||||
map.put(nic, _entityMgr.findByUuid(Network.class, networkUuid).getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getGroup() {
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HypervisorType getHypervisor() {
|
|
||||||
return HypervisorType.getType(hypervisor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean isDisplayVm() {
|
|
||||||
return displayVm;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDisplay() {
|
|
||||||
if(displayVm == null)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return displayVm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getSecurityGroupNameList() {
|
|
||||||
return securityGroupNameList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Long> getSecurityGroupIdList() {
|
|
||||||
return securityGroupIdList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getServiceOfferingId() {
|
public Long getServiceOfferingId() {
|
||||||
return serviceOfferingId;
|
return serviceOfferingId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getSize() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getTemplateId() {
|
public Long getTemplateId() {
|
||||||
return templateId;
|
return templateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUserData() {
|
|
||||||
return userData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getUserdataId() {
|
|
||||||
return userdataId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getUserdataDetails() {
|
|
||||||
return convertDetailsToMap(userdataDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getZoneId() {
|
|
||||||
return zoneId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getLeaseDuration() {
|
|
||||||
return leaseDuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VMLeaseManager.ExpiryAction getLeaseExpiryAction() {
|
|
||||||
if (StringUtils.isBlank(leaseExpiryAction)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
VMLeaseManager.ExpiryAction action = EnumUtils.getEnumIgnoreCase(VMLeaseManager.ExpiryAction.class, leaseExpiryAction);
|
|
||||||
if (action == null) {
|
|
||||||
throw new InvalidParameterValueException("Invalid value configured for leaseexpiryaction, valid values are: " +
|
|
||||||
com.cloud.utils.EnumUtils.listValues(VMLeaseManager.ExpiryAction.values()));
|
|
||||||
}
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Long> getNetworkIds() {
|
|
||||||
if (MapUtils.isNotEmpty(vAppNetworks)) {
|
|
||||||
if (CollectionUtils.isNotEmpty(networkIds) || ipAddress != null || getIp6Address() != null || MapUtils.isNotEmpty(ipToNetworkList)) {
|
|
||||||
throw new InvalidParameterValueException(String.format("%s can't be specified along with %s, %s, %s", ApiConstants.NIC_NETWORK_LIST, ApiConstants.NETWORK_IDS, ApiConstants.IP_ADDRESS, ApiConstants.IP_NETWORK_LIST));
|
|
||||||
} else {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) {
|
|
||||||
if ((networkIds != null && !networkIds.isEmpty()) || ipAddress != null || getIp6Address() != null) {
|
|
||||||
throw new InvalidParameterValueException("ipToNetworkMap can't be specified along with networkIds or ipAddress");
|
|
||||||
} else {
|
|
||||||
List<Long> networks = new ArrayList<Long>();
|
|
||||||
networks.addAll(getIpToNetworkMap().keySet());
|
|
||||||
return networks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return networkIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getSSHKeyPairNames() {
|
|
||||||
List<String> sshKeyPairs = new ArrayList<String>();
|
|
||||||
if(sshKeyPairNames != null) {
|
|
||||||
sshKeyPairs = sshKeyPairNames;
|
|
||||||
}
|
|
||||||
if(sshKeyPairName != null && !sshKeyPairName.isEmpty()) {
|
|
||||||
sshKeyPairs.add(sshKeyPairName);
|
|
||||||
}
|
|
||||||
return sshKeyPairs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getHostId() {
|
|
||||||
return hostId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getStartVm() {
|
|
||||||
return startVm == null ? true : startVm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Long, IpAddresses> getIpToNetworkMap() {
|
|
||||||
if ((networkIds != null || ipAddress != null || getIp6Address() != null) && ipToNetworkList != null) {
|
|
||||||
throw new InvalidParameterValueException("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter");
|
|
||||||
}
|
|
||||||
LinkedHashMap<Long, IpAddresses> ipToNetworkMap = null;
|
|
||||||
if (ipToNetworkList != null && !ipToNetworkList.isEmpty()) {
|
|
||||||
ipToNetworkMap = new LinkedHashMap<Long, IpAddresses>();
|
|
||||||
Collection ipsCollection = ipToNetworkList.values();
|
|
||||||
Iterator iter = ipsCollection.iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
HashMap<String, String> ips = (HashMap<String, String>)iter.next();
|
|
||||||
Long networkId = getNetworkIdFomIpMap(ips);
|
|
||||||
IpAddresses addrs = getIpAddressesFromIpMap(ips);
|
|
||||||
ipToNetworkMap.put(networkId, addrs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ipToNetworkMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private IpAddresses getIpAddressesFromIpMap(HashMap<String, String> ips) {
|
|
||||||
String requestedIp = ips.get("ip");
|
|
||||||
String requestedIpv6 = ips.get("ipv6");
|
|
||||||
String requestedMac = ips.get("mac");
|
|
||||||
if (requestedIpv6 != null) {
|
|
||||||
requestedIpv6 = NetUtils.standardizeIp6Address(requestedIpv6);
|
|
||||||
}
|
|
||||||
if (requestedMac != null) {
|
|
||||||
if(!NetUtils.isValidMac(requestedMac)) {
|
|
||||||
throw new InvalidParameterValueException("Mac address is not valid: " + requestedMac);
|
|
||||||
} else if(!NetUtils.isUnicastMac(requestedMac)) {
|
|
||||||
throw new InvalidParameterValueException("Mac address is not unicast: " + requestedMac);
|
|
||||||
}
|
|
||||||
requestedMac = NetUtils.standardizeMacAddress(requestedMac);
|
|
||||||
}
|
|
||||||
return new IpAddresses(requestedIp, requestedIpv6, requestedMac);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private Long getNetworkIdFomIpMap(HashMap<String, String> ips) {
|
|
||||||
Long networkId;
|
|
||||||
final String networkid = ips.get("networkid");
|
|
||||||
Network network = _networkService.getNetwork(networkid);
|
|
||||||
if (network != null) {
|
|
||||||
networkId = network.getId();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
networkId = Long.parseLong(networkid);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new InvalidParameterValueException("Unable to translate and find entity with networkId: " + networkid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return networkId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIpAddress() {
|
|
||||||
return ipAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIp6Address() {
|
|
||||||
if (ip6Address == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return NetUtils.standardizeIp6Address(ip6Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getMacAddress() {
|
|
||||||
if (macAddress == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(!NetUtils.isValidMac(macAddress)) {
|
|
||||||
throw new InvalidParameterValueException("Mac address is not valid: " + macAddress);
|
|
||||||
} else if(!NetUtils.isUnicastMac(macAddress)) {
|
|
||||||
throw new InvalidParameterValueException("Mac address is not unicast: " + macAddress);
|
|
||||||
}
|
|
||||||
return NetUtils.standardizeMacAddress(macAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Long> getAffinityGroupIdList() {
|
|
||||||
if (affinityGroupNameList != null && affinityGroupIdList != null) {
|
|
||||||
throw new InvalidParameterValueException("affinitygroupids parameter is mutually exclusive with affinitygroupnames parameter");
|
|
||||||
}
|
|
||||||
|
|
||||||
// transform group names to ids here
|
|
||||||
if (affinityGroupNameList != null) {
|
|
||||||
List<Long> affinityGroupIds = new ArrayList<Long>();
|
|
||||||
for (String groupName : affinityGroupNameList) {
|
|
||||||
Long groupId = _responseGenerator.getAffinityGroupId(groupName, getEntityOwnerId());
|
|
||||||
if (groupId == null) {
|
|
||||||
throw new InvalidParameterValueException("Unable to find affinity group by name " + groupName);
|
|
||||||
} else {
|
|
||||||
affinityGroupIds.add(groupId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affinityGroupIds;
|
|
||||||
} else {
|
|
||||||
return affinityGroupIdList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKeyboard() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return keyboard;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Map<Integer, String>> getDhcpOptionsMap() {
|
|
||||||
Map<String, Map<Integer, String>> dhcpOptionsMap = new HashMap<>();
|
|
||||||
if (dhcpOptionsNetworkList != null && !dhcpOptionsNetworkList.isEmpty()) {
|
|
||||||
|
|
||||||
Collection<Map<String, String>> paramsCollection = this.dhcpOptionsNetworkList.values();
|
|
||||||
for (Map<String, String> dhcpNetworkOptions : paramsCollection) {
|
|
||||||
String networkId = dhcpNetworkOptions.get(ApiConstants.NETWORK_ID);
|
|
||||||
|
|
||||||
if (networkId == null) {
|
|
||||||
throw new IllegalArgumentException("No networkid specified when providing extra dhcp options.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Integer, String> dhcpOptionsForNetwork = new HashMap<>();
|
|
||||||
dhcpOptionsMap.put(networkId, dhcpOptionsForNetwork);
|
|
||||||
|
|
||||||
for (String key : dhcpNetworkOptions.keySet()) {
|
|
||||||
if (key.startsWith(ApiConstants.DHCP_PREFIX)) {
|
|
||||||
int dhcpOptionValue = Integer.parseInt(key.replaceFirst(ApiConstants.DHCP_PREFIX, ""));
|
|
||||||
dhcpOptionsForNetwork.put(dhcpOptionValue, dhcpNetworkOptions.get(key));
|
|
||||||
} else if (!key.equals(ApiConstants.NETWORK_ID)) {
|
|
||||||
Dhcp.DhcpOptionCode dhcpOptionEnum = Dhcp.DhcpOptionCode.valueOfString(key);
|
|
||||||
dhcpOptionsForNetwork.put(dhcpOptionEnum.getCode(), dhcpNetworkOptions.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dhcpOptionsMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Long, DiskOffering> getDataDiskTemplateToDiskOfferingMap() {
|
|
||||||
if (diskOfferingId != null && dataDiskTemplateToDiskOfferingList != null) {
|
|
||||||
throw new InvalidParameterValueException("diskofferingid parameter can't be specified along with datadisktemplatetodiskofferinglist parameter");
|
|
||||||
}
|
|
||||||
if (MapUtils.isEmpty(dataDiskTemplateToDiskOfferingList)) {
|
|
||||||
return new HashMap<Long, DiskOffering>();
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap = new HashMap<Long, DiskOffering>();
|
|
||||||
for (Object objDataDiskTemplates : dataDiskTemplateToDiskOfferingList.values()) {
|
|
||||||
HashMap<String, String> dataDiskTemplates = (HashMap<String, String>) objDataDiskTemplates;
|
|
||||||
Long dataDiskTemplateId;
|
|
||||||
DiskOffering dataDiskOffering = null;
|
|
||||||
VirtualMachineTemplate dataDiskTemplate= _entityMgr.findByUuid(VirtualMachineTemplate.class, dataDiskTemplates.get("datadisktemplateid"));
|
|
||||||
if (dataDiskTemplate == null) {
|
|
||||||
dataDiskTemplate = _entityMgr.findById(VirtualMachineTemplate.class, dataDiskTemplates.get("datadisktemplateid"));
|
|
||||||
if (dataDiskTemplate == null)
|
|
||||||
throw new InvalidParameterValueException("Unable to translate and find entity with datadisktemplateid " + dataDiskTemplates.get("datadisktemplateid"));
|
|
||||||
}
|
|
||||||
dataDiskTemplateId = dataDiskTemplate.getId();
|
|
||||||
dataDiskOffering = _entityMgr.findByUuid(DiskOffering.class, dataDiskTemplates.get("diskofferingid"));
|
|
||||||
if (dataDiskOffering == null) {
|
|
||||||
dataDiskOffering = _entityMgr.findById(DiskOffering.class, dataDiskTemplates.get("diskofferingid"));
|
|
||||||
if (dataDiskOffering == null)
|
|
||||||
throw new InvalidParameterValueException("Unable to translate and find entity with diskofferingId " + dataDiskTemplates.get("diskofferingid"));
|
|
||||||
}
|
|
||||||
dataDiskTemplateToDiskOfferingMap.put(dataDiskTemplateId, dataDiskOffering);
|
|
||||||
}
|
|
||||||
return dataDiskTemplateToDiskOfferingMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExtraConfig() {
|
|
||||||
return extraConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getCopyImageTags() {
|
|
||||||
return copyImageTags == null ? false : copyImageTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getBootIntoSetup() {
|
|
||||||
return bootIntoSetup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDynamicScalingEnabled() {
|
|
||||||
return dynamicScalingEnabled == null ? true : dynamicScalingEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getOverrideDiskOfferingId() {
|
|
||||||
return overrideDiskOfferingId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApiConstants.IoDriverPolicy getIoDriverPolicy() {
|
|
||||||
if (StringUtils.isNotBlank(ioDriverPolicy)) {
|
|
||||||
try {
|
|
||||||
String policyType = ioDriverPolicy.trim().toUpperCase();
|
|
||||||
return ApiConstants.IoDriverPolicy.valueOf(policyType);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
String errMesg = String.format("Invalid io policy %s specified for vm %s. Valid values are: %s", ioDriverPolicy, getName(), Arrays.toString(ApiConstants.IoDriverPolicy.values()));
|
|
||||||
logger.warn(errMesg);
|
|
||||||
throw new InvalidParameterValueException(errMesg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getVolumeId() {
|
public Long getVolumeId() {
|
||||||
return volumeId;
|
return volumeId;
|
||||||
}
|
}
|
||||||
@ -782,57 +87,6 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
public boolean isVolumeOrSnapshotProvided() {
|
public boolean isVolumeOrSnapshotProvided() {
|
||||||
return volumeId != null || snapshotId != null;
|
return volumeId != null || snapshotId != null;
|
||||||
}
|
}
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
/////////////// API Implementation///////////////////
|
|
||||||
/////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCommandName() {
|
|
||||||
return s_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getResultObjectName() {
|
|
||||||
return "virtualmachine";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getEntityOwnerId() {
|
|
||||||
Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
|
|
||||||
if (accountId == null) {
|
|
||||||
return CallContext.current().getCallingAccount().getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
return accountId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getEventType() {
|
|
||||||
return EventTypes.EVENT_VM_CREATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCreateEventType() {
|
|
||||||
return EventTypes.EVENT_VM_CREATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCreateEventDescription() {
|
|
||||||
return "creating Vm";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getEventDescription() {
|
|
||||||
if(getStartVm()) {
|
|
||||||
return "starting Vm. Vm Id: " + getEntityUuid();
|
|
||||||
}
|
|
||||||
return "deploying Vm. Vm Id: " + getEntityUuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ApiCommandResourceType getApiResourceType() {
|
|
||||||
return ApiCommandResourceType.VirtualMachine;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
UserVm result;
|
UserVm result;
|
||||||
@ -875,7 +129,6 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create() throws ResourceAllocationException {
|
public void create() throws ResourceAllocationException {
|
||||||
if (Stream.of(templateId, snapshotId, volumeId).filter(Objects::nonNull).count() != 1) {
|
if (Stream.of(templateId, snapshotId, volumeId).filter(Objects::nonNull).count() != 1) {
|
||||||
|
|||||||
@ -41,6 +41,10 @@ public class BackupOfferingResponse extends BaseResponse {
|
|||||||
@Param(description = "description for the backup offering")
|
@Param(description = "description for the backup offering")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.PROVIDER)
|
||||||
|
@Param(description = "provider name", since = "4.21.0")
|
||||||
|
private String provider;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.EXTERNAL_ID)
|
@SerializedName(ApiConstants.EXTERNAL_ID)
|
||||||
@Param(description = "external ID on the provider side")
|
@Param(description = "external ID on the provider side")
|
||||||
private String externalId;
|
private String externalId;
|
||||||
@ -69,6 +73,10 @@ public class BackupOfferingResponse extends BaseResponse {
|
|||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProvider(String provider) {
|
||||||
|
this.provider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import com.cloud.serializer.Param;
|
|||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@EntityReference(value = Backup.class)
|
@EntityReference(value = Backup.class)
|
||||||
public class BackupResponse extends BaseResponse {
|
public class BackupResponse extends BaseResponse {
|
||||||
@ -34,6 +35,14 @@ public class BackupResponse extends BaseResponse {
|
|||||||
@Param(description = "ID of the VM backup")
|
@Param(description = "ID of the VM backup")
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.NAME)
|
||||||
|
@Param(description = "name of the backup", since = "4.21.0")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.DESCRIPTION)
|
||||||
|
@Param(description = "description for the backup", since = "4.21.0")
|
||||||
|
private String description;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
|
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
|
||||||
@Param(description = "ID of the VM")
|
@Param(description = "ID of the VM")
|
||||||
private String vmId;
|
private String vmId;
|
||||||
@ -102,6 +111,18 @@ public class BackupResponse extends BaseResponse {
|
|||||||
@Param(description = "zone name")
|
@Param(description = "zone name")
|
||||||
private String zone;
|
private String zone;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VM_DETAILS)
|
||||||
|
@Param(description = "Lists the vm specific details for the backup", since = "4.21.0")
|
||||||
|
private Map<String, String> vmDetails;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.INTERVAL_TYPE)
|
||||||
|
@Param(description = "Interval type of the backup", since = "4.21.0")
|
||||||
|
private String intervalType;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.BACKUP_VM_OFFERING_REMOVED)
|
||||||
|
@Param(description = "The backup offering corresponding to this backup was removed from the VM", since = "4.21.0")
|
||||||
|
private Boolean vmOfferingRemoved;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -110,6 +131,22 @@ public class BackupResponse extends BaseResponse {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
public String getVmId() {
|
public String getVmId() {
|
||||||
return vmId;
|
return vmId;
|
||||||
}
|
}
|
||||||
@ -245,4 +282,28 @@ public class BackupResponse extends BaseResponse {
|
|||||||
public void setZone(String zone) {
|
public void setZone(String zone) {
|
||||||
this.zone = zone;
|
this.zone = zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getVmDetails() {
|
||||||
|
return vmDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVmDetails(Map<String, String> vmDetails) {
|
||||||
|
this.vmDetails = vmDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIntervalType() {
|
||||||
|
return this.intervalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIntervalType(String intervalType) {
|
||||||
|
this.intervalType = intervalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getVmOfferingRemoved() {
|
||||||
|
return this.vmOfferingRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVmOfferingRemoved(Boolean vmOfferingRemoved) {
|
||||||
|
this.vmOfferingRemoved = vmOfferingRemoved;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,6 +60,10 @@ public class BackupScheduleResponse extends BaseResponse {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.QUIESCE_VM)
|
||||||
|
@Param(description = "quiesce the instance before checkpointing the disks for backup")
|
||||||
|
private Boolean quiesceVM;
|
||||||
|
|
||||||
public String getVmName() {
|
public String getVmName() {
|
||||||
return vmName;
|
return vmName;
|
||||||
}
|
}
|
||||||
@ -103,4 +107,8 @@ public class BackupScheduleResponse extends BaseResponse {
|
|||||||
public void setMaxBackups(Integer maxBackups) {
|
public void setMaxBackups(Integer maxBackups) {
|
||||||
this.maxBackups = maxBackups;
|
this.maxBackups = maxBackups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setQuiesceVM(Boolean quiesceVM) {
|
||||||
|
this.quiesceVM = quiesceVM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
package org.apache.cloudstack.api.response;
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
import com.cloud.serializer.Param;
|
import com.cloud.serializer.Param;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.storage.object.ObjectStore;
|
import org.apache.cloudstack.storage.object.ObjectStore;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import org.apache.cloudstack.api.BaseResponseWithAnnotations;
|
import org.apache.cloudstack.api.BaseResponseWithAnnotations;
|
||||||
@ -24,15 +26,15 @@ import org.apache.cloudstack.api.EntityReference;
|
|||||||
|
|
||||||
@EntityReference(value = ObjectStore.class)
|
@EntityReference(value = ObjectStore.class)
|
||||||
public class ObjectStoreResponse extends BaseResponseWithAnnotations {
|
public class ObjectStoreResponse extends BaseResponseWithAnnotations {
|
||||||
@SerializedName("id")
|
@SerializedName(ApiConstants.ID)
|
||||||
@Param(description = "the ID of the object store")
|
@Param(description = "the ID of the object store")
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@SerializedName("name")
|
@SerializedName(ApiConstants.NAME)
|
||||||
@Param(description = "the name of the object store")
|
@Param(description = "the name of the object store")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@SerializedName("url")
|
@SerializedName(ApiConstants.URL)
|
||||||
@Param(description = "the url of the object store")
|
@Param(description = "the url of the object store")
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
@ -44,6 +46,10 @@ public class ObjectStoreResponse extends BaseResponseWithAnnotations {
|
|||||||
@Param(description = "the total size of the object store")
|
@Param(description = "the total size of the object store")
|
||||||
private Long storageTotal;
|
private Long storageTotal;
|
||||||
|
|
||||||
|
@SerializedName("storageallocated")
|
||||||
|
@Param(description = "the allocated size of the object store")
|
||||||
|
private Long storageAllocated;
|
||||||
|
|
||||||
@SerializedName("storageused")
|
@SerializedName("storageused")
|
||||||
@Param(description = "the object store currently used size")
|
@Param(description = "the object store currently used size")
|
||||||
private Long storageUsed;
|
private Long storageUsed;
|
||||||
@ -96,6 +102,14 @@ public class ObjectStoreResponse extends BaseResponseWithAnnotations {
|
|||||||
this.storageTotal = storageTotal;
|
this.storageTotal = storageTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getStorageAllocated() {
|
||||||
|
return storageAllocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStorageAllocated(Long storageAllocated) {
|
||||||
|
this.storageAllocated = storageAllocated;
|
||||||
|
}
|
||||||
|
|
||||||
public Long getStorageUsed() {
|
public Long getStorageUsed() {
|
||||||
return storageUsed;
|
return storageUsed;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package org.apache.cloudstack.backup;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.cloudstack.acl.ControlledEntity;
|
import org.apache.cloudstack.acl.ControlledEntity;
|
||||||
import org.apache.cloudstack.api.Identity;
|
import org.apache.cloudstack.api.Identity;
|
||||||
@ -63,6 +64,8 @@ public interface Backup extends ControlledEntity, InternalIdentity, Identity {
|
|||||||
private String id;
|
private String id;
|
||||||
private Date created;
|
private Date created;
|
||||||
private String type;
|
private String type;
|
||||||
|
private Long backupSize = 0L;
|
||||||
|
private Long dataSize = 0L;
|
||||||
|
|
||||||
public RestorePoint(String id, Date created, String type) {
|
public RestorePoint(String id, Date created, String type) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@ -70,6 +73,12 @@ public interface Backup extends ControlledEntity, InternalIdentity, Identity {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RestorePoint(String id, Date created, String type, Long backupSize, Long dataSize) {
|
||||||
|
this(id, created, type);
|
||||||
|
this.backupSize = backupSize;
|
||||||
|
this.dataSize = dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -93,6 +102,22 @@ public interface Backup extends ControlledEntity, InternalIdentity, Identity {
|
|||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getBackupSize() {
|
||||||
|
return backupSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackupSize(Long backupSize) {
|
||||||
|
this.backupSize = backupSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDataSize() {
|
||||||
|
return dataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataSize(Long dataSize) {
|
||||||
|
this.dataSize = dataSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VolumeInfo {
|
class VolumeInfo {
|
||||||
@ -100,12 +125,20 @@ public interface Backup extends ControlledEntity, InternalIdentity, Identity {
|
|||||||
private Volume.Type type;
|
private Volume.Type type;
|
||||||
private Long size;
|
private Long size;
|
||||||
private String path;
|
private String path;
|
||||||
|
private Long deviceId;
|
||||||
|
private String diskOfferingId;
|
||||||
|
private Long minIops;
|
||||||
|
private Long maxIops;
|
||||||
|
|
||||||
public VolumeInfo(String uuid, String path, Volume.Type type, Long size) {
|
public VolumeInfo(String uuid, String path, Volume.Type type, Long size, Long deviceId, String diskOfferingId, Long minIops, Long maxIops) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.diskOfferingId = diskOfferingId;
|
||||||
|
this.minIops = minIops;
|
||||||
|
this.maxIops = maxIops;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUuid() {
|
public String getUuid() {
|
||||||
@ -128,13 +161,29 @@ public interface Backup extends ControlledEntity, InternalIdentity, Identity {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDiskOfferingId() {
|
||||||
|
return diskOfferingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMinIops() {
|
||||||
|
return minIops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMaxIops() {
|
||||||
|
return maxIops;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return StringUtils.join(":", uuid, path, type, size);
|
return StringUtils.join(":", uuid, path, type, size, deviceId, diskOfferingId, minIops, maxIops);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long getVmId();
|
Long getVmId();
|
||||||
long getBackupOfferingId();
|
long getBackupOfferingId();
|
||||||
String getExternalId();
|
String getExternalId();
|
||||||
String getType();
|
String getType();
|
||||||
@ -142,7 +191,12 @@ public interface Backup extends ControlledEntity, InternalIdentity, Identity {
|
|||||||
Backup.Status getStatus();
|
Backup.Status getStatus();
|
||||||
Long getSize();
|
Long getSize();
|
||||||
Long getProtectedSize();
|
Long getProtectedSize();
|
||||||
|
void setName(String name);
|
||||||
|
String getDescription();
|
||||||
|
void setDescription(String description);
|
||||||
List<VolumeInfo> getBackedUpVolumes();
|
List<VolumeInfo> getBackedUpVolumes();
|
||||||
long getZoneId();
|
long getZoneId();
|
||||||
|
Map<String, String> getDetails();
|
||||||
|
String getDetail(String name);
|
||||||
Long getBackupScheduleId();
|
Long getBackupScheduleId();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,20 +18,29 @@
|
|||||||
package org.apache.cloudstack.backup;
|
package org.apache.cloudstack.backup;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.cloud.capacity.Capacity;
|
||||||
import com.cloud.exception.ResourceAllocationException;
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd;
|
import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.backup.UpdateBackupOfferingCmd;
|
import org.apache.cloudstack.api.command.admin.backup.UpdateBackupOfferingCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.backup.CreateBackupCmd;
|
||||||
import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd;
|
import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd;
|
||||||
import org.apache.cloudstack.api.command.user.backup.DeleteBackupScheduleCmd;
|
import org.apache.cloudstack.api.command.user.backup.DeleteBackupScheduleCmd;
|
||||||
import org.apache.cloudstack.api.command.user.backup.ListBackupOfferingsCmd;
|
import org.apache.cloudstack.api.command.user.backup.ListBackupOfferingsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.backup.ListBackupsCmd;
|
import org.apache.cloudstack.api.command.user.backup.ListBackupsCmd;
|
||||||
|
import org.apache.cloudstack.api.response.BackupResponse;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.component.Manager;
|
import com.cloud.utils.component.Manager;
|
||||||
import com.cloud.utils.component.PluggableService;
|
import com.cloud.utils.component.PluggableService;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import com.cloud.vm.VmDiskInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backup and Recover Manager Interface
|
* Backup and Recover Manager Interface
|
||||||
@ -106,6 +115,14 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
|
|||||||
ConfigKey.Scope.Global,
|
ConfigKey.Scope.Global,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
|
ConfigKey<Float> BackupStorageCapacityThreshold = new ConfigKey<>("Alert", Float.class,
|
||||||
|
"zone.backupStorage.capacity.notificationthreshold",
|
||||||
|
"0.75",
|
||||||
|
"Percentage (as a value between 0 and 1) of backup storage utilization above which alerts will be sent about low storage available.",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Zone,
|
||||||
|
null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List backup provider offerings
|
* List backup provider offerings
|
||||||
* @param zoneId zone id
|
* @param zoneId zone id
|
||||||
@ -168,11 +185,11 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates backup of a VM
|
* Creates backup of a VM
|
||||||
* @param vmId Virtual Machine ID
|
* @param cmd CreateBackupCmd
|
||||||
* @param job The async job associated with the backup retention
|
* @param job The async job associated with the backup retention
|
||||||
* @return returns operation success
|
* @return returns operation success
|
||||||
*/
|
*/
|
||||||
boolean createBackup(final Long vmId, Object job) throws ResourceAllocationException;
|
boolean createBackup(CreateBackupCmd cmd, Object job) throws ResourceAllocationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List existing backups for a VM
|
* List existing backups for a VM
|
||||||
@ -184,6 +201,15 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
|
|||||||
*/
|
*/
|
||||||
boolean restoreBackup(final Long backupId);
|
boolean restoreBackup(final Long backupId);
|
||||||
|
|
||||||
|
Map<Long, Network.IpAddresses> getIpToNetworkMapFromBackup(Backup backup, boolean preserveIps, List<Long> networkIds);
|
||||||
|
|
||||||
|
Boolean canCreateInstanceFromBackup(Long backupId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore a backup to a new Instance
|
||||||
|
*/
|
||||||
|
boolean restoreBackupToVM(Long backupId, Long vmId) throws ResourceUnavailableException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore a backed up volume and attach it to a VM
|
* Restore a backed up volume and attach it to a VM
|
||||||
*/
|
*/
|
||||||
@ -197,5 +223,25 @@ public interface BackupManager extends BackupService, Configurable, PluggableSer
|
|||||||
*/
|
*/
|
||||||
boolean deleteBackup(final Long backupId, final Boolean forced);
|
boolean deleteBackup(final Long backupId, final Boolean forced);
|
||||||
|
|
||||||
|
void validateBackupForZone(Long zoneId);
|
||||||
|
|
||||||
BackupOffering updateBackupOffering(UpdateBackupOfferingCmd updateBackupOfferingCmd);
|
BackupOffering updateBackupOffering(UpdateBackupOfferingCmd updateBackupOfferingCmd);
|
||||||
|
|
||||||
|
VmDiskInfo getRootDiskInfoFromBackup(Backup backup);
|
||||||
|
|
||||||
|
List<VmDiskInfo> getDataDiskInfoListFromBackup(Backup backup);
|
||||||
|
|
||||||
|
void checkVmDisksSizeAgainstBackup(List<VmDiskInfo> vmDiskInfoList, Backup backup);
|
||||||
|
|
||||||
|
Map<String, String> getBackupDetailsFromVM(VirtualMachine vm);
|
||||||
|
|
||||||
|
String createVolumeInfoFromVolumes(List<Volume> vmVolumes);
|
||||||
|
|
||||||
|
String getBackupNameFromVM(VirtualMachine vm);
|
||||||
|
|
||||||
|
BackupResponse createBackupResponse(Backup backup, Boolean listVmDetails);
|
||||||
|
|
||||||
|
Capacity getBackupStorageUsedStats(Long zoneId);
|
||||||
|
|
||||||
|
void checkAndRemoveBackupOfferingBeforeExpunge(VirtualMachine vm);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
package org.apache.cloudstack.backup;
|
package org.apache.cloudstack.backup;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
@ -71,10 +70,12 @@ public interface BackupProvider {
|
|||||||
/**
|
/**
|
||||||
* Starts and creates an adhoc backup process
|
* Starts and creates an adhoc backup process
|
||||||
* for a previously registered VM backup
|
* for a previously registered VM backup
|
||||||
* @param vm the machine to make a backup of
|
*
|
||||||
|
* @param vm the machine to make a backup of
|
||||||
|
* @param quiesceVM instance will be quiesced for checkpointing for backup. Applicable only to NAS plugin.
|
||||||
* @return the result and {code}Backup{code} {code}Object{code}
|
* @return the result and {code}Backup{code} {code}Object{code}
|
||||||
*/
|
*/
|
||||||
Pair<Boolean, Backup> takeBackup(VirtualMachine vm);
|
Pair<Boolean, Backup> takeBackup(VirtualMachine vm, Boolean quiesceVM);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete an existing backup
|
* Delete an existing backup
|
||||||
@ -84,6 +85,8 @@ public interface BackupProvider {
|
|||||||
*/
|
*/
|
||||||
boolean deleteBackup(Backup backup, boolean forced);
|
boolean deleteBackup(Backup backup, boolean forced);
|
||||||
|
|
||||||
|
boolean restoreBackupToVM(VirtualMachine vm, Backup backup, String hostIp, String dataStoreUuid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore VM from backup
|
* Restore VM from backup
|
||||||
*/
|
*/
|
||||||
@ -92,27 +95,44 @@ public interface BackupProvider {
|
|||||||
/**
|
/**
|
||||||
* Restore a volume from a backup
|
* Restore a volume from a backup
|
||||||
*/
|
*/
|
||||||
Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState);
|
Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns backup metrics for a list of VMs in a zone
|
* Syncs backup metrics (backup size, protected size) from the plugin and stores it within the provider
|
||||||
* @param zoneId the zone for which to return metrics
|
* @param zoneId the zone for which to return metrics
|
||||||
* @param vms a list of machines to get measurements for
|
|
||||||
* @return a map of machine -> backup metrics
|
|
||||||
*/
|
*/
|
||||||
Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<VirtualMachine> vms);
|
void syncBackupMetrics(Long zoneId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method should TODO
|
* Returns a list of Backup.RestorePoint
|
||||||
* @param vm the machine to get restore point for
|
* @param vm the machine to get the restore points for
|
||||||
*/
|
*/
|
||||||
List<Backup.RestorePoint> listRestorePoints(VirtualMachine vm);
|
List<Backup.RestorePoint> listRestorePoints(VirtualMachine vm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method should TODO
|
* Creates and returns an entry in the backups table by getting the information from restorePoint and vm.
|
||||||
|
*
|
||||||
* @param restorePoint the restore point to create a backup for
|
* @param restorePoint the restore point to create a backup for
|
||||||
* @param vm The machine for which to create a backup
|
* @param vm The machine for which to create a backup
|
||||||
* @param metric the metric object to update with the new backup data
|
|
||||||
*/
|
*/
|
||||||
Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm, Backup.Metric metric);
|
Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the backup provider supports creating new instance from backup
|
||||||
|
*/
|
||||||
|
boolean supportsInstanceFromBackup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the backup storage usage (Used, Total) for a backup provider
|
||||||
|
* @param zoneId the zone for which to return metrics
|
||||||
|
* @return a pair of Used size and Total size for the backup storage
|
||||||
|
*/
|
||||||
|
Pair<Long, Long> getBackupStorageStats(Long zoneId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the backup storage usage (Used, Total) from the plugin and stores it in db
|
||||||
|
* @param zoneId the zone for which to return metrics
|
||||||
|
*/
|
||||||
|
void syncBackupStorageStats(Long zoneId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,9 @@ public interface BackupRepository extends InternalIdentity, Identity {
|
|||||||
String getType();
|
String getType();
|
||||||
String getAddress();
|
String getAddress();
|
||||||
String getMountOptions();
|
String getMountOptions();
|
||||||
|
void setUsedBytes(Long usedBytes);
|
||||||
Long getCapacityBytes();
|
Long getCapacityBytes();
|
||||||
Long getUsedBytes();
|
Long getUsedBytes();
|
||||||
|
void setCapacityBytes(Long capacityBytes);
|
||||||
Date getCreated();
|
Date getCreated();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ public interface BackupSchedule extends InternalIdentity {
|
|||||||
String getTimezone();
|
String getTimezone();
|
||||||
Date getScheduledTimestamp();
|
Date getScheduledTimestamp();
|
||||||
Long getAsyncJobId();
|
Long getAsyncJobId();
|
||||||
|
Boolean getQuiesceVM();
|
||||||
int getMaxBackups();
|
int getMaxBackups();
|
||||||
String getUuid();
|
String getUuid();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,8 @@ public class AddObjectStoragePoolCmdTest {
|
|||||||
|
|
||||||
String provider = "Simulator";
|
String provider = "Simulator";
|
||||||
|
|
||||||
|
Long size = 10L;
|
||||||
|
|
||||||
Map<String, String> details;
|
Map<String, String> details;
|
||||||
|
|
||||||
private AutoCloseable closeable;
|
private AutoCloseable closeable;
|
||||||
@ -74,6 +76,7 @@ public class AddObjectStoragePoolCmdTest {
|
|||||||
ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "url", url);
|
ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "url", url);
|
||||||
ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "providerName", provider);
|
ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "providerName", provider);
|
||||||
ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "details", details);
|
ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "details", details);
|
||||||
|
ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "size", size);
|
||||||
addObjectStoragePoolCmdSpy._storageService = storageService;
|
addObjectStoragePoolCmdSpy._storageService = storageService;
|
||||||
addObjectStoragePoolCmdSpy._responseGenerator = responseGenerator;
|
addObjectStoragePoolCmdSpy._responseGenerator = responseGenerator;
|
||||||
}
|
}
|
||||||
@ -87,12 +90,12 @@ public class AddObjectStoragePoolCmdTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testAddObjectStore() throws DiscoveryException {
|
public void testAddObjectStore() throws DiscoveryException {
|
||||||
Mockito.doReturn(objectStore).when(storageService).discoverObjectStore(Mockito.anyString(),
|
Mockito.doReturn(objectStore).when(storageService).discoverObjectStore(Mockito.anyString(),
|
||||||
Mockito.anyString(), Mockito.anyString(), any());
|
Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), any());
|
||||||
ObjectStoreResponse objectStoreResponse = new ObjectStoreResponse();
|
ObjectStoreResponse objectStoreResponse = new ObjectStoreResponse();
|
||||||
Mockito.doReturn(objectStoreResponse).when(responseGenerator).createObjectStoreResponse(any());
|
Mockito.doReturn(objectStoreResponse).when(responseGenerator).createObjectStoreResponse(any());
|
||||||
addObjectStoragePoolCmdSpy.execute();
|
addObjectStoragePoolCmdSpy.execute();
|
||||||
|
|
||||||
Mockito.verify(storageService, Mockito.times(1))
|
Mockito.verify(storageService, Mockito.times(1))
|
||||||
.discoverObjectStore(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
|
.discoverObjectStore(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,483 @@
|
|||||||
|
// 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.vm;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants.BootMode;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants.BootType;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants.IoDriverPolicy;
|
||||||
|
import org.apache.cloudstack.vm.lease.VMLeaseManager;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import com.cloud.network.NetworkService;
|
||||||
|
import com.cloud.utils.db.EntityManager;
|
||||||
|
import com.cloud.vm.VmDetailConstants;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import com.cloud.offering.DiskOffering;
|
||||||
|
import com.cloud.network.Network.IpAddresses;
|
||||||
|
import com.cloud.vm.VmDiskInfo;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class DeployVMCmdTest {
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private DeployVMCmd cmd = new DeployVMCmd();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBootType_ValidUEFI() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", "UEFI");
|
||||||
|
|
||||||
|
BootType result = cmd.getBootType();
|
||||||
|
|
||||||
|
assertEquals(BootType.UEFI, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBootTypeValidBIOS() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", "BIOS");
|
||||||
|
|
||||||
|
BootType result = cmd.getBootType();
|
||||||
|
|
||||||
|
assertEquals(BootType.BIOS, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBootTypeInvalidValue() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", "INVALID");
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getBootType();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("Invalid bootType INVALID"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBootTypeNullValue() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", null);
|
||||||
|
|
||||||
|
BootType result = cmd.getBootType();
|
||||||
|
|
||||||
|
assertNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBootModeValidSecure() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootMode", "SECURE");
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", "UEFI");
|
||||||
|
|
||||||
|
BootMode result = cmd.getBootMode();
|
||||||
|
|
||||||
|
assertEquals(BootMode.SECURE, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBootModeValidLegacy() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootMode", "LEGACY");
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", "UEFI");
|
||||||
|
|
||||||
|
BootMode result = cmd.getBootMode();
|
||||||
|
|
||||||
|
assertEquals(BootMode.LEGACY, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBootModeInvalidValue() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootMode", "INVALID");
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", "UEFI");
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getBootMode();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("Invalid bootmode: INVALID specified for VM: null. Valid values are: [LEGACY, SECURE]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBootModeUEFIWithoutBootMode() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootMode", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", "UEFI");
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getBootMode();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("bootmode must be specified for the VM with boot type: UEFI. Valid values are: [LEGACY, SECURE]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDetails() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootType", "UEFI");
|
||||||
|
ReflectionTestUtils.setField(cmd, "bootMode", "SECURE");
|
||||||
|
ReflectionTestUtils.setField(cmd, "rootdisksize", 100L);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ioDriverPolicy", "native");
|
||||||
|
ReflectionTestUtils.setField(cmd, "iothreadsEnabled", true);
|
||||||
|
ReflectionTestUtils.setField(cmd, "nicMultiqueueNumber", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "nicPackedVirtQueues", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "details", new HashMap<>());
|
||||||
|
|
||||||
|
Map<String, String> result = cmd.getDetails();
|
||||||
|
|
||||||
|
assertEquals("SECURE", result.get("UEFI"));
|
||||||
|
assertEquals("100", result.get(VmDetailConstants.ROOT_DISK_SIZE));
|
||||||
|
assertEquals("native", result.get(VmDetailConstants.IO_POLICY));
|
||||||
|
assertEquals("true", result.get(VmDetailConstants.IOTHREADS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetLeaseExpiryActionValidStop() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "leaseExpiryAction", "STOP");
|
||||||
|
|
||||||
|
VMLeaseManager.ExpiryAction result = cmd.getLeaseExpiryAction();
|
||||||
|
|
||||||
|
assertEquals(VMLeaseManager.ExpiryAction.STOP, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetLeaseExpiryActionValidDestroy() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "leaseExpiryAction", "DESTROY");
|
||||||
|
|
||||||
|
VMLeaseManager.ExpiryAction result = cmd.getLeaseExpiryAction();
|
||||||
|
|
||||||
|
assertEquals(VMLeaseManager.ExpiryAction.DESTROY, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetLeaseExpiryActionInvalidValue() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "leaseExpiryAction", "INVALID");
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getLeaseExpiryAction();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("Invalid value configured for leaseexpiryaction"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetLeaseExpiryActionNullValue() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "leaseExpiryAction", null);
|
||||||
|
|
||||||
|
VMLeaseManager.ExpiryAction result = cmd.getLeaseExpiryAction();
|
||||||
|
|
||||||
|
assertNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIoDriverPolicyValidThrottle() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "ioDriverPolicy", "native");
|
||||||
|
|
||||||
|
IoDriverPolicy result = cmd.getIoDriverPolicy();
|
||||||
|
|
||||||
|
assertEquals(IoDriverPolicy.valueOf("NATIVE"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIoDriverPolicyInvalidValue() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "ioDriverPolicy", "INVALID");
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getIoDriverPolicy();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("Invalid io policy INVALID"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNetworkIds() {
|
||||||
|
List<Long> networkIds = Arrays.asList(1L, 2L, 3L);
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", networkIds);
|
||||||
|
ReflectionTestUtils.setField(cmd, "vAppNetworks", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", null);
|
||||||
|
|
||||||
|
List<Long> result = cmd.getNetworkIds();
|
||||||
|
|
||||||
|
assertEquals(networkIds, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNetworkIdsVAppNetworks() {
|
||||||
|
Map<String, Object> vAppNetworks = new HashMap<>();
|
||||||
|
vAppNetworks.put("network1", new HashMap<String, String>());
|
||||||
|
ReflectionTestUtils.setField(cmd, "vAppNetworks", vAppNetworks);
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipAddress", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ip6Address", null);
|
||||||
|
|
||||||
|
List<Long> result = cmd.getNetworkIds();
|
||||||
|
|
||||||
|
assertTrue(result.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNetworkIdsVAppNetworksAndNetworkIds() {
|
||||||
|
Map<String, Object> vAppNetworks = new HashMap<>();
|
||||||
|
vAppNetworks.put("network1", new HashMap<String, String>());
|
||||||
|
ReflectionTestUtils.setField(cmd, "vAppNetworks", vAppNetworks);
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", Arrays.asList(1L, 2L));
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getNetworkIds();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("nicnetworklist can't be specified along with networkids"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNetworkIdsIpToNetworkListAndNetworkIds() {
|
||||||
|
Map<String, Object> ipToNetworkList = new HashMap<>();
|
||||||
|
ipToNetworkList.put("0", new HashMap<String, String>());
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", ipToNetworkList);
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", Arrays.asList(1L, 2L));
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getNetworkIds();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("ipToNetworkMap can't be specified along with networkIds or ipAddress"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIpToNetworkMap_WithNetworkIds() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", Arrays.asList(1L, 2L));
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", new HashMap<>());
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getIpToNetworkMap();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIpToNetworkMap_WithIpAddress() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipAddress", "192.168.1.1");
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", new HashMap<>());
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getIpToNetworkMap();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("NetworkIds and ipAddress can't be specified along with ipToNetworkMap parameter"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIpToNetworkMap_WithEmptyIpToNetworkList() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipAddress", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", new HashMap<>());
|
||||||
|
|
||||||
|
Map<Long, IpAddresses> result = cmd.getIpToNetworkMap();
|
||||||
|
|
||||||
|
assertNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIpToNetworkMap_WithNullIpToNetworkList() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipAddress", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", null);
|
||||||
|
|
||||||
|
Map<Long, IpAddresses> result = cmd.getIpToNetworkMap();
|
||||||
|
|
||||||
|
assertNull(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDataDiskInfoList() {
|
||||||
|
Map<String, Object> dataDisksDetails = new HashMap<>();
|
||||||
|
Map<String, String> dataDisk = new HashMap<>();
|
||||||
|
dataDisk.put(ApiConstants.DISK_OFFERING_ID, "offering-uuid");
|
||||||
|
dataDisk.put(ApiConstants.DEVICE_ID, "0");
|
||||||
|
dataDisk.put(ApiConstants.MIN_IOPS, "1000");
|
||||||
|
dataDisk.put(ApiConstants.MAX_IOPS, "2000");
|
||||||
|
dataDisksDetails.put("0", dataDisk);
|
||||||
|
|
||||||
|
ReflectionTestUtils.setField(cmd, "dataDisksDetails", dataDisksDetails);
|
||||||
|
|
||||||
|
EntityManager entityMgr = mock(EntityManager.class);
|
||||||
|
ReflectionTestUtils.setField(cmd, "_entityMgr", entityMgr);
|
||||||
|
DiskOffering diskOffering = mock(DiskOffering.class);
|
||||||
|
when(diskOffering.getDiskSize()).thenReturn(1024 * 1024 * 1024L);
|
||||||
|
when(diskOffering.isCustomizedIops()).thenReturn(true);
|
||||||
|
when(entityMgr.findByUuid(DiskOffering.class, "offering-uuid")).thenReturn(diskOffering);
|
||||||
|
|
||||||
|
List<VmDiskInfo> result = cmd.getDataDiskInfoList();
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(1, result.size());
|
||||||
|
assertEquals(diskOffering, result.get(0).getDiskOffering());
|
||||||
|
assertEquals(1L, result.get(0).getSize().longValue());
|
||||||
|
assertEquals(1000L, result.get(0).getMinIops().longValue());
|
||||||
|
assertEquals(2000L, result.get(0).getMaxIops().longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIpAddressesFromIpMap() {
|
||||||
|
Map<String, Object> ipToNetworkList = new HashMap<>();
|
||||||
|
Map<String, String> ipMap = new HashMap<>();
|
||||||
|
ipMap.put("ip", "192.168.1.100");
|
||||||
|
ipMap.put("mac", "00:11:22:33:44:55");
|
||||||
|
ipMap.put("networkid", "1");
|
||||||
|
ipToNetworkList.put("0", ipMap);
|
||||||
|
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", ipToNetworkList);
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipAddress", null);
|
||||||
|
|
||||||
|
Network mockNetwork = mock(Network.class);
|
||||||
|
NetworkService networkServiceMock = mock(NetworkService.class);
|
||||||
|
ReflectionTestUtils.setField(cmd, "_networkService", networkServiceMock);
|
||||||
|
|
||||||
|
Map<Long, IpAddresses> result = cmd.getIpToNetworkMap();
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertTrue(result.containsKey(1L));
|
||||||
|
assertEquals(result.get(1L).getIp4Address(), "192.168.1.100");
|
||||||
|
assertEquals(result.get(1L).getMacAddress(), "00:11:22:33:44:55");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIpAddressesFromIpMapInvalidMac() {
|
||||||
|
Map<String, Object> ipToNetworkList = new HashMap<>();
|
||||||
|
Map<String, String> ipMap = new HashMap<>();
|
||||||
|
ipMap.put("ip", "192.168.1.100");
|
||||||
|
ipMap.put("mac", "invalid-mac");
|
||||||
|
ipMap.put("networkid", "1");
|
||||||
|
ipToNetworkList.put("0", ipMap);
|
||||||
|
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipToNetworkList", ipToNetworkList);
|
||||||
|
ReflectionTestUtils.setField(cmd, "networkIds", null);
|
||||||
|
ReflectionTestUtils.setField(cmd, "ipAddress", null);
|
||||||
|
|
||||||
|
Network mockNetwork = mock(Network.class);
|
||||||
|
NetworkService networkServiceMock = mock(NetworkService.class);
|
||||||
|
ReflectionTestUtils.setField(cmd, "_networkService", networkServiceMock);
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getIpToNetworkMap();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("Mac address is not valid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDhcpOptionsMap() {
|
||||||
|
Map<String, Object> dhcpOptionsNetworkList = new HashMap<>();
|
||||||
|
Map<String, String> dhcpOptions = new HashMap<>();
|
||||||
|
dhcpOptions.put("networkid", "network-1");
|
||||||
|
dhcpOptions.put("dhcp:114", "url-value");
|
||||||
|
dhcpOptions.put("dhcp:66", "www.test.com");
|
||||||
|
dhcpOptionsNetworkList.put("0", dhcpOptions);
|
||||||
|
|
||||||
|
ReflectionTestUtils.setField(cmd, "dhcpOptionsNetworkList", dhcpOptionsNetworkList);
|
||||||
|
|
||||||
|
Map<String, Map<Integer, String>> result = cmd.getDhcpOptionsMap();
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertTrue(result.containsKey("network-1"));
|
||||||
|
Map<Integer, String> networkOptions = result.get("network-1");
|
||||||
|
assertEquals("url-value", networkOptions.get(114));
|
||||||
|
assertEquals("www.test.com", networkOptions.get(66));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDhcpOptionsMap_WithMissingNetworkId() {
|
||||||
|
Map<String, Object> dhcpOptionsNetworkList = new HashMap<>();
|
||||||
|
Map<String, String> dhcpOptions = new HashMap<>();
|
||||||
|
dhcpOptions.put("dhcp:114", "url-value");
|
||||||
|
dhcpOptionsNetworkList.put("0", dhcpOptions);
|
||||||
|
|
||||||
|
ReflectionTestUtils.setField(cmd, "dhcpOptionsNetworkList", dhcpOptionsNetworkList);
|
||||||
|
|
||||||
|
IllegalArgumentException thrownException = assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
cmd.getDhcpOptionsMap();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("No networkid specified when providing extra dhcp options"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDataDiskTemplateToDiskOfferingMap() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "diskOfferingId", null);
|
||||||
|
|
||||||
|
Map<String, Object> dataDiskTemplateToDiskOfferingList = new HashMap<>();
|
||||||
|
Map<String, String> dataDiskTemplate = new HashMap<>();
|
||||||
|
dataDiskTemplate.put("datadisktemplateid", "template-uuid");
|
||||||
|
dataDiskTemplate.put("diskofferingid", "offering-uuid");
|
||||||
|
dataDiskTemplateToDiskOfferingList.put("0", dataDiskTemplate);
|
||||||
|
|
||||||
|
ReflectionTestUtils.setField(cmd, "dataDiskTemplateToDiskOfferingList", dataDiskTemplateToDiskOfferingList);
|
||||||
|
|
||||||
|
VirtualMachineTemplate mockTemplate = mock(VirtualMachineTemplate.class);
|
||||||
|
when(mockTemplate.getId()).thenReturn(1L);
|
||||||
|
|
||||||
|
DiskOffering mockOffering = mock(DiskOffering.class);
|
||||||
|
|
||||||
|
EntityManager entityMgr = mock(EntityManager.class);
|
||||||
|
ReflectionTestUtils.setField(cmd, "_entityMgr", entityMgr);
|
||||||
|
when(entityMgr.findByUuid(VirtualMachineTemplate.class, "template-uuid")).thenReturn(mockTemplate);
|
||||||
|
when(entityMgr.findByUuid(DiskOffering.class, "offering-uuid")).thenReturn(mockOffering);
|
||||||
|
|
||||||
|
Map<Long, DiskOffering> result = cmd.getDataDiskTemplateToDiskOfferingMap();
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(mockOffering, result.get(1L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDataDiskTemplateToDiskOfferingMapWithDiskOfferingId() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "diskOfferingId", 1L);
|
||||||
|
ReflectionTestUtils.setField(cmd, "dataDiskTemplateToDiskOfferingList", new HashMap<>());
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getDataDiskTemplateToDiskOfferingMap();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("diskofferingid parameter can't be specified along with datadisktemplatetodiskofferinglist parameter"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetDataDiskTemplateToDiskOfferingMapInvalidTemplateId() {
|
||||||
|
ReflectionTestUtils.setField(cmd, "diskOfferingId", null);
|
||||||
|
|
||||||
|
Map<String, Object> dataDiskTemplateToDiskOfferingList = new HashMap<>();
|
||||||
|
Map<String, String> dataDiskTemplate = new HashMap<>();
|
||||||
|
dataDiskTemplate.put("datadisktemplateid", "invalid-template");
|
||||||
|
dataDiskTemplate.put("diskofferingid", "offering-uuid");
|
||||||
|
dataDiskTemplateToDiskOfferingList.put("0", dataDiskTemplate);
|
||||||
|
|
||||||
|
ReflectionTestUtils.setField(cmd, "dataDiskTemplateToDiskOfferingList", dataDiskTemplateToDiskOfferingList);
|
||||||
|
|
||||||
|
EntityManager entityMgr = mock(EntityManager.class);
|
||||||
|
ReflectionTestUtils.setField(cmd, "_entityMgr", entityMgr);
|
||||||
|
when(entityMgr.findByUuid(VirtualMachineTemplate.class, "invalid-template")).thenReturn(null);
|
||||||
|
when(entityMgr.findById(VirtualMachineTemplate.class, "invalid-template")).thenReturn(null);
|
||||||
|
|
||||||
|
InvalidParameterValueException thrownException = assertThrows(InvalidParameterValueException.class, () -> {
|
||||||
|
cmd.getDataDiskTemplateToDiskOfferingMap();
|
||||||
|
});
|
||||||
|
assertTrue(thrownException.getMessage().contains("Unable to translate and find entity with datadisktemplateid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -28,6 +28,7 @@ public class BackupAnswer extends Answer {
|
|||||||
private Long size;
|
private Long size;
|
||||||
private Long virtualSize;
|
private Long virtualSize;
|
||||||
private Map<String, String> volumes;
|
private Map<String, String> volumes;
|
||||||
|
Boolean needsCleanup;
|
||||||
|
|
||||||
public BackupAnswer(final Command command, final boolean success, final String details) {
|
public BackupAnswer(final Command command, final boolean success, final String details) {
|
||||||
super(command, success, details);
|
super(command, success, details);
|
||||||
@ -56,4 +57,15 @@ public class BackupAnswer extends Answer {
|
|||||||
public void setVolumes(Map<String, String> volumes) {
|
public void setVolumes(Map<String, String> volumes) {
|
||||||
this.volumes = volumes;
|
this.volumes = volumes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getNeedsCleanup() {
|
||||||
|
if (needsCleanup == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return needsCleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNeedsCleanup(Boolean needsCleanup) {
|
||||||
|
this.needsCleanup = needsCleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 org.apache.cloudstack.backup;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.Command;
|
||||||
|
|
||||||
|
public class BackupStorageStatsAnswer extends Answer {
|
||||||
|
private Long totalSize;
|
||||||
|
private Long usedSize;
|
||||||
|
|
||||||
|
public BackupStorageStatsAnswer(final Command command, final boolean success, final String details) {
|
||||||
|
super(command, success, details);
|
||||||
|
this.totalSize = 0L;
|
||||||
|
this.usedSize = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTotalSize() {
|
||||||
|
return totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalSize(Long totalSize) {
|
||||||
|
this.totalSize = totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getUsedSize() {
|
||||||
|
return usedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsedSize(Long usedSize) {
|
||||||
|
this.usedSize = usedSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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.agent.api.LogLevel;
|
||||||
|
|
||||||
|
public class GetBackupStorageStatsCommand extends Command {
|
||||||
|
private String backupRepoType;
|
||||||
|
private String backupRepoAddress;
|
||||||
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
|
private String mountOptions;
|
||||||
|
|
||||||
|
public GetBackupStorageStatsCommand(String backupRepoType, String backupRepoAddress, String mountOptions) {
|
||||||
|
super();
|
||||||
|
this.backupRepoType = backupRepoType;
|
||||||
|
this.backupRepoAddress = backupRepoAddress;
|
||||||
|
this.mountOptions = mountOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBackupRepoType() {
|
||||||
|
return backupRepoType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackupRepoType(String backupRepoType) {
|
||||||
|
this.backupRepoType = backupRepoType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBackupRepoAddress() {
|
||||||
|
return backupRepoAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackupRepoAddress(String backupRepoAddress) {
|
||||||
|
this.backupRepoAddress = backupRepoAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMountOptions() {
|
||||||
|
return mountOptions == null ? "" : mountOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMountOptions(String mountOptions) {
|
||||||
|
this.mountOptions = mountOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean executeInSequence() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -30,7 +30,8 @@ public class RestoreBackupCommand extends Command {
|
|||||||
private String backupPath;
|
private String backupPath;
|
||||||
private String backupRepoType;
|
private String backupRepoType;
|
||||||
private String backupRepoAddress;
|
private String backupRepoAddress;
|
||||||
private List<String> volumePaths;
|
private List<String> backupVolumesUUIDs;
|
||||||
|
private List<String> restoreVolumePaths;
|
||||||
private String diskType;
|
private String diskType;
|
||||||
private Boolean vmExists;
|
private Boolean vmExists;
|
||||||
private String restoreVolumeUUID;
|
private String restoreVolumeUUID;
|
||||||
@ -72,12 +73,12 @@ public class RestoreBackupCommand extends Command {
|
|||||||
this.backupRepoAddress = backupRepoAddress;
|
this.backupRepoAddress = backupRepoAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getVolumePaths() {
|
public List<String> getRestoreVolumePaths() {
|
||||||
return volumePaths;
|
return restoreVolumePaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVolumePaths(List<String> volumePaths) {
|
public void setRestoreVolumePaths(List<String> restoreVolumePaths) {
|
||||||
this.volumePaths = volumePaths;
|
this.restoreVolumePaths = restoreVolumePaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isVmExists() {
|
public Boolean isVmExists() {
|
||||||
@ -127,4 +128,12 @@ public class RestoreBackupCommand extends Command {
|
|||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getBackupVolumesUUIDs() {
|
||||||
|
return backupVolumesUUIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackupVolumesUUIDs(List<String> backupVolumesUUIDs) {
|
||||||
|
this.backupVolumesUUIDs = backupVolumesUUIDs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ public class TakeBackupCommand extends Command {
|
|||||||
private String backupRepoType;
|
private String backupRepoType;
|
||||||
private String backupRepoAddress;
|
private String backupRepoAddress;
|
||||||
private List<String> volumePaths;
|
private List<String> volumePaths;
|
||||||
|
private Boolean quiesce;
|
||||||
@LogLevel(LogLevel.Log4jLevel.Off)
|
@LogLevel(LogLevel.Log4jLevel.Off)
|
||||||
private String mountOptions;
|
private String mountOptions;
|
||||||
|
|
||||||
@ -87,6 +88,14 @@ public class TakeBackupCommand extends Command {
|
|||||||
this.volumePaths = volumePaths;
|
this.volumePaths = volumePaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getQuiesce() {
|
||||||
|
return quiesce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuiesce(Boolean quiesce) {
|
||||||
|
this.quiesce = quiesce;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeInSequence() {
|
public boolean executeInSequence() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -124,6 +124,7 @@ public interface VirtualMachineManager extends Manager {
|
|||||||
* @param defaultNetwork The default network for the VM.
|
* @param defaultNetwork The default network for the VM.
|
||||||
* @param rootDiskOffering For created VMs not based on templates, root disk offering specifies the root disk.
|
* @param rootDiskOffering For created VMs not based on templates, root disk offering specifies the root disk.
|
||||||
* @param dataDiskOfferings Data disks to attach to the VM.
|
* @param dataDiskOfferings Data disks to attach to the VM.
|
||||||
|
* @param dataDiskDeviceIds Device Ids to assign the data disks to.
|
||||||
* @param auxiliaryNetworks additional networks to attach the VMs to.
|
* @param auxiliaryNetworks additional networks to attach the VMs to.
|
||||||
* @param plan How to deploy the VM.
|
* @param plan How to deploy the VM.
|
||||||
* @param hyperType Hypervisor type
|
* @param hyperType Hypervisor type
|
||||||
@ -131,7 +132,7 @@ public interface VirtualMachineManager extends Manager {
|
|||||||
* @throws InsufficientCapacityException If there are insufficient capacity to deploy this vm.
|
* @throws InsufficientCapacityException If there are insufficient capacity to deploy this vm.
|
||||||
*/
|
*/
|
||||||
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, DiskOfferingInfo rootDiskOfferingInfo,
|
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering, DiskOfferingInfo rootDiskOfferingInfo,
|
||||||
List<DiskOfferingInfo> dataDiskOfferings, LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan,
|
List<DiskOfferingInfo> dataDiskOfferings, List<Long> dataDiskDeviceIds, LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, DeploymentPlan plan,
|
||||||
HypervisorType hyperType, Map<String, Map<Integer, String>> extraDhcpOptions, Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
|
HypervisorType hyperType, Map<String, Map<Integer, String>> extraDhcpOptions, Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
|
||||||
|
|
||||||
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering,
|
void allocate(String vmInstanceName, VirtualMachineTemplate template, ServiceOffering serviceOffering,
|
||||||
|
|||||||
@ -40,6 +40,7 @@ import com.cloud.exception.InsufficientCapacityException;
|
|||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.offering.DiskOffering;
|
import com.cloud.offering.DiskOffering;
|
||||||
import com.cloud.vm.NicProfile;
|
import com.cloud.vm.NicProfile;
|
||||||
|
import com.cloud.vm.VmDiskInfo;
|
||||||
|
|
||||||
@Path("orchestration")
|
@Path("orchestration")
|
||||||
@Produces({"application/json", "application/xml"})
|
@Produces({"application/json", "application/xml"})
|
||||||
@ -69,15 +70,17 @@ public interface OrchestrationService {
|
|||||||
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
|
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
|
||||||
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
|
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
|
||||||
@QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap,
|
@QueryParam("root-disk-size") Long rootDiskSize, @QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap,
|
||||||
@QueryParam("datadisktemplate-diskoffering-map") Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, @QueryParam("disk-offering-id") Long diskOfferingId, @QueryParam("root-disk-offering-id") Long rootDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
|
@QueryParam("datadisktemplate-diskoffering-map") Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, @QueryParam("disk-offering-id") Long diskOfferingId,
|
||||||
|
@QueryParam("root-disk-offering-id") Long rootDiskOfferingId, List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
VirtualMachineEntity createVirtualMachineFromScratch(@QueryParam("id") String id, @QueryParam("owner") String owner, @QueryParam("iso-id") String isoId,
|
VirtualMachineEntity createVirtualMachineFromScratch(@QueryParam("id") String id, @QueryParam("owner") String owner, @QueryParam("iso-id") String isoId,
|
||||||
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
|
@QueryParam("host-name") String hostName, @QueryParam("display-name") String displayName, @QueryParam("hypervisor") String hypervisor,
|
||||||
@QueryParam("os") String os, @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
|
@QueryParam("os") String os, @QueryParam("cpu") int cpu, @QueryParam("speed") int speed, @QueryParam("ram") long memory, @QueryParam("disk-size") Long diskSize,
|
||||||
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
|
@QueryParam("compute-tags") List<String> computeTags, @QueryParam("root-disk-tags") List<String> rootDiskTags,
|
||||||
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
|
@QueryParam("network-nic-map") Map<String, List<NicProfile>> networkNicMap, @QueryParam("deploymentplan") DeploymentPlan plan,
|
||||||
@QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap, @QueryParam("disk-offering-id") Long diskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
|
@QueryParam("extra-dhcp-option-map") Map<String, Map<Integer, String>> extraDhcpOptionMap, @QueryParam("disk-offering-id") Long diskOfferingId,
|
||||||
|
@QueryParam("data-disks-offering-info") List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException;
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
NetworkEntity createNetwork(String id, String name, String domainName, String cidr, String gateway);
|
NetworkEntity createNetwork(String id, String name, String domainName, String cidr, String gateway);
|
||||||
|
|||||||
@ -220,6 +220,14 @@ public interface StorageManager extends StorageService {
|
|||||||
"storage.pool.host.connect.workers", "1",
|
"storage.pool.host.connect.workers", "1",
|
||||||
"Number of worker threads to be used to connect hosts to a primary storage", true);
|
"Number of worker threads to be used to connect hosts to a primary storage", true);
|
||||||
|
|
||||||
|
ConfigKey<Float> ObjectStorageCapacityThreshold = new ConfigKey<>("Alert", Float.class,
|
||||||
|
"objectStorage.capacity.notificationthreshold",
|
||||||
|
"0.75",
|
||||||
|
"Percentage (as a value between 0 and 1) of object storage utilization above which alerts will be sent about low storage available.",
|
||||||
|
true,
|
||||||
|
ConfigKey.Scope.Global,
|
||||||
|
null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* should we execute in sequence not involving any storages?
|
* should we execute in sequence not involving any storages?
|
||||||
* @return tru if commands should execute in sequence
|
* @return tru if commands should execute in sequence
|
||||||
@ -415,4 +423,6 @@ public interface StorageManager extends StorageService {
|
|||||||
Pair<Boolean, String> checkIfReadyVolumeFitsInStoragePoolWithStorageAccessGroups(StoragePool destPool, Volume volume);
|
Pair<Boolean, String> checkIfReadyVolumeFitsInStoragePoolWithStorageAccessGroups(StoragePool destPool, Volume volume);
|
||||||
|
|
||||||
String[] getStorageAccessGroups(Long zoneId, Long podId, Long clusterId, Long hostId);
|
String[] getStorageAccessGroups(Long zoneId, Long podId, Long clusterId, Long hostId);
|
||||||
|
|
||||||
|
CapacityVO getObjectStorageUsedStats(Long zoneId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,8 @@ import org.apache.cloudstack.api.ApiConstants;
|
|||||||
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
|
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
|
||||||
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
|
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
|
||||||
|
import org.apache.cloudstack.backup.BackupManager;
|
||||||
|
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||||
import org.apache.cloudstack.ca.CAManager;
|
import org.apache.cloudstack.ca.CAManager;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
@ -437,6 +439,10 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
VmWorkJobDao vmWorkJobDao;
|
VmWorkJobDao vmWorkJobDao;
|
||||||
@Inject
|
@Inject
|
||||||
DataStoreProviderManager dataStoreProviderManager;
|
DataStoreProviderManager dataStoreProviderManager;
|
||||||
|
@Inject
|
||||||
|
BackupManager backupManager;
|
||||||
|
@Inject
|
||||||
|
BackupDao backupDao;
|
||||||
|
|
||||||
private SingleCache<List<Long>> vmIdsInProgressCache;
|
private SingleCache<List<Long>> vmIdsInProgressCache;
|
||||||
|
|
||||||
@ -525,8 +531,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
@Override
|
@Override
|
||||||
@DB
|
@DB
|
||||||
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
|
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
|
||||||
final DiskOfferingInfo rootDiskOfferingInfo, final List<DiskOfferingInfo> dataDiskOfferings,
|
final DiskOfferingInfo rootDiskOfferingInfo, final List<DiskOfferingInfo> dataDiskOfferings, List<Long> dataDiskDeviceIds,
|
||||||
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks, final DeploymentPlan plan, final HypervisorType hyperType, final Map<String, Map<Integer, String>> extraDhcpOptions, final Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, Volume volume, Snapshot snapshot)
|
final LinkedHashMap<? extends Network, List<? extends NicProfile>> auxiliaryNetworks,final DeploymentPlan plan, final HypervisorType hyperType,
|
||||||
|
final Map<String, Map<Integer, String>> extraDhcpOptions, final Map<Long, DiskOffering> datadiskTemplateToDiskOfferingMap, Volume volume, Snapshot snapshot)
|
||||||
throws InsufficientCapacityException {
|
throws InsufficientCapacityException {
|
||||||
|
|
||||||
logger.info("allocating virtual machine from template: {} with hostname: {} and {} networks", template, vmInstanceName, auxiliaryNetworks.size());
|
logger.info("allocating virtual machine from template: {} with hostname: {} and {} networks", template, vmInstanceName, auxiliaryNetworks.size());
|
||||||
@ -570,19 +577,22 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
|
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
|
||||||
try {
|
try {
|
||||||
if (dataDiskOfferings != null) {
|
if (dataDiskOfferings != null) {
|
||||||
|
int index = 0;
|
||||||
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
|
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
|
||||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId(), dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
|
Long deviceId = dataDiskDeviceIds.get(index++);
|
||||||
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, null);
|
String volumeName = deviceId == null ? "DATA-" + persistedVm.getId() : "DATA-" + persistedVm.getId() + "-" + String.valueOf(deviceId);
|
||||||
|
volumeMgr.allocateRawVolume(Type.DATADISK, volumeName, dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
|
||||||
|
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, deviceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
|
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
|
||||||
int diskNumber = 1;
|
Long diskNumber = 1L;
|
||||||
for (Entry<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap : datadiskTemplateToDiskOfferingMap.entrySet()) {
|
for (Entry<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap : datadiskTemplateToDiskOfferingMap.entrySet()) {
|
||||||
DiskOffering diskOffering = dataDiskTemplateToDiskOfferingMap.getValue();
|
DiskOffering diskOffering = dataDiskTemplateToDiskOfferingMap.getValue();
|
||||||
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
|
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
|
||||||
VMTemplateVO dataDiskTemplate = _templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
|
VMTemplateVO dataDiskTemplate = _templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
|
||||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf(diskNumber), diskOffering, diskOfferingSize, null, null,
|
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf( diskNumber), diskOffering, diskOfferingSize, null, null,
|
||||||
persistedVm, dataDiskTemplate, owner, Long.valueOf(diskNumber));
|
persistedVm, dataDiskTemplate, owner, diskNumber);
|
||||||
diskNumber++;
|
diskNumber++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -629,7 +639,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
|
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
|
||||||
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
|
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
|
||||||
DiskOffering diskOffering = _diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
|
DiskOffering diskOffering = _diskOfferingDao.findById(serviceOffering.getDiskOfferingId());
|
||||||
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), networks, plan, hyperType, null, null, volume, snapshot);
|
allocate(vmInstanceName, template, serviceOffering, new DiskOfferingInfo(diskOffering), new ArrayList<>(), new ArrayList<>(), networks, plan, hyperType, null, null, volume, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualMachineGuru getVmGuru(final VirtualMachine vm) {
|
VirtualMachineGuru getVmGuru(final VirtualMachine vm) {
|
||||||
@ -2589,6 +2599,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||||||
throw new CloudRuntimeException("Unable to destroy " + vm);
|
throw new CloudRuntimeException("Unable to destroy " + vm);
|
||||||
} else {
|
} else {
|
||||||
if (expunge) {
|
if (expunge) {
|
||||||
|
backupManager.checkAndRemoveBackupOfferingBeforeExpunge(vm);
|
||||||
if (!stateTransitTo(vm, VirtualMachine.Event.ExpungeOperation, vm.getHostId())) {
|
if (!stateTransitTo(vm, VirtualMachine.Event.ExpungeOperation, vm.getHostId())) {
|
||||||
logger.debug("Unable to expunge the vm because it is not in the correct state: {}", vm);
|
logger.debug("Unable to expunge the vm because it is not in the correct state: {}", vm);
|
||||||
throw new CloudRuntimeException("Unable to expunge " + vm);
|
throw new CloudRuntimeException("Unable to expunge " + vm);
|
||||||
|
|||||||
@ -60,6 +60,7 @@ import com.cloud.utils.component.ComponentContext;
|
|||||||
import com.cloud.vm.NicProfile;
|
import com.cloud.vm.NicProfile;
|
||||||
import com.cloud.vm.VMInstanceVO;
|
import com.cloud.vm.VMInstanceVO;
|
||||||
import com.cloud.vm.VirtualMachineManager;
|
import com.cloud.vm.VirtualMachineManager;
|
||||||
|
import com.cloud.vm.VmDiskInfo;
|
||||||
import com.cloud.vm.dao.UserVmDao;
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
import com.cloud.vm.dao.VMInstanceDetailsDao;
|
import com.cloud.vm.dao.VMInstanceDetailsDao;
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
@ -162,7 +163,8 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
@Override
|
@Override
|
||||||
public VirtualMachineEntity createVirtualMachine(String id, String owner, String templateId, String hostName, String displayName, String hypervisor, int cpu,
|
public VirtualMachineEntity createVirtualMachine(String id, String owner, String templateId, String hostName, String displayName, String hypervisor, int cpu,
|
||||||
int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, List<NicProfile>> networkNicMap, DeploymentPlan plan,
|
int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, List<NicProfile>> networkNicMap, DeploymentPlan plan,
|
||||||
Long rootDiskSize, Map<String, Map<Integer, String>> extraDhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Long dataDiskOfferingId, Long rootDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
|
Long rootDiskSize, Map<String, Map<Integer, String>> extraDhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Long dataDiskOfferingId, Long rootDiskOfferingId,
|
||||||
|
List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
|
||||||
|
|
||||||
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks,
|
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks,
|
||||||
// vmEntityManager);
|
// vmEntityManager);
|
||||||
@ -187,7 +189,6 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
// Else, a disk offering is optional, and if present will be used to create the data disk
|
// Else, a disk offering is optional, and if present will be used to create the data disk
|
||||||
|
|
||||||
DiskOfferingInfo rootDiskOfferingInfo = new DiskOfferingInfo();
|
DiskOfferingInfo rootDiskOfferingInfo = new DiskOfferingInfo();
|
||||||
List<DiskOfferingInfo> dataDiskOfferings = new ArrayList<DiskOfferingInfo>();
|
|
||||||
|
|
||||||
ServiceOfferingVO computeOffering = _serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
|
ServiceOfferingVO computeOffering = _serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
|
||||||
|
|
||||||
@ -210,6 +211,8 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<DiskOfferingInfo> dataDiskOfferings = new ArrayList<DiskOfferingInfo>();
|
||||||
|
List<Long> dataDiskDeviceIds = new ArrayList<>();
|
||||||
if (dataDiskOfferingId != null) {
|
if (dataDiskOfferingId != null) {
|
||||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(dataDiskOfferingId);
|
DiskOfferingVO diskOffering = _diskOfferingDao.findById(dataDiskOfferingId);
|
||||||
if (diskOffering == null) {
|
if (diskOffering == null) {
|
||||||
@ -243,6 +246,12 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dataDiskOfferings.add(dataDiskOfferingInfo);
|
dataDiskOfferings.add(dataDiskOfferingInfo);
|
||||||
|
dataDiskDeviceIds.add(null);
|
||||||
|
}
|
||||||
|
} else if (dataDiskInfoList != null){
|
||||||
|
dataDiskOfferings.addAll(dataDiskInfoList);
|
||||||
|
for (VmDiskInfo dataDiskInfo : dataDiskInfoList) {
|
||||||
|
dataDiskDeviceIds.add(dataDiskInfo.getDeviceId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,8 +271,8 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
template = _templateDao.findByIdIncludingRemoved(new Long(templateId));
|
template = _templateDao.findByIdIncludingRemoved(new Long(templateId));
|
||||||
} else
|
} else
|
||||||
template = _templateDao.findById(new Long(templateId));
|
template = _templateDao.findById(new Long(templateId));
|
||||||
_itMgr.allocate(vm.getInstanceName(), template, computeOffering, rootDiskOfferingInfo, dataDiskOfferings, networkIpMap, plan,
|
_itMgr.allocate(vm.getInstanceName(), template, computeOffering, rootDiskOfferingInfo, dataDiskOfferings, dataDiskDeviceIds,
|
||||||
hypervisorType, extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap, volume, snapshot);
|
networkIpMap, plan, hypervisorType, extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap, volume, snapshot);
|
||||||
|
|
||||||
return vmEntity;
|
return vmEntity;
|
||||||
}
|
}
|
||||||
@ -271,7 +280,7 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
@Override
|
@Override
|
||||||
public VirtualMachineEntity createVirtualMachineFromScratch(String id, String owner, String isoId, String hostName, String displayName, String hypervisor, String os,
|
public VirtualMachineEntity createVirtualMachineFromScratch(String id, String owner, String isoId, String hostName, String displayName, String hypervisor, String os,
|
||||||
int cpu, int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, List<NicProfile>> networkNicMap, DeploymentPlan plan,
|
int cpu, int speed, long memory, Long diskSize, List<String> computeTags, List<String> rootDiskTags, Map<String, List<NicProfile>> networkNicMap, DeploymentPlan plan,
|
||||||
Map<String, Map<Integer, String>> extraDhcpOptionMap, Long diskOfferingId, Volume volume, Snapshot snapshot)
|
Map<String, Map<Integer, String>> extraDhcpOptionMap, Long diskOfferingId, List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot)
|
||||||
throws InsufficientCapacityException {
|
throws InsufficientCapacityException {
|
||||||
|
|
||||||
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, vmEntityManager);
|
// VirtualMachineEntityImpl vmEntity = new VirtualMachineEntityImpl(id, owner, hostName, displayName, cpu, speed, memory, computeTags, rootDiskTags, networks, vmEntityManager);
|
||||||
@ -317,6 +326,14 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
rootDiskOfferingInfo.setMaxIops(maxIops != null && maxIops.trim().length() > 0 ? Long.parseLong(maxIops) : null);
|
rootDiskOfferingInfo.setMaxIops(maxIops != null && maxIops.trim().length() > 0 ? Long.parseLong(maxIops) : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
List<DiskOfferingInfo> dataDiskOfferings = new ArrayList<>();
|
||||||
|
List<Long> dataDiskDeviceIds = new ArrayList<>();
|
||||||
|
if (dataDiskInfoList != null) {
|
||||||
|
dataDiskOfferings.addAll(dataDiskInfoList);
|
||||||
|
for (VmDiskInfo dataDiskInfo : dataDiskInfoList) {
|
||||||
|
dataDiskDeviceIds.add(dataDiskInfo.getDeviceId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LinkedHashMap<Network, List<? extends NicProfile>> networkIpMap = new LinkedHashMap<Network, List<? extends NicProfile>>();
|
LinkedHashMap<Network, List<? extends NicProfile>> networkIpMap = new LinkedHashMap<Network, List<? extends NicProfile>>();
|
||||||
for (String uuid : networkNicMap.keySet()) {
|
for (String uuid : networkNicMap.keySet()) {
|
||||||
@ -328,7 +345,8 @@ public class CloudOrchestrator implements OrchestrationService {
|
|||||||
|
|
||||||
HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor);
|
HypervisorType hypervisorType = HypervisorType.valueOf(hypervisor);
|
||||||
|
|
||||||
_itMgr.allocate(vm.getInstanceName(), _templateDao.findByIdIncludingRemoved(new Long(isoId)), computeOffering, rootDiskOfferingInfo, new ArrayList<DiskOfferingInfo>(), networkIpMap, plan, hypervisorType, extraDhcpOptionMap, null, volume, snapshot);
|
_itMgr.allocate(vm.getInstanceName(), _templateDao.findByIdIncludingRemoved(new Long(isoId)), computeOffering, rootDiskOfferingInfo, dataDiskOfferings, dataDiskDeviceIds,
|
||||||
|
networkIpMap, plan, hypervisorType, extraDhcpOptionMap, null, volume, snapshot);
|
||||||
|
|
||||||
return vmEntity;
|
return vmEntity;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -254,6 +254,8 @@ public class CapacityVO implements Capacity {
|
|||||||
capacityNames.put(CAPACITY_TYPE_GPU, "GPU");
|
capacityNames.put(CAPACITY_TYPE_GPU, "GPU");
|
||||||
capacityNames.put(CAPACITY_TYPE_CPU_CORE, "CPU_CORE");
|
capacityNames.put(CAPACITY_TYPE_CPU_CORE, "CPU_CORE");
|
||||||
capacityNames.put(CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, "VIRTUAL_NETWORK_IPV6_SUBNET");
|
capacityNames.put(CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, "VIRTUAL_NETWORK_IPV6_SUBNET");
|
||||||
|
capacityNames.put(CAPACITY_TYPE_BACKUP_STORAGE, "BACKUP_STORAGE");
|
||||||
|
capacityNames.put(CAPACITY_TYPE_OBJECT_STORAGE, "OBJECT_STORAGE");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCapacityName (Short capacityType) {
|
public static String getCapacityName (Short capacityType) {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import com.cloud.usage.UsageBackupVO;
|
|||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
public interface UsageBackupDao extends GenericDao<UsageBackupVO, Long> {
|
public interface UsageBackupDao extends GenericDao<UsageBackupVO, Long> {
|
||||||
void updateMetrics(Long vmId, Long size, Long virtualSize);
|
void updateMetrics(Long vmId, Long backupOfferingId, Long size, Long virtualSize);
|
||||||
void removeUsage(Long accountId, Long vmId, Date eventDate);
|
void removeUsage(Long accountId, Long vmId, Long backupOfferingId, Date eventDate);
|
||||||
List<UsageBackupVO> getUsageRecords(Long accountId, Date startDate, Date endDate);
|
List<UsageBackupVO> getUsageRecords(Long accountId, Date startDate, Date endDate);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,16 +36,17 @@ import com.cloud.utils.db.TransactionLegacy;
|
|||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class UsageBackupDaoImpl extends GenericDaoBase<UsageBackupVO, Long> implements UsageBackupDao {
|
public class UsageBackupDaoImpl extends GenericDaoBase<UsageBackupVO, Long> implements UsageBackupDao {
|
||||||
protected static final String UPDATE_DELETED = "UPDATE usage_backup SET removed = ? WHERE account_id = ? AND vm_id = ? and removed IS NULL";
|
protected static final String UPDATE_DELETED = "UPDATE usage_backup SET removed = ? WHERE account_id = ? AND vm_id = ? and backup_offering_id = ? and removed IS NULL";
|
||||||
protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT id, zone_id, account_id, domain_id, vm_id, backup_offering_id, size, protected_size, created, removed FROM usage_backup WHERE " +
|
protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT id, zone_id, account_id, domain_id, vm_id, backup_offering_id, size, protected_size, created, removed FROM usage_backup WHERE " +
|
||||||
" account_id = ? AND ((removed IS NULL AND created <= ?) OR (created BETWEEN ? AND ?) OR (removed BETWEEN ? AND ?) " +
|
" account_id = ? AND ((removed IS NULL AND created <= ?) OR (created BETWEEN ? AND ?) OR (removed BETWEEN ? AND ?) " +
|
||||||
" OR ((created <= ?) AND (removed >= ?)))";
|
" OR ((created <= ?) AND (removed >= ?)))";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateMetrics(final Long vmId, final Long size, final Long virtualSize) {
|
public void updateMetrics(final Long vmId, Long backupOfferingId, final Long size, final Long virtualSize) {
|
||||||
try (TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB)) {
|
try (TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB)) {
|
||||||
SearchCriteria<UsageBackupVO> sc = this.createSearchCriteria();
|
SearchCriteria<UsageBackupVO> sc = this.createSearchCriteria();
|
||||||
sc.addAnd("vmId", SearchCriteria.Op.EQ, vmId);
|
sc.addAnd("vmId", SearchCriteria.Op.EQ, vmId);
|
||||||
|
sc.addAnd("backupOfferingId", SearchCriteria.Op.EQ, backupOfferingId);
|
||||||
UsageBackupVO vo = findOneBy(sc);
|
UsageBackupVO vo = findOneBy(sc);
|
||||||
if (vo != null) {
|
if (vo != null) {
|
||||||
vo.setSize(size);
|
vo.setSize(size);
|
||||||
@ -58,7 +59,7 @@ public class UsageBackupDaoImpl extends GenericDaoBase<UsageBackupVO, Long> impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeUsage(Long accountId, Long vmId, Date eventDate) {
|
public void removeUsage(Long accountId, Long vmId, Long backupOfferingId, Date eventDate) {
|
||||||
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
|
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
|
||||||
try {
|
try {
|
||||||
txn.start();
|
txn.start();
|
||||||
@ -67,6 +68,7 @@ public class UsageBackupDaoImpl extends GenericDaoBase<UsageBackupVO, Long> impl
|
|||||||
pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), eventDate));
|
pstmt.setString(1, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), eventDate));
|
||||||
pstmt.setLong(2, accountId);
|
pstmt.setLong(2, accountId);
|
||||||
pstmt.setLong(3, vmId);
|
pstmt.setLong(3, vmId);
|
||||||
|
pstmt.setLong(3, backupOfferingId);
|
||||||
pstmt.executeUpdate();
|
pstmt.executeUpdate();
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
|||||||
@ -118,7 +118,7 @@ public interface VMInstanceDao extends GenericDao<VMInstanceVO, Long>, StateDao<
|
|||||||
|
|
||||||
List<VMInstanceVO> listVmsMigratingFromHost(Long hostId);
|
List<VMInstanceVO> listVmsMigratingFromHost(Long hostId);
|
||||||
|
|
||||||
List<VMInstanceVO> listByZoneWithBackups(Long zoneId, Long backupOfferingId);
|
List<VMInstanceVO> listByZoneAndBackupOffering(Long zoneId, Long backupOfferingId);
|
||||||
|
|
||||||
public Long countActiveByHostId(long hostId);
|
public Long countActiveByHostId(long hostId);
|
||||||
|
|
||||||
@ -187,4 +187,5 @@ public interface VMInstanceDao extends GenericDao<VMInstanceVO, Long>, StateDao<
|
|||||||
|
|
||||||
Map<String, Long> getNameIdMapForVmIds(Collection<Long> ids);
|
Map<String, Long> getNameIdMapForVmIds(Collection<Long> ids);
|
||||||
|
|
||||||
|
List<VMInstanceVO> listByIdsIncludingRemoved(List<Long> ids);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -661,7 +661,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<VMInstanceVO> listByZoneWithBackups(Long zoneId, Long backupOfferingId) {
|
public List<VMInstanceVO> listByZoneAndBackupOffering(Long zoneId, Long backupOfferingId) {
|
||||||
SearchCriteria<VMInstanceVO> sc = BackupSearch.create();
|
SearchCriteria<VMInstanceVO> sc = BackupSearch.create();
|
||||||
sc.setParameters("zone_id", zoneId);
|
sc.setParameters("zone_id", zoneId);
|
||||||
if (backupOfferingId != null) {
|
if (backupOfferingId != null) {
|
||||||
@ -1246,4 +1246,14 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
|
|||||||
return vms.stream()
|
return vms.stream()
|
||||||
.collect(Collectors.toMap(VMInstanceVO::getInstanceName, VMInstanceVO::getId));
|
.collect(Collectors.toMap(VMInstanceVO::getInstanceName, VMInstanceVO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<VMInstanceVO> listByIdsIncludingRemoved(List<Long> ids) {
|
||||||
|
SearchBuilder<VMInstanceVO> idsSearch = createSearchBuilder();
|
||||||
|
idsSearch.and("ids", idsSearch.entity().getId(), SearchCriteria.Op.IN);
|
||||||
|
idsSearch.done();
|
||||||
|
SearchCriteria<VMInstanceVO> sc = idsSearch.create();
|
||||||
|
sc.setParameters("ids", ids.toArray());
|
||||||
|
return listIncludingRemovedBy(sc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,98 @@
|
|||||||
|
// 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 javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ResourceDetail;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "backup_details")
|
||||||
|
public class BackupDetailVO implements ResourceDetail {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "id")
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Column(name = "backup_id")
|
||||||
|
private long resourceId;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "value", length = 65536)
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
@Column(name = "display")
|
||||||
|
private boolean display = true;
|
||||||
|
|
||||||
|
public BackupDetailVO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BackupDetailVO(long backupId, String name, String value, boolean display) {
|
||||||
|
this.resourceId = backupId;
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
this.display = display;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getResourceId() {
|
||||||
|
return resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDisplay() {
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceId(long resourceId) {
|
||||||
|
this.resourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -144,11 +144,21 @@ public class BackupRepositoryVO implements BackupRepository {
|
|||||||
return usedBytes;
|
return usedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUsedBytes(Long usedBytes) {
|
||||||
|
this.usedBytes = usedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getCapacityBytes() {
|
public Long getCapacityBytes() {
|
||||||
return capacityBytes;
|
return capacityBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCapacityBytes(Long capacityBytes) {
|
||||||
|
this.capacityBytes = capacityBytes;
|
||||||
|
}
|
||||||
|
|
||||||
public Date getCreated() {
|
public Date getCreated() {
|
||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,16 +65,20 @@ public class BackupScheduleVO implements BackupSchedule {
|
|||||||
@Column(name = "max_backups")
|
@Column(name = "max_backups")
|
||||||
private int maxBackups = 0;
|
private int maxBackups = 0;
|
||||||
|
|
||||||
|
@Column(name = "quiescevm")
|
||||||
|
Boolean quiesceVM = false;
|
||||||
|
|
||||||
public BackupScheduleVO() {
|
public BackupScheduleVO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public BackupScheduleVO(Long vmId, DateUtil.IntervalType scheduleType, String schedule, String timezone, Date scheduledTimestamp, int maxBackups) {
|
public BackupScheduleVO(Long vmId, DateUtil.IntervalType scheduleType, String schedule, String timezone, Date scheduledTimestamp, int maxBackups, Boolean quiesceVM) {
|
||||||
this.vmId = vmId;
|
this.vmId = vmId;
|
||||||
this.scheduleType = (short) scheduleType.ordinal();
|
this.scheduleType = (short) scheduleType.ordinal();
|
||||||
this.schedule = schedule;
|
this.schedule = schedule;
|
||||||
this.timezone = timezone;
|
this.timezone = timezone;
|
||||||
this.scheduledTimestamp = scheduledTimestamp;
|
this.scheduledTimestamp = scheduledTimestamp;
|
||||||
this.maxBackups = maxBackups;
|
this.maxBackups = maxBackups;
|
||||||
|
this.quiesceVM = quiesceVM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -149,4 +153,12 @@ public class BackupScheduleVO implements BackupSchedule {
|
|||||||
public void setMaxBackups(int maxBackups) {
|
public void setMaxBackups(int maxBackups) {
|
||||||
this.maxBackups = maxBackups;
|
this.maxBackups = maxBackups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setQuiesceVM(Boolean quiesceVM) {
|
||||||
|
this.quiesceVM = quiesceVM;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getQuiesceVM() {
|
||||||
|
return quiesceVM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package org.apache.cloudstack.backup;
|
|||||||
|
|
||||||
import com.cloud.utils.db.GenericDao;
|
import com.cloud.utils.db.GenericDao;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
@ -38,6 +40,7 @@ import javax.persistence.Id;
|
|||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Temporal;
|
import javax.persistence.Temporal;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "backups")
|
@Table(name = "backups")
|
||||||
@ -47,11 +50,17 @@ public class BackupVO implements Backup {
|
|||||||
@Column(name = "id")
|
@Column(name = "id")
|
||||||
private long id;
|
private long id;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "description")
|
||||||
|
private String description;
|
||||||
|
|
||||||
@Column(name = "uuid")
|
@Column(name = "uuid")
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
|
||||||
@Column(name = "vm_id")
|
@Column(name = "vm_id")
|
||||||
private long vmId;
|
private Long vmId;
|
||||||
|
|
||||||
@Column(name = "external_id")
|
@Column(name = "external_id")
|
||||||
private String externalId;
|
private String externalId;
|
||||||
@ -94,6 +103,9 @@ public class BackupVO implements Backup {
|
|||||||
@Column(name = "backup_schedule_id")
|
@Column(name = "backup_schedule_id")
|
||||||
private Long backupScheduleId;
|
private Long backupScheduleId;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
Map<String, String> details;
|
||||||
|
|
||||||
public BackupVO() {
|
public BackupVO() {
|
||||||
this.uuid = UUID.randomUUID().toString();
|
this.uuid = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
@ -115,11 +127,11 @@ public class BackupVO implements Backup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getVmId() {
|
public Long getVmId() {
|
||||||
return vmId;
|
return vmId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVmId(long vmId) {
|
public void setVmId(Long vmId) {
|
||||||
this.vmId = vmId;
|
this.vmId = vmId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +230,22 @@ public class BackupVO implements Backup {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return null;
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<VolumeInfo> getBackedUpVolumes() {
|
public List<VolumeInfo> getBackedUpVolumes() {
|
||||||
@ -232,10 +259,23 @@ public class BackupVO implements Backup {
|
|||||||
this.backedUpVolumes = backedUpVolumes;
|
this.backedUpVolumes = backedUpVolumes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getDetails() {
|
||||||
|
return details;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDetail(String name) {
|
||||||
|
return this.details.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetails(Map<String, String> details) {
|
||||||
|
this.details = details;
|
||||||
|
}
|
||||||
|
|
||||||
public Date getRemoved() {
|
public Date getRemoved() {
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRemoved(Date removed) {
|
public void setRemoved(Date removed) {
|
||||||
this.removed = removed;
|
this.removed = removed;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,6 @@ package org.apache.cloudstack.backup.dao;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.response.BackupResponse;
|
|
||||||
import org.apache.cloudstack.backup.Backup;
|
import org.apache.cloudstack.backup.Backup;
|
||||||
import org.apache.cloudstack.backup.BackupVO;
|
import org.apache.cloudstack.backup.BackupVO;
|
||||||
|
|
||||||
@ -33,11 +32,14 @@ public interface BackupDao extends GenericDao<BackupVO, Long> {
|
|||||||
List<Backup> listByVmId(Long zoneId, Long vmId);
|
List<Backup> listByVmId(Long zoneId, Long vmId);
|
||||||
List<Backup> listByAccountId(Long accountId);
|
List<Backup> listByAccountId(Long accountId);
|
||||||
List<Backup> syncBackups(Long zoneId, Long vmId, List<Backup> externalBackups);
|
List<Backup> syncBackups(Long zoneId, Long vmId, List<Backup> externalBackups);
|
||||||
|
List<Backup> listByVmIdAndOffering(Long zoneId, Long vmId, Long offeringId);
|
||||||
|
List<BackupVO> searchByVmIds(List<Long> vmIds);
|
||||||
BackupVO getBackupVO(Backup backup);
|
BackupVO getBackupVO(Backup backup);
|
||||||
List<Backup> listByOfferingId(Long backupOfferingId);
|
List<Backup> listByOfferingId(Long backupOfferingId);
|
||||||
|
List<Long> listVmIdsWithBackupsInZone(Long zoneId);
|
||||||
BackupResponse newBackupResponse(Backup backup);
|
|
||||||
public Long countBackupsForAccount(long accountId);
|
public Long countBackupsForAccount(long accountId);
|
||||||
public Long calculateBackupStorageForAccount(long accountId);
|
public Long calculateBackupStorageForAccount(long accountId);
|
||||||
|
void loadDetails(BackupVO backup);
|
||||||
|
void saveDetails(BackupVO backup);
|
||||||
List<BackupVO> listBySchedule(Long backupScheduleId);
|
List<BackupVO> listBySchedule(Long backupScheduleId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,30 +19,31 @@ package org.apache.cloudstack.backup.dao;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.utils.db.Filter;
|
import com.cloud.utils.db.Filter;
|
||||||
import com.cloud.utils.db.GenericSearchBuilder;
|
import com.cloud.utils.db.GenericSearchBuilder;
|
||||||
import org.apache.cloudstack.api.response.BackupResponse;
|
|
||||||
import org.apache.cloudstack.backup.Backup;
|
|
||||||
import org.apache.cloudstack.backup.BackupOffering;
|
|
||||||
import org.apache.cloudstack.backup.BackupVO;
|
|
||||||
|
|
||||||
import com.cloud.dc.DataCenterVO;
|
import org.apache.cloudstack.backup.Backup;
|
||||||
|
import org.apache.cloudstack.backup.BackupDetailVO;
|
||||||
|
import org.apache.cloudstack.backup.BackupVO;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
|
||||||
import com.cloud.dc.dao.DataCenterDao;
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
import com.cloud.domain.DomainVO;
|
|
||||||
import com.cloud.domain.dao.DomainDao;
|
import com.cloud.domain.dao.DomainDao;
|
||||||
import com.cloud.user.AccountVO;
|
|
||||||
import com.cloud.user.dao.AccountDao;
|
import com.cloud.user.dao.AccountDao;
|
||||||
import com.cloud.utils.db.GenericDaoBase;
|
import com.cloud.utils.db.GenericDaoBase;
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
import com.cloud.vm.VMInstanceVO;
|
import com.cloud.utils.db.Transaction;
|
||||||
|
import com.cloud.utils.db.TransactionCallback;
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
import com.google.gson.Gson;
|
import com.cloud.network.dao.NetworkDao;
|
||||||
|
|
||||||
public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements BackupDao {
|
public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements BackupDao {
|
||||||
|
|
||||||
@ -58,13 +59,26 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
|
|||||||
@Inject
|
@Inject
|
||||||
VMInstanceDao vmInstanceDao;
|
VMInstanceDao vmInstanceDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private VMTemplateDao templateDao;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
BackupOfferingDao backupOfferingDao;
|
BackupOfferingDao backupOfferingDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
BackupDetailsDao backupDetailsDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ServiceOfferingDao serviceOfferingDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
NetworkDao networkDao;
|
||||||
|
|
||||||
private SearchBuilder<BackupVO> backupSearch;
|
private SearchBuilder<BackupVO> backupSearch;
|
||||||
private GenericSearchBuilder<BackupVO, Long> CountBackupsByAccount;
|
private GenericSearchBuilder<BackupVO, Long> CountBackupsByAccount;
|
||||||
private GenericSearchBuilder<BackupVO, SumCount> CalculateBackupStorageByAccount;
|
private GenericSearchBuilder<BackupVO, SumCount> CalculateBackupStorageByAccount;
|
||||||
private SearchBuilder<BackupVO> listBackupsBySchedule;
|
private SearchBuilder<BackupVO> listBackupsBySchedule;
|
||||||
|
private GenericSearchBuilder<BackupVO, Long> backupVmSearchInZone;
|
||||||
|
|
||||||
public BackupDaoImpl() {
|
public BackupDaoImpl() {
|
||||||
}
|
}
|
||||||
@ -78,6 +92,11 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
|
|||||||
backupSearch.and("zone_id", backupSearch.entity().getZoneId(), SearchCriteria.Op.EQ);
|
backupSearch.and("zone_id", backupSearch.entity().getZoneId(), SearchCriteria.Op.EQ);
|
||||||
backupSearch.done();
|
backupSearch.done();
|
||||||
|
|
||||||
|
backupVmSearchInZone = createSearchBuilder(Long.class);
|
||||||
|
backupVmSearchInZone.select(null, SearchCriteria.Func.DISTINCT, backupVmSearchInZone.entity().getVmId());
|
||||||
|
backupVmSearchInZone.and("zone_id", backupVmSearchInZone.entity().getZoneId(), SearchCriteria.Op.EQ);
|
||||||
|
backupVmSearchInZone.done();
|
||||||
|
|
||||||
CountBackupsByAccount = createSearchBuilder(Long.class);
|
CountBackupsByAccount = createSearchBuilder(Long.class);
|
||||||
CountBackupsByAccount.select(null, SearchCriteria.Func.COUNT, null);
|
CountBackupsByAccount.select(null, SearchCriteria.Func.COUNT, null);
|
||||||
CountBackupsByAccount.and("account", CountBackupsByAccount.entity().getAccountId(), SearchCriteria.Op.EQ);
|
CountBackupsByAccount.and("account", CountBackupsByAccount.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||||
@ -130,6 +149,17 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
|
|||||||
return new ArrayList<>(listBy(sc));
|
return new ArrayList<>(listBy(sc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Backup> listByVmIdAndOffering(Long zoneId, Long vmId, Long offeringId) {
|
||||||
|
SearchCriteria<BackupVO> sc = backupSearch.create();
|
||||||
|
sc.setParameters("vm_id", vmId);
|
||||||
|
if (zoneId != null) {
|
||||||
|
sc.setParameters("zone_id", zoneId);
|
||||||
|
}
|
||||||
|
sc.setParameters("backup_offering_id", offeringId);
|
||||||
|
return new ArrayList<>(listBy(sc));
|
||||||
|
}
|
||||||
|
|
||||||
private Backup findByExternalId(Long zoneId, String externalId) {
|
private Backup findByExternalId(Long zoneId, String externalId) {
|
||||||
SearchCriteria<BackupVO> sc = backupSearch.create();
|
SearchCriteria<BackupVO> sc = backupSearch.create();
|
||||||
sc.setParameters("external_id", externalId);
|
sc.setParameters("external_id", externalId);
|
||||||
@ -137,6 +167,18 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
|
|||||||
return findOneBy(sc);
|
return findOneBy(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BackupVO> searchByVmIds(List<Long> vmIds) {
|
||||||
|
if (CollectionUtils.isEmpty(vmIds)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
SearchBuilder<BackupVO> sb = createSearchBuilder();
|
||||||
|
sb.and("vmIds", sb.entity().getVmId(), SearchCriteria.Op.IN);
|
||||||
|
SearchCriteria<BackupVO> sc = sb.create();
|
||||||
|
sc.setParameters("vmIds", vmIds.toArray());
|
||||||
|
return search(sc, null);
|
||||||
|
}
|
||||||
|
|
||||||
public BackupVO getBackupVO(Backup backup) {
|
public BackupVO getBackupVO(Backup backup) {
|
||||||
BackupVO backupVO = new BackupVO();
|
BackupVO backupVO = new BackupVO();
|
||||||
backupVO.setExternalId(backup.getExternalId());
|
backupVO.setExternalId(backup.getExternalId());
|
||||||
@ -158,6 +200,27 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
|
|||||||
expunge(sc);
|
expunge(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BackupVO persist(BackupVO backup) {
|
||||||
|
return Transaction.execute((TransactionCallback<BackupVO>) status -> {
|
||||||
|
BackupVO backupDb = super.persist(backup);
|
||||||
|
saveDetails(backup);
|
||||||
|
loadDetails(backupDb);
|
||||||
|
return backupDb;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean update(Long id, BackupVO backup) {
|
||||||
|
return Transaction.execute((TransactionCallback<Boolean>) status -> {
|
||||||
|
boolean result = super.update(id, backup);
|
||||||
|
if (result) {
|
||||||
|
saveDetails(backup);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Backup> syncBackups(Long zoneId, Long vmId, List<Backup> externalBackups) {
|
public List<Backup> syncBackups(Long zoneId, Long vmId, List<Backup> externalBackups) {
|
||||||
for (Backup backup : externalBackups) {
|
for (Backup backup : externalBackups) {
|
||||||
@ -171,7 +234,7 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
|
|||||||
public Long countBackupsForAccount(long accountId) {
|
public Long countBackupsForAccount(long accountId) {
|
||||||
SearchCriteria<Long> sc = CountBackupsByAccount.create();
|
SearchCriteria<Long> sc = CountBackupsByAccount.create();
|
||||||
sc.setParameters("account", accountId);
|
sc.setParameters("account", accountId);
|
||||||
sc.setParameters("status", Backup.Status.Error, Backup.Status.Failed, Backup.Status.Removed, Backup.Status.Expunged);
|
sc.setParameters("status", Backup.Status.Failed, Backup.Status.Removed, Backup.Status.Expunged);
|
||||||
return customSearch(sc, null).get(0);
|
return customSearch(sc, null).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +242,7 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
|
|||||||
public Long calculateBackupStorageForAccount(long accountId) {
|
public Long calculateBackupStorageForAccount(long accountId) {
|
||||||
SearchCriteria<SumCount> sc = CalculateBackupStorageByAccount.create();
|
SearchCriteria<SumCount> sc = CalculateBackupStorageByAccount.create();
|
||||||
sc.setParameters("account", accountId);
|
sc.setParameters("account", accountId);
|
||||||
sc.setParameters("status", Backup.Status.Error, Backup.Status.Failed, Backup.Status.Removed, Backup.Status.Expunged);
|
sc.setParameters("status", Backup.Status.Failed, Backup.Status.Removed, Backup.Status.Expunged);
|
||||||
return customSearch(sc, null).get(0).sum;
|
return customSearch(sc, null).get(0).sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,44 +255,29 @@ public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements Bac
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BackupResponse newBackupResponse(Backup backup) {
|
public void loadDetails(BackupVO backup) {
|
||||||
VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
|
Map<String, String> details = backupDetailsDao.listDetailsKeyPairs(backup.getId());
|
||||||
AccountVO account = accountDao.findByIdIncludingRemoved(vm.getAccountId());
|
backup.setDetails(details);
|
||||||
DomainVO domain = domainDao.findByIdIncludingRemoved(vm.getDomainId());
|
}
|
||||||
DataCenterVO zone = dataCenterDao.findByIdIncludingRemoved(vm.getDataCenterId());
|
|
||||||
Long offeringId = backup.getBackupOfferingId();
|
|
||||||
if (offeringId == null) {
|
|
||||||
offeringId = vm.getBackupOfferingId();
|
|
||||||
}
|
|
||||||
BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(offeringId);
|
|
||||||
|
|
||||||
BackupResponse response = new BackupResponse();
|
@Override
|
||||||
response.setId(backup.getUuid());
|
public void saveDetails(BackupVO backup) {
|
||||||
response.setVmId(vm.getUuid());
|
Map<String, String> detailsStr = backup.getDetails();
|
||||||
response.setVmName(vm.getHostName());
|
if (detailsStr == null) {
|
||||||
response.setExternalId(backup.getExternalId());
|
return;
|
||||||
response.setType(backup.getType());
|
|
||||||
response.setDate(backup.getDate());
|
|
||||||
response.setSize(backup.getSize());
|
|
||||||
response.setProtectedSize(backup.getProtectedSize());
|
|
||||||
response.setStatus(backup.getStatus());
|
|
||||||
// ACS 4.20: For backups taken prior this release the backup.backed_volumes column would be empty hence use vm_instance.backup_volumes
|
|
||||||
String backedUpVolumes;
|
|
||||||
if (Objects.isNull(backup.getBackedUpVolumes())) {
|
|
||||||
backedUpVolumes = new Gson().toJson(vm.getBackupVolumeList().toArray(), Backup.VolumeInfo[].class);
|
|
||||||
} else {
|
|
||||||
backedUpVolumes = new Gson().toJson(backup.getBackedUpVolumes().toArray(), Backup.VolumeInfo[].class);
|
|
||||||
}
|
}
|
||||||
response.setVolumes(backedUpVolumes);
|
List<BackupDetailVO> details = new ArrayList<BackupDetailVO>();
|
||||||
response.setBackupOfferingId(offering.getUuid());
|
for (String key : detailsStr.keySet()) {
|
||||||
response.setBackupOffering(offering.getName());
|
BackupDetailVO detail = new BackupDetailVO(backup.getId(), key, detailsStr.get(key), true);
|
||||||
response.setAccountId(account.getUuid());
|
details.add(detail);
|
||||||
response.setAccount(account.getAccountName());
|
}
|
||||||
response.setDomainId(domain.getUuid());
|
backupDetailsDao.saveDetails(details);
|
||||||
response.setDomain(domain.getName());
|
}
|
||||||
response.setZoneId(zone.getUuid());
|
|
||||||
response.setZone(zone.getName());
|
@Override
|
||||||
response.setObjectName("backup");
|
public List<Long> listVmIdsWithBackupsInZone(Long zoneId) {
|
||||||
return response;
|
SearchCriteria<Long> sc = backupVmSearchInZone.create();
|
||||||
|
sc.setParameters("zone_id", zoneId);
|
||||||
|
return customSearchIncludingRemoved(sc, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.backup.dao;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.backup.BackupDetailVO;
|
||||||
|
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
|
||||||
|
|
||||||
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
|
public interface BackupDetailsDao extends GenericDao<BackupDetailVO, Long>, ResourceDetailsDao<BackupDetailVO> {
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.backup.dao;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.cloudstack.backup.BackupDetailVO;
|
||||||
|
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class BackupDetailsDaoImpl extends ResourceDetailsDaoBase<BackupDetailVO> implements BackupDetailsDao {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addDetail(long resourceId, String key, String value, boolean display) {
|
||||||
|
super.addDetail(new BackupDetailVO(resourceId, key, value, display));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -58,6 +58,7 @@ public class BackupOfferingDaoImpl extends GenericDaoBase<BackupOfferingVO, Long
|
|||||||
response.setName(offering.getName());
|
response.setName(offering.getName());
|
||||||
response.setDescription(offering.getDescription());
|
response.setDescription(offering.getDescription());
|
||||||
response.setExternalId(offering.getExternalId());
|
response.setExternalId(offering.getExternalId());
|
||||||
|
response.setProvider(offering.getProvider());
|
||||||
response.setUserDrivenBackups(offering.isUserDrivenBackupAllowed());
|
response.setUserDrivenBackups(offering.isUserDrivenBackupAllowed());
|
||||||
if (zone != null) {
|
if (zone != null) {
|
||||||
response.setZoneId(zone.getUuid());
|
response.setZoneId(zone.getUuid());
|
||||||
|
|||||||
@ -28,4 +28,6 @@ public interface BackupRepositoryDao extends GenericDao<BackupRepositoryVO, Long
|
|||||||
List<BackupRepository> listByZoneAndProvider(Long zoneId, String provider);
|
List<BackupRepository> listByZoneAndProvider(Long zoneId, String provider);
|
||||||
|
|
||||||
BackupRepository findByBackupOfferingId(Long backupOfferingId);
|
BackupRepository findByBackupOfferingId(Long backupOfferingId);
|
||||||
|
|
||||||
|
boolean updateCapacity(BackupRepository backupRepository, Long capacityBytes, Long usedBytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,4 +64,12 @@ public class BackupRepositoryDaoImpl extends GenericDaoBase<BackupRepositoryVO,
|
|||||||
}
|
}
|
||||||
return findByUuid(offering.getExternalId());
|
return findByUuid(offering.getExternalId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateCapacity(BackupRepository backupRepository, Long capacityBytes, Long usedBytes) {
|
||||||
|
BackupRepositoryVO repository = findById(backupRepository.getId());
|
||||||
|
repository.setCapacityBytes(capacityBytes);
|
||||||
|
repository.setUsedBytes(usedBytes);
|
||||||
|
return update(repository.getId(), repository);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,6 +99,9 @@ public class BackupScheduleDaoImpl extends GenericDaoBase<BackupScheduleVO, Long
|
|||||||
response.setSchedule(schedule.getSchedule());
|
response.setSchedule(schedule.getSchedule());
|
||||||
response.setTimezone(schedule.getTimezone());
|
response.setTimezone(schedule.getTimezone());
|
||||||
response.setMaxBackups(schedule.getMaxBackups());
|
response.setMaxBackups(schedule.getMaxBackups());
|
||||||
|
if (schedule.getQuiesceVM() != null) {
|
||||||
|
response.setQuiesceVM(schedule.getQuiesceVM());
|
||||||
|
}
|
||||||
response.setObjectName("backupschedule");
|
response.setObjectName("backupschedule");
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,4 +39,6 @@ public interface ObjectStoreDao extends GenericDao<ObjectStoreVO, Long> {
|
|||||||
ObjectStoreResponse setObjectStoreResponse(ObjectStoreResponse storeData, ObjectStoreVO store);
|
ObjectStoreResponse setObjectStoreResponse(ObjectStoreResponse storeData, ObjectStoreVO store);
|
||||||
|
|
||||||
Integer countAllObjectStores();
|
Integer countAllObjectStores();
|
||||||
|
|
||||||
|
Boolean updateAllocatedSize(ObjectStoreVO objectStoreVO, long delta);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,10 @@ package org.apache.cloudstack.storage.datastore.db;
|
|||||||
import com.cloud.utils.db.GenericDaoBase;
|
import com.cloud.utils.db.GenericDaoBase;
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import com.cloud.utils.db.Transaction;
|
||||||
|
import com.cloud.utils.db.TransactionCallback;
|
||||||
|
import com.cloud.utils.db.TransactionStatus;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.response.ObjectStoreResponse;
|
import org.apache.cloudstack.api.response.ObjectStoreResponse;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -142,6 +146,19 @@ public class ObjectStoreDaoImpl extends GenericDaoBase<ObjectStoreVO, Long> impl
|
|||||||
ObjectStoreResponse osResponse = new ObjectStoreResponse();
|
ObjectStoreResponse osResponse = new ObjectStoreResponse();
|
||||||
osResponse.setId(store.getUuid());
|
osResponse.setId(store.getUuid());
|
||||||
osResponse.setName(store.getName());
|
osResponse.setName(store.getName());
|
||||||
|
if (store.getTotalSize() != null && store.getTotalSize() != 0L) {
|
||||||
|
osResponse.setStorageTotal(store.getTotalSize());
|
||||||
|
}
|
||||||
|
if (store.getUsedSize() == null) {
|
||||||
|
osResponse.setStorageUsed(0L);
|
||||||
|
} else {
|
||||||
|
osResponse.setStorageUsed(store.getUsedSize());
|
||||||
|
}
|
||||||
|
if (store.getAllocatedSize() == null) {
|
||||||
|
osResponse.setStorageAllocated(0L);
|
||||||
|
} else {
|
||||||
|
osResponse.setStorageAllocated(store.getAllocatedSize());
|
||||||
|
}
|
||||||
osResponse.setProviderName(store.getProviderName());
|
osResponse.setProviderName(store.getProviderName());
|
||||||
String url = store.getUrl();
|
String url = store.getUrl();
|
||||||
osResponse.setUrl(url);
|
osResponse.setUrl(url);
|
||||||
@ -159,4 +176,19 @@ public class ObjectStoreDaoImpl extends GenericDaoBase<ObjectStoreVO, Long> impl
|
|||||||
SearchCriteria<ObjectStoreVO> sc = createSearchCriteria();
|
SearchCriteria<ObjectStoreVO> sc = createSearchCriteria();
|
||||||
return getCount(sc);
|
return getCount(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean updateAllocatedSize(ObjectStoreVO objectStoreVO, long delta) {
|
||||||
|
return Transaction.execute(new TransactionCallback<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean doInTransaction(final TransactionStatus status) {
|
||||||
|
if (objectStoreVO.getAllocatedSize() != null) {
|
||||||
|
objectStoreVO.setAllocatedSize(objectStoreVO.getAllocatedSize() + delta);
|
||||||
|
} else {
|
||||||
|
objectStoreVO.setAllocatedSize(delta);
|
||||||
|
}
|
||||||
|
return update(objectStoreVO.getId(), objectStoreVO);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,8 +60,11 @@ public class ObjectStoreVO implements ObjectStore {
|
|||||||
@Column(name = "total_size")
|
@Column(name = "total_size")
|
||||||
private Long totalSize;
|
private Long totalSize;
|
||||||
|
|
||||||
@Column(name = "used_bytes")
|
@Column(name = "used_size")
|
||||||
private Long usedBytes;
|
private Long usedSize;
|
||||||
|
|
||||||
|
@Column(name = "allocated_size")
|
||||||
|
private Long allocatedSize;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
Map<String, String> details;
|
Map<String, String> details;
|
||||||
@ -130,18 +133,26 @@ public class ObjectStoreVO implements ObjectStore {
|
|||||||
this.totalSize = totalSize;
|
this.totalSize = totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getUsedBytes() {
|
public Long getUsedSize() {
|
||||||
return usedBytes;
|
return usedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUsedBytes(Long usedBytes) {
|
public void setUsedSize(Long usedSize) {
|
||||||
this.usedBytes = usedBytes;
|
this.usedSize = usedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDetails(Map<String, String> details) {
|
public void setDetails(Map<String, String> details) {
|
||||||
this.details = details;
|
this.details = details;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getAllocatedSize() {
|
||||||
|
return allocatedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllocatedSize(Long allocatedSize) {
|
||||||
|
this.allocatedSize = allocatedSize;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("ObjectStore %s",
|
return String.format("ObjectStore %s",
|
||||||
|
|||||||
@ -271,6 +271,7 @@
|
|||||||
<bean id="annotationDaoImpl" class="org.apache.cloudstack.annotation.dao.AnnotationDaoImpl" />
|
<bean id="annotationDaoImpl" class="org.apache.cloudstack.annotation.dao.AnnotationDaoImpl" />
|
||||||
<bean id="backupScheduleDaoImpl" class="org.apache.cloudstack.backup.dao.BackupScheduleDaoImpl" />
|
<bean id="backupScheduleDaoImpl" class="org.apache.cloudstack.backup.dao.BackupScheduleDaoImpl" />
|
||||||
<bean id="backupDaoImpl" class="org.apache.cloudstack.backup.dao.BackupDaoImpl" />
|
<bean id="backupDaoImpl" class="org.apache.cloudstack.backup.dao.BackupDaoImpl" />
|
||||||
|
<bean id="backupDetailsDaoImpl" class="org.apache.cloudstack.backup.dao.BackupDetailsDaoImpl" />
|
||||||
<bean id="backupRepositoryDaoImpl" class="org.apache.cloudstack.backup.dao.BackupRepositoryDaoImpl" />
|
<bean id="backupRepositoryDaoImpl" class="org.apache.cloudstack.backup.dao.BackupRepositoryDaoImpl" />
|
||||||
<bean id="directDownloadCertificateDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateDaoImpl" />
|
<bean id="directDownloadCertificateDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateDaoImpl" />
|
||||||
<bean id="directDownloadCertificateHostMapDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateHostMapDaoImpl" />
|
<bean id="directDownloadCertificateHostMapDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateHostMapDaoImpl" />
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backup_schedule', 'max_backups', 'INT(8) UNSIGNED NOT NULL DEFAULT 0 COMMENT ''Maximum number of backups to be retained''');
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backup_schedule', 'max_backups', 'INT(8) UNSIGNED NOT NULL DEFAULT 0 COMMENT ''Maximum number of backups to be retained''');
|
||||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'backup_schedule_id', 'BIGINT(20) UNSIGNED');
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'backup_schedule_id', 'BIGINT(20) UNSIGNED');
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backup_schedule', 'quiescevm', 'tinyint(1) default NULL COMMENT "Quiesce VM before taking backup"');
|
||||||
|
|
||||||
-- Update default value for the config 'vm.network.nic.max.secondary.ipaddresses' (and value to default value if value is null)
|
-- Update default value for the config 'vm.network.nic.max.secondary.ipaddresses' (and value to default value if value is null)
|
||||||
UPDATE `cloud`.`configuration` SET default_value = '10' WHERE name = 'vm.network.nic.max.secondary.ipaddresses';
|
UPDATE `cloud`.`configuration` SET default_value = '10' WHERE name = 'vm.network.nic.max.secondary.ipaddresses';
|
||||||
@ -663,3 +664,84 @@ ALTER TABLE `cloud`.`networks` MODIFY COLUMN `cidr` varchar(255) DEFAULT NULL CO
|
|||||||
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `gateway` varchar(255) DEFAULT NULL COMMENT 'gateway(s) for this network configuration';
|
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `gateway` varchar(255) DEFAULT NULL COMMENT 'gateway(s) for this network configuration';
|
||||||
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `ip6_cidr` varchar(1024) DEFAULT NULL COMMENT 'IPv6 cidr(s) for this network';
|
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `ip6_cidr` varchar(1024) DEFAULT NULL COMMENT 'IPv6 cidr(s) for this network';
|
||||||
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `ip6_gateway` varchar(1024) DEFAULT NULL COMMENT 'IPv6 gateway(s) for this network';
|
ALTER TABLE `cloud`.`networks` MODIFY COLUMN `ip6_gateway` varchar(1024) DEFAULT NULL COMMENT 'IPv6 gateway(s) for this network';
|
||||||
|
|
||||||
|
-- Add columns name, description and backup_interval_type to backup table
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'name', 'VARCHAR(255) NULL COMMENT "name of the backup"');
|
||||||
|
UPDATE `cloud`.`backups` backup INNER JOIN `cloud`.`vm_instance` vm ON backup.vm_id = vm.id SET backup.name = vm.name;
|
||||||
|
ALTER TABLE `cloud`.`backups` MODIFY COLUMN `name` VARCHAR(255) NOT NULL;
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'description', 'VARCHAR(1024) COMMENT "description for the backup"');
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backups', 'backup_interval_type', 'int(5) COMMENT "type of backup, e.g. manual, recurring - hourly, daily, weekly or monthly"');
|
||||||
|
|
||||||
|
-- Create backup details table
|
||||||
|
CREATE TABLE IF NOT EXISTS `cloud`.`backup_details` (
|
||||||
|
`id` bigint unsigned NOT NULL auto_increment,
|
||||||
|
`backup_id` bigint unsigned NOT NULL COMMENT 'backup id',
|
||||||
|
`name` varchar(255) NOT NULL,
|
||||||
|
`value` TEXT NOT NULL,
|
||||||
|
`display` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Should detail be displayed to the end user',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
CONSTRAINT `fk_backup_details__backup_id` FOREIGN KEY `fk_backup_details__backup_id`(`backup_id`) REFERENCES `backups`(`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
-- Add diskOfferingId, deviceId, minIops and maxIops to backed_volumes in backups table
|
||||||
|
UPDATE `cloud`.`backups` b
|
||||||
|
INNER JOIN `cloud`.`vm_instance` vm ON b.vm_id = vm.id
|
||||||
|
SET b.backed_volumes = (
|
||||||
|
SELECT CONCAT("[",
|
||||||
|
GROUP_CONCAT(
|
||||||
|
CONCAT(
|
||||||
|
"{\"uuid\":\"", v.uuid, "\",",
|
||||||
|
"\"type\":\"", v.volume_type, "\",",
|
||||||
|
"\"size\":", v.`size`, ",",
|
||||||
|
"\"path\":\"", IFNULL(v.path, 'null'), "\",",
|
||||||
|
"\"deviceId\":", IFNULL(v.device_id, 'null'), ",",
|
||||||
|
"\"diskOfferingId\":\"", doff.uuid, "\",",
|
||||||
|
"\"minIops\":", IFNULL(v.min_iops, 'null'), ",",
|
||||||
|
"\"maxIops\":", IFNULL(v.max_iops, 'null'),
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
SEPARATOR ","
|
||||||
|
),
|
||||||
|
"]")
|
||||||
|
FROM `cloud`.`volumes` v
|
||||||
|
LEFT JOIN `cloud`.`disk_offering` doff ON v.disk_offering_id = doff.id
|
||||||
|
WHERE v.instance_id = vm.id
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Add diskOfferingId, deviceId, minIops and maxIops to backup_volumes in vm_instance table
|
||||||
|
UPDATE `cloud`.`vm_instance` vm
|
||||||
|
SET vm.backup_volumes = (
|
||||||
|
SELECT CONCAT("[",
|
||||||
|
GROUP_CONCAT(
|
||||||
|
CONCAT(
|
||||||
|
"{\"uuid\":\"", v.uuid, "\",",
|
||||||
|
"\"type\":\"", v.volume_type, "\",",
|
||||||
|
"\"size\":", v.`size`, ",",
|
||||||
|
"\"path\":\"", IFNULL(v.path, 'null'), "\",",
|
||||||
|
"\"deviceId\":", IFNULL(v.device_id, 'null'), ",",
|
||||||
|
"\"diskOfferingId\":\"", doff.uuid, "\",",
|
||||||
|
"\"minIops\":", IFNULL(v.min_iops, 'null'), ",",
|
||||||
|
"\"maxIops\":", IFNULL(v.max_iops, 'null'),
|
||||||
|
"}"
|
||||||
|
)
|
||||||
|
SEPARATOR ","
|
||||||
|
),
|
||||||
|
"]")
|
||||||
|
FROM `cloud`.`volumes` v
|
||||||
|
LEFT JOIN `cloud`.`disk_offering` doff ON v.disk_offering_id = doff.id
|
||||||
|
WHERE v.instance_id = vm.id
|
||||||
|
)
|
||||||
|
WHERE vm.backup_offering_id IS NOT NULL;
|
||||||
|
|
||||||
|
-- Add column allocated_size to object_store table. Rename column 'used_bytes' to 'used_size'
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.object_store', 'allocated_size', 'bigint unsigned COMMENT "allocated size in bytes"');
|
||||||
|
ALTER TABLE `cloud`.`object_store` CHANGE COLUMN `used_bytes` `used_size` BIGINT UNSIGNED COMMENT 'used size in bytes';
|
||||||
|
ALTER TABLE `cloud`.`object_store` MODIFY COLUMN `total_size` bigint unsigned COMMENT 'total size in bytes';
|
||||||
|
UPDATE `cloud`.`object_store`
|
||||||
|
JOIN (
|
||||||
|
SELECT object_store_id, SUM(quota) AS total_quota
|
||||||
|
FROM `cloud`.`bucket`
|
||||||
|
WHERE removed IS NULL
|
||||||
|
GROUP BY object_store_id
|
||||||
|
) buckets_quota_sum_view ON `object_store`.id = buckets_quota_sum_view.object_store_id
|
||||||
|
SET `object_store`.allocated_size = buckets_quota_sum_view.total_quota;
|
||||||
|
|||||||
@ -0,0 +1,73 @@
|
|||||||
|
// 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.dao;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.backup.BackupVO;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class BackupDaoImplTest {
|
||||||
|
@Spy
|
||||||
|
@InjectMocks
|
||||||
|
private BackupDaoImpl backupDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
BackupDetailsDao backupDetailsDao;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadDetails() {
|
||||||
|
Long backupId = 1L;
|
||||||
|
BackupVO backup = new BackupVO();
|
||||||
|
ReflectionTestUtils.setField(backup, "id", backupId);
|
||||||
|
Map<String, String> details = new HashMap<>();
|
||||||
|
details.put("key1", "value1");
|
||||||
|
details.put("key2", "value2");
|
||||||
|
|
||||||
|
Mockito.when(backupDetailsDao.listDetailsKeyPairs(backupId)).thenReturn(details);
|
||||||
|
|
||||||
|
backupDao.loadDetails(backup);
|
||||||
|
|
||||||
|
Assert.assertEquals(details, backup.getDetails());
|
||||||
|
Mockito.verify(backupDetailsDao).listDetailsKeyPairs(backupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSaveDetails() {
|
||||||
|
Long backupId = 1L;
|
||||||
|
BackupVO backup = new BackupVO();
|
||||||
|
ReflectionTestUtils.setField(backup, "id", backupId);
|
||||||
|
Map<String, String> details = new HashMap<>();
|
||||||
|
details.put("key1", "value1");
|
||||||
|
details.put("key2", "value2");
|
||||||
|
backup.setDetails(details);
|
||||||
|
|
||||||
|
backupDao.saveDetails(backup);
|
||||||
|
|
||||||
|
Mockito.verify(backupDetailsDao).saveDetails(Mockito.anyList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.cloudstack.storage.object.datastore;
|
package org.apache.cloudstack.storage.object.datastore;
|
||||||
|
|
||||||
|
import com.cloud.configuration.Resource;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailVO;
|
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailVO;
|
||||||
@ -44,6 +45,7 @@ public class ObjectStoreHelper {
|
|||||||
store.setUuid(UUID.randomUUID().toString());
|
store.setUuid(UUID.randomUUID().toString());
|
||||||
store.setUrl((String)params.get("url"));
|
store.setUrl((String)params.get("url"));
|
||||||
store.setName((String)params.get("name"));
|
store.setName((String)params.get("name"));
|
||||||
|
store.setTotalSize((Long)params.get("size") * Resource.ResourceType.bytesToGiB);
|
||||||
|
|
||||||
store = ObjectStoreDao.persist(store);
|
store = ObjectStoreDao.persist(store);
|
||||||
|
|
||||||
|
|||||||
@ -16,16 +16,23 @@
|
|||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.backup;
|
package org.apache.cloudstack.backup;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import com.cloud.configuration.Resource;
|
import com.cloud.offering.DiskOffering;
|
||||||
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
|
import com.cloud.storage.Volume;
|
||||||
|
import com.cloud.storage.VolumeVO;
|
||||||
|
import com.cloud.storage.dao.DiskOfferingDao;
|
||||||
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.storage.dao.VolumeDao;
|
import com.cloud.storage.dao.VolumeDao;
|
||||||
|
|
||||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||||
|
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
@ -35,12 +42,16 @@ import com.cloud.vm.VMInstanceVO;
|
|||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
|
||||||
public class DummyBackupProvider extends AdapterBase implements BackupProvider {
|
public class DummyBackupProvider extends AdapterBase implements BackupProvider {
|
||||||
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private BackupDao backupDao;
|
private BackupDao backupDao;
|
||||||
@Inject
|
@Inject
|
||||||
private VolumeDao volumeDao;
|
private VolumeDao volumeDao;
|
||||||
|
@Inject
|
||||||
|
private BackupManager backupManager;
|
||||||
|
@Inject
|
||||||
|
private StoragePoolHostDao storagePoolHostDao;
|
||||||
|
@Inject
|
||||||
|
private DiskOfferingDao diskOfferingDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -80,24 +91,39 @@ public class DummyBackupProvider extends AdapterBase implements BackupProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
|
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
|
||||||
logger.debug("Restoring volume {} from backup {} on the Dummy Backup Provider", volumeUuid, backup);
|
final VolumeVO volume = volumeDao.findByUuid(backupVolumeInfo.getUuid());
|
||||||
throw new CloudRuntimeException("Dummy plugin does not support this feature");
|
final StoragePoolHostVO dataStore = storagePoolHostDao.findByUuid(dataStoreUuid);
|
||||||
|
final DiskOffering diskOffering = diskOfferingDao.findByUuid(backupVolumeInfo.getDiskOfferingId());
|
||||||
|
|
||||||
|
logger.debug("Restoring volume {} from backup {} on the Dummy Backup Provider", backupVolumeInfo, backup);
|
||||||
|
|
||||||
|
VolumeVO restoredVolume = new VolumeVO(Volume.Type.DATADISK, null, backup.getZoneId(),
|
||||||
|
backup.getDomainId(), backup.getAccountId(), 0, null,
|
||||||
|
backup.getSize(), null, null, null);
|
||||||
|
String volumeUUID = UUID.randomUUID().toString();
|
||||||
|
String volumeName = volume != null ? volume.getName() : backupVolumeInfo.getUuid();
|
||||||
|
restoredVolume.setName("RestoredVol-" + volumeName);
|
||||||
|
restoredVolume.setProvisioningType(diskOffering.getProvisioningType());
|
||||||
|
restoredVolume.setUpdated(new Date());
|
||||||
|
restoredVolume.setUuid(volumeUUID);
|
||||||
|
restoredVolume.setRemoved(null);
|
||||||
|
restoredVolume.setDisplayVolume(true);
|
||||||
|
restoredVolume.setPoolId(dataStore.getPoolId());
|
||||||
|
restoredVolume.setPath(restoredVolume.getUuid());
|
||||||
|
restoredVolume.setState(Volume.State.Copying);
|
||||||
|
restoredVolume.setSize(backupVolumeInfo.getSize());
|
||||||
|
restoredVolume.setDiskOfferingId(diskOffering.getId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
volumeDao.persist(restoredVolume);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CloudRuntimeException("Unable to create restored volume due to: " + e);
|
||||||
|
}
|
||||||
|
return new Pair<>(true, volumeUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void syncBackupMetrics(Long zoneId) {
|
||||||
public Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<VirtualMachine> vms) {
|
|
||||||
final Map<VirtualMachine, Backup.Metric> metrics = new HashMap<>();
|
|
||||||
final Backup.Metric metric = new Backup.Metric(1000L, 100L);
|
|
||||||
if (vms == null || vms.isEmpty()) {
|
|
||||||
return metrics;
|
|
||||||
}
|
|
||||||
for (VirtualMachine vm : vms) {
|
|
||||||
if (vm != null) {
|
|
||||||
metrics.put(vm, metric);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return metrics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -106,7 +132,7 @@ public class DummyBackupProvider extends AdapterBase implements BackupProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm, Backup.Metric metric) {
|
public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,11 +144,11 @@ public class DummyBackupProvider extends AdapterBase implements BackupProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean willDeleteBackupsOnOfferingRemoval() {
|
public boolean willDeleteBackupsOnOfferingRemoval() {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, Backup> takeBackup(VirtualMachine vm) {
|
public Pair<Boolean, Backup> takeBackup(VirtualMachine vm, Boolean quiesceVM) {
|
||||||
logger.debug("Starting backup for VM {} on Dummy provider", vm);
|
logger.debug("Starting backup for VM {} on Dummy provider", vm);
|
||||||
|
|
||||||
BackupVO backup = new BackupVO();
|
BackupVO backup = new BackupVO();
|
||||||
@ -130,20 +156,50 @@ public class DummyBackupProvider extends AdapterBase implements BackupProvider {
|
|||||||
backup.setExternalId("dummy-external-id");
|
backup.setExternalId("dummy-external-id");
|
||||||
backup.setType("FULL");
|
backup.setType("FULL");
|
||||||
backup.setDate(new Date());
|
backup.setDate(new Date());
|
||||||
backup.setSize(1024000L);
|
long virtualSize = 0L;
|
||||||
backup.setProtectedSize(Resource.ResourceType.bytesToGiB);
|
for (final Volume volume: volumeDao.findByInstance(vm.getId())) {
|
||||||
|
if (Volume.State.Ready.equals(volume.getState())) {
|
||||||
|
virtualSize += volume.getSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backup.setSize(virtualSize);
|
||||||
|
backup.setProtectedSize(virtualSize);
|
||||||
backup.setStatus(Backup.Status.BackedUp);
|
backup.setStatus(Backup.Status.BackedUp);
|
||||||
backup.setBackupOfferingId(vm.getBackupOfferingId());
|
backup.setBackupOfferingId(vm.getBackupOfferingId());
|
||||||
backup.setAccountId(vm.getAccountId());
|
backup.setAccountId(vm.getAccountId());
|
||||||
backup.setDomainId(vm.getDomainId());
|
backup.setDomainId(vm.getDomainId());
|
||||||
backup.setZoneId(vm.getDataCenterId());
|
backup.setZoneId(vm.getDataCenterId());
|
||||||
backup.setBackedUpVolumes(BackupManagerImpl.createVolumeInfoFromVolumes(volumeDao.findByInstance(vm.getId())));
|
backup.setName(backupManager.getBackupNameFromVM(vm));
|
||||||
|
List<Volume> volumes = new ArrayList<>(volumeDao.findByInstance(vm.getId()));
|
||||||
|
backup.setBackedUpVolumes(backupManager.createVolumeInfoFromVolumes(volumes));
|
||||||
|
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
|
||||||
|
backup.setDetails(details);
|
||||||
|
|
||||||
backup = backupDao.persist(backup);
|
backup = backupDao.persist(backup);
|
||||||
return new Pair<>(true, backup);
|
return new Pair<>(true, backup);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteBackup(Backup backup, boolean forced) {
|
public boolean deleteBackup(Backup backup, boolean forced) {
|
||||||
|
return backupDao.remove(backup.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInstanceFromBackup() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<Long, Long> getBackupStorageStats(Long zoneId) {
|
||||||
|
return new Pair<>(8L * 1024 * 1024 * 1024, 10L * 1024 * 1024 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncBackupStorageStats(Long zoneId) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean restoreBackupToVM(VirtualMachine vm, Backup backup, String hostIp, String dataStoreUuid) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,12 +24,15 @@ import com.cloud.host.HostVO;
|
|||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.offering.DiskOffering;
|
||||||
|
import com.cloud.resource.ResourceManager;
|
||||||
import com.cloud.storage.ScopeType;
|
import com.cloud.storage.ScopeType;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.VolumeApiServiceImpl;
|
import com.cloud.storage.VolumeApiServiceImpl;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
|
import com.cloud.storage.dao.DiskOfferingDao;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.storage.dao.VolumeDao;
|
import com.cloud.storage.dao.VolumeDao;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
@ -50,7 +53,6 @@ import org.apache.cloudstack.framework.config.ConfigKey;
|
|||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
@ -63,7 +65,6 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -78,6 +79,9 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
@Inject
|
@Inject
|
||||||
private BackupRepositoryDao backupRepositoryDao;
|
private BackupRepositoryDao backupRepositoryDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BackupRepositoryService backupRepositoryService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private HostDao hostDao;
|
private HostDao hostDao;
|
||||||
|
|
||||||
@ -102,6 +106,15 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
@Inject
|
@Inject
|
||||||
private VMSnapshotDetailsDao vmSnapshotDetailsDao;
|
private VMSnapshotDetailsDao vmSnapshotDetailsDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
BackupManager backupManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ResourceManager resourceManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DiskOfferingDao diskOfferingDao;
|
||||||
|
|
||||||
protected Host getLastVMHypervisorHost(VirtualMachine vm) {
|
protected Host getLastVMHypervisorHost(VirtualMachine vm) {
|
||||||
Long hostId = vm.getLastHostId();
|
Long hostId = vm.getLastHostId();
|
||||||
if (hostId == null) {
|
if (hostId == null) {
|
||||||
@ -122,13 +135,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Try to find any Host in the zone
|
// Try to find any Host in the zone
|
||||||
for (final HostVO hostInZone : hostDao.listByDataCenterIdAndHypervisorType(host.getDataCenterId(), Hypervisor.HypervisorType.KVM)) {
|
return resourceManager.findOneRandomRunningHostByHypervisor(Hypervisor.HypervisorType.KVM, host.getDataCenterId());
|
||||||
if (hostInZone.getStatus() == Status.Up) {
|
|
||||||
LOG.debug("Found Host {} in zone {}", hostInZone, host.getDataCenterId());
|
|
||||||
return hostInZone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Host getVMHypervisorHost(VirtualMachine vm) {
|
protected Host getVMHypervisorHost(VirtualMachine vm) {
|
||||||
@ -150,7 +157,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, Backup> takeBackup(final VirtualMachine vm) {
|
public Pair<Boolean, Backup> takeBackup(final VirtualMachine vm, Boolean quiesceVM) {
|
||||||
final Host host = getVMHypervisorHost(vm);
|
final Host host = getVMHypervisorHost(vm);
|
||||||
|
|
||||||
final BackupRepository backupRepository = backupRepositoryDao.findByBackupOfferingId(vm.getBackupOfferingId());
|
final BackupRepository backupRepository = backupRepositoryDao.findByBackupOfferingId(vm.getBackupOfferingId());
|
||||||
@ -167,6 +174,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
command.setBackupRepoType(backupRepository.getType());
|
command.setBackupRepoType(backupRepository.getType());
|
||||||
command.setBackupRepoAddress(backupRepository.getAddress());
|
command.setBackupRepoAddress(backupRepository.getAddress());
|
||||||
command.setMountOptions(backupRepository.getMountOptions());
|
command.setMountOptions(backupRepository.getMountOptions());
|
||||||
|
command.setQuiesce(quiesceVM);
|
||||||
|
|
||||||
if (VirtualMachine.State.Stopped.equals(vm.getState())) {
|
if (VirtualMachine.State.Stopped.equals(vm.getState())) {
|
||||||
List<VolumeVO> vmVolumes = volumeDao.findByInstance(vm.getId());
|
List<VolumeVO> vmVolumes = volumeDao.findByInstance(vm.getId());
|
||||||
@ -179,8 +187,14 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
try {
|
try {
|
||||||
answer = (BackupAnswer) agentManager.send(host.getId(), command);
|
answer = (BackupAnswer) agentManager.send(host.getId(), command);
|
||||||
} catch (AgentUnavailableException e) {
|
} catch (AgentUnavailableException e) {
|
||||||
|
logger.error("Unable to contact backend control plane to initiate backup for VM {}", vm.getInstanceName());
|
||||||
|
backupVO.setStatus(Backup.Status.Failed);
|
||||||
|
backupDao.remove(backupVO.getId());
|
||||||
throw new CloudRuntimeException("Unable to contact backend control plane to initiate backup");
|
throw new CloudRuntimeException("Unable to contact backend control plane to initiate backup");
|
||||||
} catch (OperationTimedoutException e) {
|
} catch (OperationTimedoutException e) {
|
||||||
|
logger.error("Operation to initiate backup timed out for VM {}", vm.getInstanceName());
|
||||||
|
backupVO.setStatus(Backup.Status.Failed);
|
||||||
|
backupDao.remove(backupVO.getId());
|
||||||
throw new CloudRuntimeException("Operation to initiate backup timed out, please try again");
|
throw new CloudRuntimeException("Operation to initiate backup timed out, please try again");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,15 +202,23 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
backupVO.setDate(new Date());
|
backupVO.setDate(new Date());
|
||||||
backupVO.setSize(answer.getSize());
|
backupVO.setSize(answer.getSize());
|
||||||
backupVO.setStatus(Backup.Status.BackedUp);
|
backupVO.setStatus(Backup.Status.BackedUp);
|
||||||
backupVO.setBackedUpVolumes(BackupManagerImpl.createVolumeInfoFromVolumes(volumeDao.findByInstance(vm.getId())));
|
List<Volume> volumes = new ArrayList<>(volumeDao.findByInstance(vm.getId()));
|
||||||
|
backupVO.setBackedUpVolumes(backupManager.createVolumeInfoFromVolumes(volumes));
|
||||||
if (backupDao.update(backupVO.getId(), backupVO)) {
|
if (backupDao.update(backupVO.getId(), backupVO)) {
|
||||||
return new Pair<>(true, backupVO);
|
return new Pair<>(true, backupVO);
|
||||||
} else {
|
} else {
|
||||||
throw new CloudRuntimeException("Failed to update backup");
|
throw new CloudRuntimeException("Failed to update backup");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
backupVO.setStatus(Backup.Status.Failed);
|
logger.error("Failed to take backup for VM {}: {}", vm.getInstanceName(), answer != null ? answer.getDetails() : "No answer received");
|
||||||
backupDao.remove(backupVO.getId());
|
if (answer.getNeedsCleanup()) {
|
||||||
|
logger.error("Backup cleanup failed for VM {}. Leaving the backup in Error state.", vm.getInstanceName());
|
||||||
|
backupVO.setStatus(Backup.Status.Error);
|
||||||
|
backupDao.update(backupVO.getId(), backupVO);
|
||||||
|
} else {
|
||||||
|
backupVO.setStatus(Backup.Status.Failed);
|
||||||
|
backupDao.remove(backupVO.getId());
|
||||||
|
}
|
||||||
return new Pair<>(false, null);
|
return new Pair<>(false, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,19 +241,35 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
backup.setAccountId(vm.getAccountId());
|
backup.setAccountId(vm.getAccountId());
|
||||||
backup.setDomainId(vm.getDomainId());
|
backup.setDomainId(vm.getDomainId());
|
||||||
backup.setZoneId(vm.getDataCenterId());
|
backup.setZoneId(vm.getDataCenterId());
|
||||||
|
backup.setName(backupManager.getBackupNameFromVM(vm));
|
||||||
|
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
|
||||||
|
backup.setDetails(details);
|
||||||
|
|
||||||
return backupDao.persist(backup);
|
return backupDao.persist(backup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean restoreBackupToVM(VirtualMachine vm, Backup backup, String hostIp, String dataStoreUuid) {
|
||||||
|
return restoreVMBackup(vm, backup);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
|
public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
|
||||||
List<Backup.VolumeInfo> backedVolumes = backup.getBackedUpVolumes();
|
return restoreVMBackup(vm, backup);
|
||||||
List<VolumeVO> volumes = backedVolumes.stream()
|
}
|
||||||
.map(volume -> volumeDao.findByUuid(volume.getUuid()))
|
|
||||||
.sorted((v1, v2) -> Long.compare(v1.getDeviceId(), v2.getDeviceId()))
|
private boolean restoreVMBackup(VirtualMachine vm, Backup backup) {
|
||||||
|
List<String> backedVolumesUUIDs = backup.getBackedUpVolumes().stream()
|
||||||
|
.sorted(Comparator.comparingLong(Backup.VolumeInfo::getDeviceId))
|
||||||
|
.map(Backup.VolumeInfo::getUuid)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<VolumeVO> restoreVolumes = volumeDao.findByInstance(vm.getId()).stream()
|
||||||
|
.sorted(Comparator.comparingLong(VolumeVO::getDeviceId))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
LOG.debug("Restoring vm {} from backup {} on the NAS Backup Provider", vm, backup);
|
LOG.debug("Restoring vm {} from backup {} on the NAS Backup Provider", vm, backup);
|
||||||
BackupRepository backupRepository = getBackupRepository(vm, backup);
|
BackupRepository backupRepository = getBackupRepository(backup);
|
||||||
|
|
||||||
final Host host = getLastVMHypervisorHost(vm);
|
final Host host = getLastVMHypervisorHost(vm);
|
||||||
RestoreBackupCommand restoreCommand = new RestoreBackupCommand();
|
RestoreBackupCommand restoreCommand = new RestoreBackupCommand();
|
||||||
@ -240,7 +278,8 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
|
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
|
||||||
restoreCommand.setMountOptions(backupRepository.getMountOptions());
|
restoreCommand.setMountOptions(backupRepository.getMountOptions());
|
||||||
restoreCommand.setVmName(vm.getName());
|
restoreCommand.setVmName(vm.getName());
|
||||||
restoreCommand.setVolumePaths(getVolumePaths(volumes));
|
restoreCommand.setBackupVolumesUUIDs(backedVolumesUUIDs);
|
||||||
|
restoreCommand.setRestoreVolumePaths(getVolumePaths(restoreVolumes));
|
||||||
restoreCommand.setVmExists(vm.getRemoved() == null);
|
restoreCommand.setVmExists(vm.getRemoved() == null);
|
||||||
restoreCommand.setVmState(vm.getState());
|
restoreCommand.setVmState(vm.getState());
|
||||||
|
|
||||||
@ -250,7 +289,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
} catch (AgentUnavailableException e) {
|
} catch (AgentUnavailableException e) {
|
||||||
throw new CloudRuntimeException("Unable to contact backend control plane to initiate backup");
|
throw new CloudRuntimeException("Unable to contact backend control plane to initiate backup");
|
||||||
} catch (OperationTimedoutException e) {
|
} catch (OperationTimedoutException e) {
|
||||||
throw new CloudRuntimeException("Operation to initiate backup timed out, please try again");
|
throw new CloudRuntimeException("Operation to restore backup timed out, please try again");
|
||||||
}
|
}
|
||||||
return answer.getResult();
|
return answer.getResult();
|
||||||
}
|
}
|
||||||
@ -276,24 +315,22 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
|
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
|
||||||
final VolumeVO volume = volumeDao.findByUuid(volumeUuid);
|
final VolumeVO volume = volumeDao.findByUuid(backupVolumeInfo.getUuid());
|
||||||
final VirtualMachine backupSourceVm = vmInstanceDao.findById(backup.getVmId());
|
final DiskOffering diskOffering = diskOfferingDao.findByUuid(backupVolumeInfo.getDiskOfferingId());
|
||||||
final StoragePoolHostVO dataStore = storagePoolHostDao.findByUuid(dataStoreUuid);
|
final StoragePoolHostVO dataStore = storagePoolHostDao.findByUuid(dataStoreUuid);
|
||||||
final HostVO hostVO = hostDao.findByIp(hostIp);
|
final HostVO hostVO = hostDao.findByIp(hostIp);
|
||||||
|
|
||||||
Optional<Backup.VolumeInfo> matchingVolume = getBackedUpVolumeInfo(backupSourceVm.getBackupVolumeList(), volumeUuid);
|
LOG.debug("Restoring vm volume {} from backup {} on the NAS Backup Provider", backupVolumeInfo, backup);
|
||||||
Long backedUpVolumeSize = matchingVolume.isPresent() ? matchingVolume.get().getSize() : 0L;
|
BackupRepository backupRepository = getBackupRepository(backup);
|
||||||
|
|
||||||
LOG.debug("Restoring vm volume {} from backup {} on the NAS Backup Provider", volume, backup);
|
|
||||||
BackupRepository backupRepository = getBackupRepository(backupSourceVm, backup);
|
|
||||||
|
|
||||||
VolumeVO restoredVolume = new VolumeVO(Volume.Type.DATADISK, null, backup.getZoneId(),
|
VolumeVO restoredVolume = new VolumeVO(Volume.Type.DATADISK, null, backup.getZoneId(),
|
||||||
backup.getDomainId(), backup.getAccountId(), 0, null,
|
backup.getDomainId(), backup.getAccountId(), 0, null,
|
||||||
backup.getSize(), null, null, null);
|
backup.getSize(), null, null, null);
|
||||||
String volumeUUID = UUID.randomUUID().toString();
|
String volumeUUID = UUID.randomUUID().toString();
|
||||||
restoredVolume.setName("RestoredVol-"+volume.getName());
|
String volumeName = volume != null ? volume.getName() : backupVolumeInfo.getUuid();
|
||||||
restoredVolume.setProvisioningType(volume.getProvisioningType());
|
restoredVolume.setName("RestoredVol-" + volumeName);
|
||||||
|
restoredVolume.setProvisioningType(diskOffering.getProvisioningType());
|
||||||
restoredVolume.setUpdated(new Date());
|
restoredVolume.setUpdated(new Date());
|
||||||
restoredVolume.setUuid(volumeUUID);
|
restoredVolume.setUuid(volumeUUID);
|
||||||
restoredVolume.setRemoved(null);
|
restoredVolume.setRemoved(null);
|
||||||
@ -302,20 +339,20 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
restoredVolume.setPath(restoredVolume.getUuid());
|
restoredVolume.setPath(restoredVolume.getUuid());
|
||||||
restoredVolume.setState(Volume.State.Copying);
|
restoredVolume.setState(Volume.State.Copying);
|
||||||
restoredVolume.setFormat(Storage.ImageFormat.QCOW2);
|
restoredVolume.setFormat(Storage.ImageFormat.QCOW2);
|
||||||
restoredVolume.setSize(backedUpVolumeSize);
|
restoredVolume.setSize(backupVolumeInfo.getSize());
|
||||||
restoredVolume.setDiskOfferingId(volume.getDiskOfferingId());
|
restoredVolume.setDiskOfferingId(diskOffering.getId());
|
||||||
|
|
||||||
RestoreBackupCommand restoreCommand = new RestoreBackupCommand();
|
RestoreBackupCommand restoreCommand = new RestoreBackupCommand();
|
||||||
restoreCommand.setBackupPath(backup.getExternalId());
|
restoreCommand.setBackupPath(backup.getExternalId());
|
||||||
restoreCommand.setBackupRepoType(backupRepository.getType());
|
restoreCommand.setBackupRepoType(backupRepository.getType());
|
||||||
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
|
restoreCommand.setBackupRepoAddress(backupRepository.getAddress());
|
||||||
restoreCommand.setVmName(vmNameAndState.first());
|
restoreCommand.setVmName(vmNameAndState.first());
|
||||||
restoreCommand.setVolumePaths(Collections.singletonList(String.format("%s/%s", dataStore.getLocalPath(), volumeUUID)));
|
restoreCommand.setRestoreVolumePaths(Collections.singletonList(String.format("%s/%s", dataStore.getLocalPath(), volumeUUID)));
|
||||||
restoreCommand.setDiskType(volume.getVolumeType().name().toLowerCase(Locale.ROOT));
|
restoreCommand.setDiskType(backupVolumeInfo.getType().name().toLowerCase(Locale.ROOT));
|
||||||
restoreCommand.setMountOptions(backupRepository.getMountOptions());
|
restoreCommand.setMountOptions(backupRepository.getMountOptions());
|
||||||
restoreCommand.setVmExists(null);
|
restoreCommand.setVmExists(null);
|
||||||
restoreCommand.setVmState(vmNameAndState.second());
|
restoreCommand.setVmState(vmNameAndState.second());
|
||||||
restoreCommand.setRestoreVolumeUUID(volumeUuid);
|
restoreCommand.setRestoreVolumeUUID(backupVolumeInfo.getUuid());
|
||||||
|
|
||||||
BackupAnswer answer;
|
BackupAnswer answer;
|
||||||
try {
|
try {
|
||||||
@ -323,7 +360,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
} catch (AgentUnavailableException e) {
|
} catch (AgentUnavailableException e) {
|
||||||
throw new CloudRuntimeException("Unable to contact backend control plane to initiate backup");
|
throw new CloudRuntimeException("Unable to contact backend control plane to initiate backup");
|
||||||
} catch (OperationTimedoutException e) {
|
} catch (OperationTimedoutException e) {
|
||||||
throw new CloudRuntimeException("Operation to initiate backup timed out, please try again");
|
throw new CloudRuntimeException("Operation to restore backed up volume timed out, please try again");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (answer.getResult()) {
|
if (answer.getResult()) {
|
||||||
@ -337,15 +374,10 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
return new Pair<>(answer.getResult(), answer.getDetails());
|
return new Pair<>(answer.getResult(), answer.getDetails());
|
||||||
}
|
}
|
||||||
|
|
||||||
private BackupRepository getBackupRepository(VirtualMachine vm, Backup backup) {
|
private BackupRepository getBackupRepository(Backup backup) {
|
||||||
BackupRepository backupRepository = backupRepositoryDao.findByBackupOfferingId(vm.getBackupOfferingId());
|
BackupRepository backupRepository = backupRepositoryDao.findByBackupOfferingId(backup.getBackupOfferingId());
|
||||||
final String errorMessage = "No valid backup repository found for the VM, please check the attached backup offering";
|
|
||||||
if (backupRepository == null) {
|
if (backupRepository == null) {
|
||||||
logger.warn(errorMessage + "Re-attempting with the backup offering associated with the backup");
|
throw new CloudRuntimeException(String.format("No valid backup repository found for the backup %s, please check the attached backup offering", backup.getUuid()));
|
||||||
}
|
|
||||||
backupRepository = backupRepositoryDao.findByBackupOfferingId(backup.getBackupOfferingId());
|
|
||||||
if (backupRepository == null) {
|
|
||||||
throw new CloudRuntimeException(errorMessage);
|
|
||||||
}
|
}
|
||||||
return backupRepository;
|
return backupRepository;
|
||||||
}
|
}
|
||||||
@ -363,8 +395,13 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
throw new CloudRuntimeException("No valid backup repository found for the VM, please check the attached backup offering");
|
throw new CloudRuntimeException("No valid backup repository found for the VM, please check the attached backup offering");
|
||||||
}
|
}
|
||||||
|
|
||||||
final VirtualMachine vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
|
final Host host;
|
||||||
final Host host = getLastVMHypervisorHost(vm);
|
final VirtualMachine vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
|
||||||
|
if (vm != null) {
|
||||||
|
host = getLastVMHypervisorHost(vm);
|
||||||
|
} else {
|
||||||
|
host = resourceManager.findOneRandomRunningHostByHypervisor(Hypervisor.HypervisorType.KVM, backup.getZoneId());
|
||||||
|
}
|
||||||
|
|
||||||
DeleteBackupCommand command = new DeleteBackupCommand(backup.getExternalId(), backupRepository.getType(),
|
DeleteBackupCommand command = new DeleteBackupCommand(backup.getExternalId(), backupRepository.getType(),
|
||||||
backupRepository.getAddress(), backupRepository.getMountOptions());
|
backupRepository.getAddress(), backupRepository.getMountOptions());
|
||||||
@ -375,7 +412,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
} catch (AgentUnavailableException e) {
|
} catch (AgentUnavailableException e) {
|
||||||
throw new CloudRuntimeException("Unable to contact backend control plane to initiate backup");
|
throw new CloudRuntimeException("Unable to contact backend control plane to initiate backup");
|
||||||
} catch (OperationTimedoutException e) {
|
} catch (OperationTimedoutException e) {
|
||||||
throw new CloudRuntimeException("Operation to initiate backup timed out, please try again");
|
throw new CloudRuntimeException("Operation to delete backup timed out, please try again");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (answer != null && answer.getResult()) {
|
if (answer != null && answer.getResult()) {
|
||||||
@ -386,30 +423,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void syncBackupMetrics(Long zoneId) {
|
||||||
public Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<VirtualMachine> vms) {
|
|
||||||
final Map<VirtualMachine, Backup.Metric> metrics = new HashMap<>();
|
|
||||||
if (CollectionUtils.isEmpty(vms)) {
|
|
||||||
LOG.warn("Unable to get VM Backup Metrics because the list of VMs is empty.");
|
|
||||||
return metrics;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final VirtualMachine vm : vms) {
|
|
||||||
Long vmBackupSize = 0L;
|
|
||||||
Long vmBackupProtectedSize = 0L;
|
|
||||||
for (final Backup backup: backupDao.listByVmId(null, vm.getId())) {
|
|
||||||
if (Objects.nonNull(backup.getSize())) {
|
|
||||||
vmBackupSize += backup.getSize();
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(backup.getProtectedSize())) {
|
|
||||||
vmBackupProtectedSize += backup.getProtectedSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Backup.Metric vmBackupMetric = new Backup.Metric(vmBackupSize,vmBackupProtectedSize);
|
|
||||||
LOG.debug("Metrics for VM {} is [backup size: {}, data size: {}].", vm, vmBackupMetric.getBackupSize(), vmBackupMetric.getDataSize());
|
|
||||||
metrics.put(vm, vmBackupMetric);
|
|
||||||
}
|
|
||||||
return metrics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -418,7 +432,7 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm, Backup.Metric metric) {
|
public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,6 +459,45 @@ public class NASBackupProvider extends AdapterBase implements BackupProvider, Co
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInstanceFromBackup() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<Long, Long> getBackupStorageStats(Long zoneId) {
|
||||||
|
final List<BackupRepository> repositories = backupRepositoryDao.listByZoneAndProvider(zoneId, getName());
|
||||||
|
Long totalSize = 0L;
|
||||||
|
Long usedSize = 0L;
|
||||||
|
for (final BackupRepository repository : repositories) {
|
||||||
|
if (repository.getCapacityBytes() != null) {
|
||||||
|
totalSize += repository.getCapacityBytes();
|
||||||
|
}
|
||||||
|
if (repository.getUsedBytes() != null) {
|
||||||
|
usedSize += repository.getUsedBytes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Pair<>(usedSize, totalSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncBackupStorageStats(Long zoneId) {
|
||||||
|
final List<BackupRepository> repositories = backupRepositoryDao.listByZoneAndProvider(zoneId, getName());
|
||||||
|
final Host host = resourceManager.findOneRandomRunningHostByHypervisor(Hypervisor.HypervisorType.KVM, zoneId);
|
||||||
|
for (final BackupRepository repository : repositories) {
|
||||||
|
GetBackupStorageStatsCommand command = new GetBackupStorageStatsCommand(repository.getType(), repository.getAddress(), repository.getMountOptions());
|
||||||
|
BackupStorageStatsAnswer answer;
|
||||||
|
try {
|
||||||
|
answer = (BackupStorageStatsAnswer) agentManager.send(host.getId(), command);
|
||||||
|
backupRepositoryDao.updateCapacity(repository, answer.getTotalSize(), answer.getUsedSize());
|
||||||
|
} catch (AgentUnavailableException e) {
|
||||||
|
logger.warn("Unable to contact backend control plane to get backup stats for repository: {}", repository.getName());
|
||||||
|
} catch (OperationTimedoutException e) {
|
||||||
|
logger.warn("Operation to get backup stats timed out for the repository: " + repository.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BackupOffering> listBackupOfferings(Long zoneId) {
|
public List<BackupOffering> listBackupOfferings(Long zoneId) {
|
||||||
final List<BackupRepository> repositories = backupRepositoryDao.listByZoneAndProvider(zoneId, getName());
|
final List<BackupRepository> repositories = backupRepositoryDao.listByZoneAndProvider(zoneId, getName());
|
||||||
|
|||||||
@ -0,0 +1,230 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
package org.apache.cloudstack.backup;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||||
|
import org.apache.cloudstack.backup.dao.BackupRepositoryDao;
|
||||||
|
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import com.cloud.agent.AgentManager;
|
||||||
|
import com.cloud.exception.AgentUnavailableException;
|
||||||
|
import com.cloud.exception.OperationTimedoutException;
|
||||||
|
import com.cloud.host.HostVO;
|
||||||
|
import com.cloud.host.Status;
|
||||||
|
import com.cloud.host.dao.HostDao;
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.resource.ResourceManager;
|
||||||
|
import com.cloud.storage.Volume;
|
||||||
|
import com.cloud.storage.VolumeVO;
|
||||||
|
import com.cloud.storage.dao.VolumeDao;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.vm.VMInstanceVO;
|
||||||
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class NASBackupProviderTest {
|
||||||
|
@Spy
|
||||||
|
@InjectMocks
|
||||||
|
private NASBackupProvider nasBackupProvider;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private BackupDao backupDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private BackupRepositoryDao backupRepositoryDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private BackupOfferingDao backupOfferingDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private VMInstanceDao vmInstanceDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AgentManager agentManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private VolumeDao volumeDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HostDao hostDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private BackupManager backupManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ResourceManager resourceManager;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteBackup() throws OperationTimedoutException, AgentUnavailableException {
|
||||||
|
Long hostId = 1L;
|
||||||
|
BackupVO backup = new BackupVO();
|
||||||
|
backup.setBackupOfferingId(1L);
|
||||||
|
backup.setVmId(1L);
|
||||||
|
backup.setExternalId("externalId");
|
||||||
|
ReflectionTestUtils.setField(backup, "id", 1L);
|
||||||
|
|
||||||
|
BackupRepositoryVO backupRepository = new BackupRepositoryVO(1L, "nas", "test-repo",
|
||||||
|
"nfs", "address", "sync", 1024L);
|
||||||
|
|
||||||
|
VMInstanceVO vm = mock(VMInstanceVO.class);
|
||||||
|
Mockito.when(vm.getLastHostId()).thenReturn(hostId);
|
||||||
|
HostVO host = mock(HostVO.class);
|
||||||
|
Mockito.when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
Mockito.when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
Mockito.when(backupRepositoryDao.findByBackupOfferingId(1L)).thenReturn(backupRepository);
|
||||||
|
Mockito.when(vmInstanceDao.findByIdIncludingRemoved(1L)).thenReturn(vm);
|
||||||
|
Mockito.when(agentManager.send(anyLong(), Mockito.any(DeleteBackupCommand.class))).thenReturn(new BackupAnswer(new DeleteBackupCommand(null, null, null, null), true, "details"));
|
||||||
|
Mockito.when(backupDao.remove(1L)).thenReturn(true);
|
||||||
|
|
||||||
|
boolean result = nasBackupProvider.deleteBackup(backup, true);
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSyncBackupStorageStats() throws AgentUnavailableException, OperationTimedoutException {
|
||||||
|
BackupRepositoryVO backupRepository = new BackupRepositoryVO(1L, "nas", "test-repo",
|
||||||
|
"nfs", "address", "sync", 1024L);
|
||||||
|
|
||||||
|
HostVO host = mock(HostVO.class);
|
||||||
|
Mockito.when(resourceManager.findOneRandomRunningHostByHypervisor(Hypervisor.HypervisorType.KVM, 1L)).thenReturn(host);
|
||||||
|
|
||||||
|
Mockito.when(backupRepositoryDao.listByZoneAndProvider(1L, "nas")).thenReturn(Collections.singletonList(backupRepository));
|
||||||
|
GetBackupStorageStatsCommand command = new GetBackupStorageStatsCommand("nfs", "address", "sync");
|
||||||
|
BackupStorageStatsAnswer answer = new BackupStorageStatsAnswer(command, true, null);
|
||||||
|
answer.setTotalSize(100L);
|
||||||
|
answer.setUsedSize(50L);
|
||||||
|
Mockito.when(agentManager.send(anyLong(), Mockito.any(GetBackupStorageStatsCommand.class))).thenReturn(answer);
|
||||||
|
|
||||||
|
nasBackupProvider.syncBackupStorageStats(1L);
|
||||||
|
Mockito.verify(backupRepositoryDao, Mockito.times(1)).updateCapacity(backupRepository, 100L, 50L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListBackupOfferings() {
|
||||||
|
BackupRepositoryVO backupRepository = new BackupRepositoryVO(1L, "nas", "test-repo",
|
||||||
|
"nfs", "address", "sync", 1024L);
|
||||||
|
ReflectionTestUtils.setField(backupRepository, "uuid", "uuid");
|
||||||
|
|
||||||
|
Mockito.when(backupRepositoryDao.listByZoneAndProvider(1L, "nas")).thenReturn(Collections.singletonList(backupRepository));
|
||||||
|
|
||||||
|
List<BackupOffering> result = nasBackupProvider.listBackupOfferings(1L);
|
||||||
|
Assert.assertEquals(1, result.size());
|
||||||
|
Assert.assertEquals("test-repo", result.get(0).getName());
|
||||||
|
Assert.assertEquals("uuid", result.get(0).getUuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBackupStorageStats() {
|
||||||
|
BackupRepositoryVO backupRepository1 = new BackupRepositoryVO(1L, "nas", "test-repo",
|
||||||
|
"nfs", "address", "sync", 1000L);
|
||||||
|
backupRepository1.setUsedBytes(500L);
|
||||||
|
|
||||||
|
BackupRepositoryVO backupRepository2 = new BackupRepositoryVO(1L, "nas", "test-repo",
|
||||||
|
"nfs", "address", "sync", 2000L);
|
||||||
|
backupRepository2.setUsedBytes(600L);
|
||||||
|
|
||||||
|
Mockito.when(backupRepositoryDao.listByZoneAndProvider(1L, "nas"))
|
||||||
|
.thenReturn(List.of(backupRepository1, backupRepository2));
|
||||||
|
|
||||||
|
Pair<Long, Long> result = nasBackupProvider.getBackupStorageStats(1L);
|
||||||
|
Assert.assertEquals(Long.valueOf(1100L), result.first());
|
||||||
|
Assert.assertEquals(Long.valueOf(3000L), result.second());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void takeBackupSuccessfully() throws AgentUnavailableException, OperationTimedoutException {
|
||||||
|
Long vmId = 1L;
|
||||||
|
Long hostId = 2L;
|
||||||
|
Long backupOfferingId = 3L;
|
||||||
|
Long accountId = 4L;
|
||||||
|
Long domainId = 5L;
|
||||||
|
Long zoneId = 6L;
|
||||||
|
Long backupId = 7L;
|
||||||
|
|
||||||
|
VMInstanceVO vm = mock(VMInstanceVO.class);
|
||||||
|
Mockito.when(vm.getId()).thenReturn(vmId);
|
||||||
|
Mockito.when(vm.getHostId()).thenReturn(hostId);
|
||||||
|
Mockito.when(vm.getInstanceName()).thenReturn("test-vm");
|
||||||
|
Mockito.when(vm.getBackupOfferingId()).thenReturn(backupOfferingId);
|
||||||
|
Mockito.when(vm.getAccountId()).thenReturn(accountId);
|
||||||
|
Mockito.when(vm.getDomainId()).thenReturn(domainId);
|
||||||
|
Mockito.when(vm.getDataCenterId()).thenReturn(zoneId);
|
||||||
|
Mockito.when(vm.getState()).thenReturn(VMInstanceVO.State.Running);
|
||||||
|
|
||||||
|
BackupRepository backupRepository = mock(BackupRepository.class);
|
||||||
|
Mockito.when(backupRepository.getType()).thenReturn("nfs");
|
||||||
|
Mockito.when(backupRepository.getAddress()).thenReturn("address");
|
||||||
|
Mockito.when(backupRepository.getMountOptions()).thenReturn("sync");
|
||||||
|
Mockito.when(backupRepositoryDao.findByBackupOfferingId(backupOfferingId)).thenReturn(backupRepository);
|
||||||
|
|
||||||
|
HostVO host = mock(HostVO.class);
|
||||||
|
Mockito.when(host.getId()).thenReturn(hostId);
|
||||||
|
Mockito.when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
Mockito.when(host.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
|
||||||
|
Mockito.when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
VolumeVO volume1 = mock(VolumeVO.class);
|
||||||
|
Mockito.when(volume1.getState()).thenReturn(Volume.State.Ready);
|
||||||
|
Mockito.when(volume1.getSize()).thenReturn(100L);
|
||||||
|
VolumeVO volume2 = mock(VolumeVO.class);
|
||||||
|
Mockito.when(volume2.getState()).thenReturn(Volume.State.Ready);
|
||||||
|
Mockito.when(volume2.getSize()).thenReturn(200L);
|
||||||
|
Mockito.when(volumeDao.findByInstance(vmId)).thenReturn(List.of(volume1, volume2));
|
||||||
|
|
||||||
|
BackupAnswer answer = mock(BackupAnswer.class);
|
||||||
|
Mockito.when(answer.getResult()).thenReturn(true);
|
||||||
|
Mockito.when(answer.getSize()).thenReturn(100L);
|
||||||
|
Mockito.when(agentManager.send(anyLong(), Mockito.any(TakeBackupCommand.class))).thenReturn(answer);
|
||||||
|
|
||||||
|
Mockito.when(backupDao.persist(Mockito.any(BackupVO.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||||
|
Mockito.when(backupDao.update(Mockito.anyLong(), Mockito.any(BackupVO.class))).thenReturn(true);
|
||||||
|
|
||||||
|
Pair<Boolean, Backup> result = nasBackupProvider.takeBackup(vm, false);
|
||||||
|
|
||||||
|
Assert.assertTrue(result.first());
|
||||||
|
Assert.assertNotNull(result.second());
|
||||||
|
BackupVO backup = (BackupVO) result.second();
|
||||||
|
Assert.assertEquals(Optional.ofNullable(100L), Optional.ofNullable(backup.getSize()));
|
||||||
|
Assert.assertEquals(Backup.Status.BackedUp, backup.getStatus());
|
||||||
|
Assert.assertEquals("FULL", backup.getType());
|
||||||
|
Assert.assertEquals(Optional.of(300L), Optional.of(backup.getProtectedSize()));
|
||||||
|
Assert.assertEquals(Optional.of(backupOfferingId), Optional.of(backup.getBackupOfferingId()));
|
||||||
|
Assert.assertEquals(Optional.of(accountId), Optional.of(backup.getAccountId()));
|
||||||
|
Assert.assertEquals(Optional.of(domainId), Optional.of(backup.getDomainId()));
|
||||||
|
Assert.assertEquals(Optional.of(zoneId), Optional.of(backup.getZoneId()));
|
||||||
|
|
||||||
|
Mockito.verify(backupDao).persist(Mockito.any(BackupVO.class));
|
||||||
|
Mockito.verify(backupDao).update(Mockito.anyLong(), Mockito.any(BackupVO.class));
|
||||||
|
Mockito.verify(agentManager).send(anyLong(), Mockito.any(TakeBackupCommand.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -21,21 +21,27 @@ import com.cloud.host.HostVO;
|
|||||||
import com.cloud.host.Status;
|
import com.cloud.host.Status;
|
||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.offering.DiskOffering;
|
||||||
|
import com.cloud.offering.ServiceOffering;
|
||||||
|
import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
|
import com.cloud.storage.dao.DiskOfferingDao;
|
||||||
|
import com.cloud.storage.dao.VMTemplateDao;
|
||||||
import com.cloud.utils.script.Script;
|
import com.cloud.utils.script.Script;
|
||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.storage.dao.VolumeDao;
|
import com.cloud.storage.dao.VolumeDao;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.Ternary;
|
import com.cloud.utils.Ternary;
|
||||||
import com.cloud.utils.component.AdapterBase;
|
import com.cloud.utils.component.AdapterBase;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
import com.cloud.utils.ssh.SshHelper;
|
import com.cloud.utils.ssh.SshHelper;
|
||||||
import com.cloud.vm.VMInstanceVO;
|
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||||
import org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl;
|
import org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl;
|
||||||
import org.apache.cloudstack.backup.networker.NetworkerClient;
|
import org.apache.cloudstack.backup.networker.NetworkerClient;
|
||||||
@ -116,6 +122,18 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
@Inject
|
@Inject
|
||||||
private VMInstanceDao vmInstanceDao;
|
private VMInstanceDao vmInstanceDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private VMTemplateDao vmTemplateDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ServiceOfferingDao serviceOfferingDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private BackupManager backupManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DiskOfferingDao diskOfferingDao;
|
||||||
|
|
||||||
private static String getUrlDomain(String url) throws URISyntaxException {
|
private static String getUrlDomain(String url) throws URISyntaxException {
|
||||||
URI uri;
|
URI uri;
|
||||||
try {
|
try {
|
||||||
@ -371,10 +389,10 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
|
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
|
||||||
String networkerServer;
|
String networkerServer;
|
||||||
VolumeVO volume = volumeDao.findByUuid(volumeUuid);
|
VolumeVO volume = volumeDao.findByUuid(backupVolumeInfo.getUuid());
|
||||||
VMInstanceVO backupSourceVm = vmInstanceDao.findById(backup.getVmId());
|
final DiskOffering diskOffering = diskOfferingDao.findByUuid(backupVolumeInfo.getDiskOfferingId());
|
||||||
StoragePoolHostVO dataStore = storagePoolHostDao.findByUuid(dataStoreUuid);
|
StoragePoolHostVO dataStore = storagePoolHostDao.findByUuid(dataStoreUuid);
|
||||||
HostVO hostVO = hostDao.findByIp(hostIp);
|
HostVO hostVO = hostDao.findByIp(hostIp);
|
||||||
|
|
||||||
@ -384,9 +402,8 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
final String SSID = networkerBackup.getShortId();
|
final String SSID = networkerBackup.getShortId();
|
||||||
final String clusterName = networkerBackup.getClientHostname();
|
final String clusterName = networkerBackup.getClientHostname();
|
||||||
final String destinationNetworkerClient = hostVO.getName().split("\\.")[0];
|
final String destinationNetworkerClient = hostVO.getName().split("\\.")[0];
|
||||||
Long restoredVolumeDiskSize = 0L;
|
|
||||||
|
|
||||||
LOG.debug("Restoring volume {} with uuid {} from backup {} on the Networker Backup Provider", volume, volumeUuid, backup);
|
LOG.debug("Restoring volume {} with uuid {} from backup {} on the Networker Backup Provider", volume, backupVolumeInfo, backup);
|
||||||
|
|
||||||
if ( SSID.isEmpty() ) {
|
if ( SSID.isEmpty() ) {
|
||||||
LOG.debug("There was an error retrieving the SSID for backup with id " + externalBackupId + " from EMC NEtworker");
|
LOG.debug("There was an error retrieving the SSID for backup with id " + externalBackupId + " from EMC NEtworker");
|
||||||
@ -401,18 +418,13 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
throw new CloudRuntimeException(String.format("Failed to convert API to HOST : %s", e));
|
throw new CloudRuntimeException(String.format("Failed to convert API to HOST : %s", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find volume size from backup vols
|
|
||||||
for ( Backup.VolumeInfo VMVolToRestore : backupSourceVm.getBackupVolumeList()) {
|
|
||||||
if (VMVolToRestore.getUuid().equals(volumeUuid))
|
|
||||||
restoredVolumeDiskSize = (VMVolToRestore.getSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
VolumeVO restoredVolume = new VolumeVO(Volume.Type.DATADISK, null, backup.getZoneId(),
|
VolumeVO restoredVolume = new VolumeVO(Volume.Type.DATADISK, null, backup.getZoneId(),
|
||||||
backup.getDomainId(), backup.getAccountId(), 0, null,
|
backup.getDomainId(), backup.getAccountId(), 0, null,
|
||||||
backup.getSize(), null, null, null);
|
backup.getSize(), null, null, null);
|
||||||
|
|
||||||
restoredVolume.setName("RV-"+volume.getName());
|
String volumeName = volume != null ? volume.getName() : backupVolumeInfo.getUuid();
|
||||||
restoredVolume.setProvisioningType(volume.getProvisioningType());
|
restoredVolume.setName("RV-" + volumeName);
|
||||||
|
restoredVolume.setProvisioningType(diskOffering.getProvisioningType());
|
||||||
restoredVolume.setUpdated(new Date());
|
restoredVolume.setUpdated(new Date());
|
||||||
restoredVolume.setUuid(UUID.randomUUID().toString());
|
restoredVolume.setUuid(UUID.randomUUID().toString());
|
||||||
restoredVolume.setRemoved(null);
|
restoredVolume.setRemoved(null);
|
||||||
@ -420,8 +432,8 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
restoredVolume.setPoolId(volume.getPoolId());
|
restoredVolume.setPoolId(volume.getPoolId());
|
||||||
restoredVolume.setPath(restoredVolume.getUuid());
|
restoredVolume.setPath(restoredVolume.getUuid());
|
||||||
restoredVolume.setState(Volume.State.Copying);
|
restoredVolume.setState(Volume.State.Copying);
|
||||||
restoredVolume.setSize(restoredVolumeDiskSize);
|
restoredVolume.setSize(backupVolumeInfo.getSize());
|
||||||
restoredVolume.setDiskOfferingId(volume.getDiskOfferingId());
|
restoredVolume.setDiskOfferingId(diskOffering.getId());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
volumeDao.persist(restoredVolume);
|
volumeDao.persist(restoredVolume);
|
||||||
@ -461,7 +473,7 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, Backup> takeBackup(VirtualMachine vm) {
|
public Pair<Boolean, Backup> takeBackup(VirtualMachine vm, Boolean quiesceVM) {
|
||||||
String networkerServer;
|
String networkerServer;
|
||||||
String clusterName;
|
String clusterName;
|
||||||
|
|
||||||
@ -511,7 +523,10 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
LOG.info("EMC Networker finished backup job for vm {} with saveset Time: {}", vm, saveTime);
|
LOG.info("EMC Networker finished backup job for vm {} with saveset Time: {}", vm, saveTime);
|
||||||
BackupVO backup = getClient(vm.getDataCenterId()).registerBackupForVm(vm, backupJobStart, saveTime);
|
BackupVO backup = getClient(vm.getDataCenterId()).registerBackupForVm(vm, backupJobStart, saveTime);
|
||||||
if (backup != null) {
|
if (backup != null) {
|
||||||
backup.setBackedUpVolumes(BackupManagerImpl.createVolumeInfoFromVolumes(volumeDao.findByInstance(vm.getId())));
|
List<Volume> volumes = new ArrayList<>(volumeDao.findByInstance(vm.getId()));
|
||||||
|
backup.setBackedUpVolumes(backupManager.createVolumeInfoFromVolumes(volumes));
|
||||||
|
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
|
||||||
|
backup.setDetails(details);
|
||||||
backupDao.persist(backup);
|
backupDao.persist(backup);
|
||||||
return new Pair<>(true, backup);
|
return new Pair<>(true, backup);
|
||||||
} else {
|
} else {
|
||||||
@ -536,35 +551,11 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void syncBackupMetrics(Long zoneId) {
|
||||||
public Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<VirtualMachine> vms) {
|
|
||||||
final Map<VirtualMachine, Backup.Metric> metrics = new HashMap<>();
|
|
||||||
long vmBackupSize=0L;
|
|
||||||
long vmBackupProtectedSize=0L;
|
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(vms)) {
|
|
||||||
LOG.warn("Unable to get VM Backup Metrics because the list of VMs is empty.");
|
|
||||||
return metrics;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final VirtualMachine vm : vms) {
|
|
||||||
for ( Backup.VolumeInfo thisVMVol : vm.getBackupVolumeList()) {
|
|
||||||
vmBackupProtectedSize += (thisVMVol.getSize() / 1024L / 1024L);
|
|
||||||
}
|
|
||||||
final ArrayList<String> vmBackups = getClient(zoneId).getBackupsForVm(vm);
|
|
||||||
for ( String vmBackup : vmBackups ) {
|
|
||||||
NetworkerBackup vmNwBackup = getClient(zoneId).getNetworkerBackupInfo(vmBackup);
|
|
||||||
vmBackupSize += vmNwBackup.getSize().getValue() / 1024L;
|
|
||||||
}
|
|
||||||
Backup.Metric vmBackupMetric = new Backup.Metric(vmBackupSize,vmBackupProtectedSize);
|
|
||||||
LOG.debug(String.format("Metrics for VM [%s] is [backup size: %s, data size: %s].", vm, vmBackupMetric.getBackupSize(), vmBackupMetric.getDataSize()));
|
|
||||||
metrics.put(vm, vmBackupMetric);
|
|
||||||
}
|
|
||||||
return metrics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm, Backup.Metric metric) {
|
public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm) {
|
||||||
// Technically an administrator can manually create a backup for a VM by utilizing the KVM scripts
|
// Technically an administrator can manually create a backup for a VM by utilizing the KVM scripts
|
||||||
// with the proper parameters. So we will register any backups taken on the Networker side from
|
// with the proper parameters. So we will register any backups taken on the Networker side from
|
||||||
// outside Cloudstack. If ever Networker will support KVM out of the box this functionality also will
|
// outside Cloudstack. If ever Networker will support KVM out of the box this functionality also will
|
||||||
@ -597,6 +588,16 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
backup.setAccountId(vm.getAccountId());
|
backup.setAccountId(vm.getAccountId());
|
||||||
backup.setDomainId(vm.getDomainId());
|
backup.setDomainId(vm.getDomainId());
|
||||||
backup.setZoneId(vm.getDataCenterId());
|
backup.setZoneId(vm.getDataCenterId());
|
||||||
|
backup.setName(backupManager.getBackupNameFromVM(vm));
|
||||||
|
|
||||||
|
HashMap<String, String> details = new HashMap<>();
|
||||||
|
details.put(ApiConstants.HYPERVISOR, vm.getHypervisorType().toString());
|
||||||
|
ServiceOffering serviceOffering = serviceOfferingDao.findById(vm.getServiceOfferingId());
|
||||||
|
details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOffering.getUuid());
|
||||||
|
VirtualMachineTemplate template = vmTemplateDao.findById(vm.getTemplateId());
|
||||||
|
details.put(ApiConstants.TEMPLATE_ID, template.getUuid());
|
||||||
|
backup.setDetails(details);
|
||||||
|
|
||||||
backupDao.persist(backup);
|
backupDao.persist(backup);
|
||||||
return backup;
|
return backup;
|
||||||
}
|
}
|
||||||
@ -611,6 +612,25 @@ public class NetworkerBackupProvider extends AdapterBase implements BackupProvid
|
|||||||
return backupIds.stream().map(id -> new Backup.RestorePoint(id, null, null)).collect(Collectors.toList());
|
return backupIds.stream().map(id -> new Backup.RestorePoint(id, null, null)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInstanceFromBackup() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<Long, Long> getBackupStorageStats(Long zoneId) {
|
||||||
|
return new Pair<>(0L, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncBackupStorageStats(Long zoneId) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean willDeleteBackupsOnOfferingRemoval() { return false; }
|
public boolean willDeleteBackupsOnOfferingRemoval() { return false; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean restoreBackupToVM(VirtualMachine vm, Backup backup, String hostIp, String dataStoreUuid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.apache.cloudstack.api.ApiErrorCode;
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
import org.apache.cloudstack.api.ServerApiException;
|
import org.apache.cloudstack.api.ServerApiException;
|
||||||
|
import org.apache.cloudstack.backup.BackupManager;
|
||||||
import org.apache.cloudstack.backup.BackupOffering;
|
import org.apache.cloudstack.backup.BackupOffering;
|
||||||
import org.apache.cloudstack.backup.BackupVO;
|
import org.apache.cloudstack.backup.BackupVO;
|
||||||
import org.apache.cloudstack.backup.networker.api.NetworkerBackup;
|
import org.apache.cloudstack.backup.networker.api.NetworkerBackup;
|
||||||
@ -45,6 +46,7 @@ import org.apache.http.impl.client.HttpClientBuilder;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -65,6 +67,9 @@ import java.util.List;
|
|||||||
import static org.apache.cloudstack.backup.NetworkerBackupProvider.BACKUP_IDENTIFIER;
|
import static org.apache.cloudstack.backup.NetworkerBackupProvider.BACKUP_IDENTIFIER;
|
||||||
|
|
||||||
public class NetworkerClient {
|
public class NetworkerClient {
|
||||||
|
@Inject
|
||||||
|
BackupManager backupManager;
|
||||||
|
|
||||||
private static final Logger LOG = LogManager.getLogger(NetworkerClient.class);
|
private static final Logger LOG = LogManager.getLogger(NetworkerClient.class);
|
||||||
private final URI apiURI;
|
private final URI apiURI;
|
||||||
private final String apiName;
|
private final String apiName;
|
||||||
@ -267,6 +272,8 @@ public class NetworkerClient {
|
|||||||
backup.setAccountId(vm.getAccountId());
|
backup.setAccountId(vm.getAccountId());
|
||||||
backup.setDomainId(vm.getDomainId());
|
backup.setDomainId(vm.getDomainId());
|
||||||
backup.setZoneId(vm.getDataCenterId());
|
backup.setZoneId(vm.getDataCenterId());
|
||||||
|
backup.setName(backupManager.getBackupNameFromVM(vm));
|
||||||
|
|
||||||
return backup;
|
return backup;
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
LOG.error("Failed to register backup from EMC Networker due to:", e);
|
LOG.error("Failed to register backup from EMC Networker due to:", e);
|
||||||
|
|||||||
@ -30,8 +30,11 @@ import java.text.SimpleDateFormat;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.cloud.vm.VMInstanceVO;
|
import com.cloud.vm.VMInstanceVO;
|
||||||
import com.github.tomakehurst.wiremock.client.VerificationException;
|
import com.github.tomakehurst.wiremock.client.VerificationException;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.backup.BackupManager;
|
||||||
import org.apache.cloudstack.backup.BackupOffering;
|
import org.apache.cloudstack.backup.BackupOffering;
|
||||||
import org.apache.cloudstack.backup.BackupVO;
|
import org.apache.cloudstack.backup.BackupVO;
|
||||||
import org.apache.cloudstack.backup.networker.NetworkerClient;
|
import org.apache.cloudstack.backup.networker.NetworkerClient;
|
||||||
@ -40,6 +43,9 @@ import org.junit.Assert;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import com.github.tomakehurst.wiremock.client.BasicCredentials;
|
import com.github.tomakehurst.wiremock.client.BasicCredentials;
|
||||||
import com.github.tomakehurst.wiremock.junit.WireMockRule;
|
import com.github.tomakehurst.wiremock.junit.WireMockRule;
|
||||||
|
|
||||||
@ -58,6 +64,7 @@ public class NetworkerClientTest {
|
|||||||
.willReturn(aResponse()
|
.willReturn(aResponse()
|
||||||
.withStatus(200)));
|
.withStatus(200)));
|
||||||
client = new NetworkerClient(url, adminUsername, adminPassword, false, 60);
|
client = new NetworkerClient(url, adminUsername, adminPassword, false, 60);
|
||||||
|
ReflectionTestUtils.setField(client, "backupManager", Mockito.mock(BackupManager.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -24,12 +24,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.apache.cloudstack.backup.Backup.Metric;
|
|
||||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||||
import org.apache.cloudstack.backup.veeam.VeeamClient;
|
import org.apache.cloudstack.backup.veeam.VeeamClient;
|
||||||
import org.apache.cloudstack.backup.veeam.api.Job;
|
import org.apache.cloudstack.backup.veeam.api.Job;
|
||||||
@ -45,6 +42,7 @@ import com.cloud.dc.VmwareDatacenter;
|
|||||||
import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap;
|
import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap;
|
||||||
import com.cloud.dc.dao.VmwareDatacenterDao;
|
import com.cloud.dc.dao.VmwareDatacenterDao;
|
||||||
import com.cloud.hypervisor.vmware.dao.VmwareDatacenterZoneMapDao;
|
import com.cloud.hypervisor.vmware.dao.VmwareDatacenterZoneMapDao;
|
||||||
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.dao.VolumeDao;
|
import com.cloud.storage.dao.VolumeDao;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.component.AdapterBase;
|
import com.cloud.utils.component.AdapterBase;
|
||||||
@ -102,8 +100,12 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
|
|||||||
@Inject
|
@Inject
|
||||||
private VirtualMachineManager virtualMachineManager;
|
private VirtualMachineManager virtualMachineManager;
|
||||||
@Inject
|
@Inject
|
||||||
|
private BackupManager backupManager;
|
||||||
|
@Inject
|
||||||
private VolumeDao volumeDao;
|
private VolumeDao volumeDao;
|
||||||
|
|
||||||
|
private Map<String, Backup.Metric> backupFilesMetricsMap = new HashMap<>();
|
||||||
|
|
||||||
protected VeeamClient getClient(final Long zoneId) {
|
protected VeeamClient getClient(final Long zoneId) {
|
||||||
try {
|
try {
|
||||||
return new VeeamClient(VeeamUrl.valueIn(zoneId), VeeamVersion.valueIn(zoneId), VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId),
|
return new VeeamClient(VeeamUrl.valueIn(zoneId), VeeamVersion.valueIn(zoneId), VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId),
|
||||||
@ -213,11 +215,11 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean willDeleteBackupsOnOfferingRemoval() {
|
public boolean willDeleteBackupsOnOfferingRemoval() {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, Backup> takeBackup(final VirtualMachine vm) {
|
public Pair<Boolean, Backup> takeBackup(final VirtualMachine vm, Boolean quiesceVM) {
|
||||||
final VeeamClient client = getClient(vm.getDataCenterId());
|
final VeeamClient client = getClient(vm.getDataCenterId());
|
||||||
Boolean result = client.startBackupJob(vm.getBackupExternalId());
|
Boolean result = client.startBackupJob(vm.getBackupExternalId());
|
||||||
return new Pair<>(result, null);
|
return new Pair<>(result, null);
|
||||||
@ -244,7 +246,7 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
|
|||||||
|
|
||||||
client.syncBackupRepository();
|
client.syncBackupRepository();
|
||||||
|
|
||||||
List<Backup> allBackups = backupDao.listByVmId(backup.getZoneId(), backup.getVmId());
|
List<Backup> allBackups = backupDao.listByVmIdAndOffering(backup.getZoneId(), backup.getVmId(), backup.getBackupOfferingId());
|
||||||
for (Backup b : allBackups) {
|
for (Backup b : allBackups) {
|
||||||
if (b.getId() != backup.getId()) {
|
if (b.getId() != backup.getId()) {
|
||||||
backupDao.remove(b.getId());
|
backupDao.remove(b.getId());
|
||||||
@ -289,62 +291,71 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
|
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, Backup.VolumeInfo backupVolumeInfo, String hostIp, String dataStoreUuid, Pair<String, VirtualMachine.State> vmNameAndState) {
|
||||||
final Long zoneId = backup.getZoneId();
|
final Long zoneId = backup.getZoneId();
|
||||||
final String restorePointId = backup.getExternalId();
|
final String restorePointId = backup.getExternalId();
|
||||||
return getClient(zoneId).restoreVMToDifferentLocation(restorePointId, hostIp, dataStoreUuid);
|
return getClient(zoneId).restoreVMToDifferentLocation(restorePointId, null, hostIp, dataStoreUuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<VirtualMachine, Backup.Metric> getBackupMetrics(final Long zoneId, final List<VirtualMachine> vms) {
|
public void syncBackupMetrics(Long zoneId) {
|
||||||
final Map<VirtualMachine, Backup.Metric> metrics = new HashMap<>();
|
backupFilesMetricsMap = getClient(zoneId).getBackupMetrics();
|
||||||
if (CollectionUtils.isEmpty(vms)) {
|
|
||||||
logger.warn("Unable to get VM Backup Metrics because the list of VMs is empty.");
|
|
||||||
return metrics;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> vmUuids = vms.stream().filter(Objects::nonNull).map(VirtualMachine::getUuid).collect(Collectors.toList());
|
|
||||||
logger.debug(String.format("Get Backup Metrics for VMs: [%s].", String.join(", ", vmUuids)));
|
|
||||||
|
|
||||||
final Map<String, Backup.Metric> backendMetrics = getClient(zoneId).getBackupMetrics();
|
|
||||||
for (final VirtualMachine vm : vms) {
|
|
||||||
if (vm == null || !backendMetrics.containsKey(vm.getUuid())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Metric metric = backendMetrics.get(vm.getUuid());
|
|
||||||
logger.debug("Metrics for VM [{}] is [backup size: {}, data size: {}].", vm,
|
|
||||||
metric.getBackupSize(), metric.getDataSize());
|
|
||||||
metrics.put(vm, metric);
|
|
||||||
}
|
|
||||||
return metrics;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm, Backup.Metric metric) {
|
public Backup createNewBackupEntryForRestorePoint(Backup.RestorePoint restorePoint, VirtualMachine vm) {
|
||||||
BackupVO backup = new BackupVO();
|
BackupVO backup = new BackupVO();
|
||||||
backup.setVmId(vm.getId());
|
backup.setVmId(vm.getId());
|
||||||
backup.setExternalId(restorePoint.getId());
|
backup.setExternalId(restorePoint.getId());
|
||||||
backup.setType(restorePoint.getType());
|
backup.setType(restorePoint.getType());
|
||||||
backup.setDate(restorePoint.getCreated());
|
backup.setDate(restorePoint.getCreated());
|
||||||
backup.setStatus(Backup.Status.BackedUp);
|
backup.setStatus(Backup.Status.BackedUp);
|
||||||
if (metric != null) {
|
if (restorePoint.getBackupSize() != null) {
|
||||||
backup.setSize(metric.getBackupSize());
|
backup.setSize(restorePoint.getBackupSize());
|
||||||
backup.setProtectedSize(metric.getDataSize());
|
}
|
||||||
|
if (restorePoint.getDataSize() != null) {
|
||||||
|
backup.setProtectedSize(restorePoint.getDataSize());
|
||||||
}
|
}
|
||||||
backup.setBackupOfferingId(vm.getBackupOfferingId());
|
backup.setBackupOfferingId(vm.getBackupOfferingId());
|
||||||
backup.setAccountId(vm.getAccountId());
|
backup.setAccountId(vm.getAccountId());
|
||||||
backup.setDomainId(vm.getDomainId());
|
backup.setDomainId(vm.getDomainId());
|
||||||
backup.setZoneId(vm.getDataCenterId());
|
backup.setZoneId(vm.getDataCenterId());
|
||||||
backup.setBackedUpVolumes(BackupManagerImpl.createVolumeInfoFromVolumes(volumeDao.findByInstance(vm.getId())));
|
backup.setName(backupManager.getBackupNameFromVM(vm));
|
||||||
|
List<Volume> volumes = new ArrayList<>(volumeDao.findByInstance(vm.getId()));
|
||||||
|
backup.setBackedUpVolumes(backupManager.createVolumeInfoFromVolumes(volumes));
|
||||||
|
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
|
||||||
|
backup.setDetails(details);
|
||||||
backupDao.persist(backup);
|
backupDao.persist(backup);
|
||||||
return backup;
|
return backup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Backup.RestorePoint> listRestorePoints(VirtualMachine vm) {
|
public List<Backup.RestorePoint> listRestorePoints(VirtualMachine vm) {
|
||||||
|
final VmwareDatacenter vmwareDC = findVmwareDatacenterForVM(vm);
|
||||||
String backupName = getGuestBackupName(vm.getInstanceName(), vm.getUuid());
|
String backupName = getGuestBackupName(vm.getInstanceName(), vm.getUuid());
|
||||||
return getClient(vm.getDataCenterId()).listRestorePoints(backupName, vm.getInstanceName());
|
return getClient(vm.getDataCenterId()).listRestorePoints(backupName, vmwareDC.getVcenterHost(), vm.getInstanceName(), backupFilesMetricsMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean restoreBackupToVM(VirtualMachine vm, Backup backup, String hostIp, String dataStoreUuid) {
|
||||||
|
final Long zoneId = backup.getZoneId();
|
||||||
|
final String restorePointId = backup.getExternalId();
|
||||||
|
final String restoreLocation = vm.getInstanceName();
|
||||||
|
return getClient(zoneId).restoreVMToDifferentLocation(restorePointId, restoreLocation, hostIp, dataStoreUuid).first();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsInstanceFromBackup() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pair<Long, Long> getBackupStorageStats(Long zoneId) {
|
||||||
|
return new Pair<>(0L, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncBackupStorageStats(Long zoneId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -17,8 +17,6 @@
|
|||||||
|
|
||||||
package org.apache.cloudstack.backup.veeam;
|
package org.apache.cloudstack.backup.veeam;
|
||||||
|
|
||||||
import static org.apache.cloudstack.backup.VeeamBackupProvider.BACKUP_IDENTIFIER;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
@ -109,7 +107,6 @@ public class VeeamClient {
|
|||||||
private static final String BACKUP_FILE_REFERENCE = "BackupFileReference";
|
private static final String BACKUP_FILE_REFERENCE = "BackupFileReference";
|
||||||
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
|
||||||
|
|
||||||
private String veeamServerIp;
|
private String veeamServerIp;
|
||||||
private final Integer veeamServerVersion;
|
private final Integer veeamServerVersion;
|
||||||
private String veeamServerUsername;
|
private String veeamServerUsername;
|
||||||
@ -659,9 +656,7 @@ public class VeeamClient {
|
|||||||
public boolean deleteJobAndBackup(final String jobName) {
|
public boolean deleteJobAndBackup(final String jobName) {
|
||||||
Pair<Boolean, String> result = executePowerShellCommands(Arrays.asList(
|
Pair<Boolean, String> result = executePowerShellCommands(Arrays.asList(
|
||||||
String.format("$job = Get-VBRJob -Name '%s'", jobName),
|
String.format("$job = Get-VBRJob -Name '%s'", jobName),
|
||||||
"if ($job) { Remove-VBRJob -Job $job -Confirm:$false }",
|
"if ($job) { Remove-VBRJob -Job $job -Confirm:$false }"
|
||||||
String.format("$backup = Get-VBRBackup -Name '%s'", jobName),
|
|
||||||
"if ($backup) { Remove-VBRBackup -Backup $backup -FromDisk -Confirm:$false }"
|
|
||||||
));
|
));
|
||||||
return result != null && result.first() && !result.second().contains(FAILED_TO_DELETE);
|
return result != null && result.first() && !result.second().contains(FAILED_TO_DELETE);
|
||||||
}
|
}
|
||||||
@ -721,40 +716,19 @@ public class VeeamClient {
|
|||||||
throw new CloudRuntimeException("Could not get backup metrics via Veeam B&R API");
|
throw new CloudRuntimeException("Could not get backup metrics via Veeam B&R API");
|
||||||
}
|
}
|
||||||
for (final BackupFile backupFile : backupFiles.getBackupFiles()) {
|
for (final BackupFile backupFile : backupFiles.getBackupFiles()) {
|
||||||
String vmUuid = null;
|
String backupFileId = StringUtils.substringAfterLast(backupFile.getUid(), ":");
|
||||||
String backupName = null;
|
if (backupFileId.isEmpty()) {
|
||||||
List<Link> links = backupFile.getLink();
|
|
||||||
for (Link link : links) {
|
|
||||||
if (BACKUP_REFERENCE.equals(link.getType())) {
|
|
||||||
backupName = link.getName();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (backupName != null && backupName.contains(BACKUP_IDENTIFIER)) {
|
|
||||||
final String[] names = backupName.split(BACKUP_IDENTIFIER);
|
|
||||||
if (names.length > 1) {
|
|
||||||
vmUuid = names[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (vmUuid == null) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (vmUuid.contains(" - ")) {
|
Long backupSize = null;
|
||||||
vmUuid = vmUuid.split(" - ")[0];
|
Long dataSize = null;
|
||||||
}
|
|
||||||
Long usedSize = 0L;
|
|
||||||
Long dataSize = 0L;
|
|
||||||
if (metrics.containsKey(vmUuid)) {
|
|
||||||
usedSize = metrics.get(vmUuid).getBackupSize();
|
|
||||||
dataSize = metrics.get(vmUuid).getDataSize();
|
|
||||||
}
|
|
||||||
if (backupFile.getBackupSize() != null) {
|
if (backupFile.getBackupSize() != null) {
|
||||||
usedSize += Long.valueOf(backupFile.getBackupSize());
|
backupSize = Long.valueOf(backupFile.getBackupSize());
|
||||||
}
|
}
|
||||||
if (backupFile.getDataSize() != null) {
|
if (backupFile.getDataSize() != null) {
|
||||||
dataSize += Long.valueOf(backupFile.getDataSize());
|
dataSize = Long.valueOf(backupFile.getDataSize());
|
||||||
}
|
}
|
||||||
metrics.put(vmUuid, new Backup.Metric(usedSize, dataSize));
|
metrics.put(backupFileId, new Backup.Metric(backupSize, dataSize));
|
||||||
}
|
}
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
logger.error("Failed to process response to get backup metrics via Veeam B&R API due to:", e);
|
logger.error("Failed to process response to get backup metrics via Veeam B&R API due to:", e);
|
||||||
@ -768,23 +742,14 @@ public class VeeamClient {
|
|||||||
final List<String> cmds = Arrays.asList(
|
final List<String> cmds = Arrays.asList(
|
||||||
"$backups = Get-VBRBackup",
|
"$backups = Get-VBRBackup",
|
||||||
"foreach ($backup in $backups) {" +
|
"foreach ($backup in $backups) {" +
|
||||||
" $backup.JobName;" +
|
" $restorePoints = Get-VBRRestorePoint -Backup $backup;" +
|
||||||
" $storageGroups = $backup.GetStorageGroups();" +
|
" foreach ($restorePoint in $restorePoints) {" +
|
||||||
" foreach ($group in $storageGroups) {" +
|
" $backupFile = $restorePoint.GetStorage();" +
|
||||||
" $usedSize = 0;" +
|
" $restorePoint.Id.Guid;" +
|
||||||
" $dataSize = 0;" +
|
" $backupFile.Stats.BackupSize;" +
|
||||||
" $sizePerStorage = $group.GetStorages().Stats.BackupSize;" +
|
" $backupFile.Stats.DataSize;" +
|
||||||
" $dataPerStorage = $group.GetStorages().Stats.DataSize;" +
|
" echo \"" + separator + "\";" +
|
||||||
" foreach ($size in $sizePerStorage) {" +
|
|
||||||
" $usedSize += $size;" +
|
|
||||||
" }" +
|
|
||||||
" foreach ($size in $dataPerStorage) {" +
|
|
||||||
" $dataSize += $size;" +
|
|
||||||
" }" +
|
|
||||||
" $usedSize;" +
|
|
||||||
" $dataSize;" +
|
|
||||||
" }" +
|
" }" +
|
||||||
" echo \"" + separator + "\"" +
|
|
||||||
"}"
|
"}"
|
||||||
);
|
);
|
||||||
Pair<Boolean, String> response = executePowerShellCommands(cmds);
|
Pair<Boolean, String> response = executePowerShellCommands(cmds);
|
||||||
@ -796,24 +761,22 @@ public class VeeamClient {
|
|||||||
|
|
||||||
protected Map<String, Backup.Metric> processPowerShellResultForBackupMetrics(final String result) {
|
protected Map<String, Backup.Metric> processPowerShellResultForBackupMetrics(final String result) {
|
||||||
logger.debug("Processing powershell result: " + result);
|
logger.debug("Processing powershell result: " + result);
|
||||||
|
|
||||||
final String separator = "=====";
|
final String separator = "=====";
|
||||||
final Map<String, Backup.Metric> sizes = new HashMap<>();
|
Map<String, Backup.Metric> metrics = new HashMap<>();
|
||||||
for (final String block : result.split(separator + "\r\n")) {
|
for (final String block : result.split(separator + "\r\n")) {
|
||||||
final String[] parts = block.split("\r\n");
|
final String[] parts = block.split("\r\n");
|
||||||
if (parts.length != 3) {
|
if (parts.length != 3) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final String backupName = parts[0];
|
final String restorePointId = parts[0];
|
||||||
if (backupName != null && backupName.contains(BACKUP_IDENTIFIER)) {
|
final Long backupSize = Long.valueOf(parts[1]);
|
||||||
final String[] names = backupName.split(BACKUP_IDENTIFIER);
|
final Long dataSize = Long.valueOf(parts[2]);
|
||||||
sizes.put(names[names.length - 1], new Backup.Metric(Long.valueOf(parts[1]), Long.valueOf(parts[2])));
|
metrics.put(restorePointId, new Backup.Metric(backupSize, dataSize));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return sizes;
|
return metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Backup.RestorePoint getRestorePointFromBlock(String[] parts) {
|
private Backup.RestorePoint getRestorePointFromBlock(String[] parts, Map<String, Backup.Metric> metricsMap) {
|
||||||
logger.debug(String.format("Processing block of restore points: [%s].", StringUtils.join(parts, ", ")));
|
logger.debug(String.format("Processing block of restore points: [%s].", StringUtils.join(parts, ", ")));
|
||||||
String id = null;
|
String id = null;
|
||||||
Date created = null;
|
Date created = null;
|
||||||
@ -834,10 +797,17 @@ public class VeeamClient {
|
|||||||
type = split[1].trim();
|
type = split[1].trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Backup.RestorePoint(id, created, type);
|
Backup.Metric metric = metricsMap.get(id);
|
||||||
|
Long backupSize = null;
|
||||||
|
Long dataSize = null;
|
||||||
|
if (metric != null) {
|
||||||
|
backupSize = metric.getBackupSize();
|
||||||
|
dataSize = metric.getDataSize();
|
||||||
|
}
|
||||||
|
return new Backup.RestorePoint(id, created, type, backupSize, dataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Backup.RestorePoint> listRestorePointsLegacy(String backupName, String vmInternalName) {
|
public List<Backup.RestorePoint> listRestorePointsLegacy(String backupName, String vmInternalName, Map<String, Backup.Metric> metricsMap) {
|
||||||
final List<String> cmds = Arrays.asList(
|
final List<String> cmds = Arrays.asList(
|
||||||
String.format("$backup = Get-VBRBackup -Name '%s'", backupName),
|
String.format("$backup = Get-VBRBackup -Name '%s'", backupName),
|
||||||
String.format("if ($backup) { $restore = (Get-VBRRestorePoint -Backup:$backup -Name \"%s\" ^| Where-Object {$_.IsConsistent -eq $true})", vmInternalName),
|
String.format("if ($backup) { $restore = (Get-VBRRestorePoint -Backup:$backup -Name \"%s\" ^| Where-Object {$_.IsConsistent -eq $true})", vmInternalName),
|
||||||
@ -855,26 +825,26 @@ public class VeeamClient {
|
|||||||
}
|
}
|
||||||
logger.debug(String.format("Found restore points from [backupName: %s, vmInternalName: %s] which is: [%s].", backupName, vmInternalName, block));
|
logger.debug(String.format("Found restore points from [backupName: %s, vmInternalName: %s] which is: [%s].", backupName, vmInternalName, block));
|
||||||
final String[] parts = block.split("\r\n");
|
final String[] parts = block.split("\r\n");
|
||||||
restorePoints.add(getRestorePointFromBlock(parts));
|
restorePoints.add(getRestorePointFromBlock(parts, metricsMap));
|
||||||
}
|
}
|
||||||
return restorePoints;
|
return restorePoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Backup.RestorePoint> listRestorePoints(String backupName, String vmInternalName) {
|
public List<Backup.RestorePoint> listRestorePoints(String backupName, String vmwareDcName, String vmInternalName, Map<String, Backup.Metric> metricsMap) {
|
||||||
if (isLegacyServer()) {
|
if (isLegacyServer()) {
|
||||||
return listRestorePointsLegacy(backupName, vmInternalName);
|
return listRestorePointsLegacy(backupName, vmInternalName, metricsMap);
|
||||||
} else {
|
} else {
|
||||||
return listVmRestorePointsViaVeeamAPI(vmInternalName);
|
return listVmRestorePointsViaVeeamAPI(vmwareDcName, vmInternalName, metricsMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Backup.RestorePoint> listVmRestorePointsViaVeeamAPI(String vmInternalName) {
|
public List<Backup.RestorePoint> listVmRestorePointsViaVeeamAPI(String vmwareDcName, String vmInternalName, Map<String, Backup.Metric> metricsMap) {
|
||||||
logger.debug(String.format("Trying to list VM restore points via Veeam B&R API for VM %s: ", vmInternalName));
|
logger.debug(String.format("Trying to list VM restore points via Veeam B&R API for VM %s: ", vmInternalName));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final HttpResponse response = get(String.format("/vmRestorePoints?format=Entity"));
|
final HttpResponse response = get(String.format("/vmRestorePoints?format=Entity"));
|
||||||
checkResponseOK(response);
|
checkResponseOK(response);
|
||||||
return processHttpResponseForVmRestorePoints(response.getEntity().getContent(), vmInternalName);
|
return processHttpResponseForVmRestorePoints(response.getEntity().getContent(), vmwareDcName, vmInternalName, metricsMap);
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
logger.error("Failed to list VM restore points via Veeam B&R API due to:", e);
|
logger.error("Failed to list VM restore points via Veeam B&R API due to:", e);
|
||||||
checkResponseTimeOut(e);
|
checkResponseTimeOut(e);
|
||||||
@ -882,21 +852,24 @@ public class VeeamClient {
|
|||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Backup.RestorePoint> processHttpResponseForVmRestorePoints(InputStream content, String vmInternalName) {
|
public List<Backup.RestorePoint> processHttpResponseForVmRestorePoints(InputStream content, String vmwareDcName, String vmInternalName, Map<String, Backup.Metric> metricsMap) {
|
||||||
List<Backup.RestorePoint> vmRestorePointList = new ArrayList<>();
|
List<Backup.RestorePoint> vmRestorePointList = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
final ObjectMapper objectMapper = new XmlMapper();
|
final ObjectMapper objectMapper = new XmlMapper();
|
||||||
final VmRestorePoints vmRestorePoints = objectMapper.readValue(content, VmRestorePoints.class);
|
final VmRestorePoints vmRestorePoints = objectMapper.readValue(content, VmRestorePoints.class);
|
||||||
|
final String hierarchyId = findDCHierarchy(vmwareDcName);
|
||||||
|
final String hierarchyUuid = StringUtils.substringAfterLast(hierarchyId, ":");
|
||||||
if (vmRestorePoints == null) {
|
if (vmRestorePoints == null) {
|
||||||
throw new CloudRuntimeException("Could not get VM restore points via Veeam B&R API");
|
throw new CloudRuntimeException("Could not get VM restore points via Veeam B&R API");
|
||||||
}
|
}
|
||||||
for (final VmRestorePoint vmRestorePoint : vmRestorePoints.getVmRestorePoints()) {
|
for (final VmRestorePoint vmRestorePoint : vmRestorePoints.getVmRestorePoints()) {
|
||||||
logger.debug(String.format("Processing VM restore point Name=%s, VmDisplayName=%s for vm name=%s",
|
logger.debug(String.format("Processing VM restore point Name=%s, VmDisplayName=%s for vm name=%s",
|
||||||
vmRestorePoint.getName(), vmRestorePoint.getVmDisplayName(), vmInternalName));
|
vmRestorePoint.getName(), vmRestorePoint.getVmDisplayName(), vmInternalName));
|
||||||
if (!vmInternalName.equals(vmRestorePoint.getVmDisplayName())) {
|
if (!vmInternalName.equals(vmRestorePoint.getVmDisplayName()) || !vmRestorePoint.getHierarchyObjRef().contains(hierarchyUuid)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
boolean isReady = true;
|
boolean isReady = true;
|
||||||
|
String backupFileId = "";
|
||||||
List<Link> links = vmRestorePoint.getLink();
|
List<Link> links = vmRestorePoint.getLink();
|
||||||
for (Link link : links) {
|
for (Link link : links) {
|
||||||
if (Arrays.asList(BACKUP_FILE_REFERENCE, RESTORE_POINT_REFERENCE).contains(link.getType()) && !link.getRel().equals("Up")) {
|
if (Arrays.asList(BACKUP_FILE_REFERENCE, RESTORE_POINT_REFERENCE).contains(link.getType()) && !link.getRel().equals("Up")) {
|
||||||
@ -904,15 +877,27 @@ public class VeeamClient {
|
|||||||
isReady = false;
|
isReady = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (link.getType() != null && link.getType().equals(BACKUP_FILE_REFERENCE)) {
|
||||||
|
backupFileId = StringUtils.substringAfterLast(link.getHref(), "/");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!isReady) {
|
if (!isReady) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String vmRestorePointId = vmRestorePoint.getUid().substring(vmRestorePoint.getUid().lastIndexOf(':') + 1);
|
String vmRestorePointId = StringUtils.substringAfterLast(vmRestorePoint.getUid(), ":");
|
||||||
Date created = formatDate(vmRestorePoint.getCreationTimeUtc());
|
Date created = formatDate(vmRestorePoint.getCreationTimeUtc());
|
||||||
String type = vmRestorePoint.getPointType();
|
String type = vmRestorePoint.getPointType();
|
||||||
logger.debug(String.format("Adding restore point %s, %s, %s", vmRestorePointId, created, type));
|
logger.debug(String.format("Adding restore point %s, %s, %s", vmRestorePointId, created, type));
|
||||||
vmRestorePointList.add(new Backup.RestorePoint(vmRestorePointId, created, type));
|
Long backupSize = null;
|
||||||
|
Long dataSize = null;
|
||||||
|
if (!backupFileId.isEmpty()) {
|
||||||
|
Backup.Metric metric = metricsMap.get(backupFileId);
|
||||||
|
if (metric != null) {
|
||||||
|
backupSize = metric.getBackupSize();
|
||||||
|
dataSize = metric.getDataSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vmRestorePointList.add(new Backup.RestorePoint(vmRestorePointId, created, type, backupSize, dataSize));
|
||||||
}
|
}
|
||||||
} catch (final IOException | ParseException e) {
|
} catch (final IOException | ParseException e) {
|
||||||
logger.error("Failed to process response to get VM restore points via Veeam B&R API due to:", e);
|
logger.error("Failed to process response to get VM restore points via Veeam B&R API due to:", e);
|
||||||
@ -925,15 +910,17 @@ public class VeeamClient {
|
|||||||
return dateFormat.parse(StringUtils.substring(date, 0, 19));
|
return dateFormat.parse(StringUtils.substring(date, 0, 19));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<Boolean, String> restoreVMToDifferentLocation(String restorePointId, String hostIp, String dataStoreUuid) {
|
public Pair<Boolean, String> restoreVMToDifferentLocation(String restorePointId, String restoreLocation, String hostIp, String dataStoreUuid) {
|
||||||
final String restoreLocation = RESTORE_VM_SUFFIX + UUID.randomUUID().toString();
|
if (restoreLocation == null) {
|
||||||
|
restoreLocation = RESTORE_VM_SUFFIX + UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
final String datastoreId = dataStoreUuid.replace("-","");
|
final String datastoreId = dataStoreUuid.replace("-","");
|
||||||
final List<String> cmds = Arrays.asList(
|
final List<String> cmds = Arrays.asList(
|
||||||
"$points = Get-VBRRestorePoint",
|
"$points = Get-VBRRestorePoint",
|
||||||
String.format("foreach($point in $points) { if ($point.Id -eq '%s') { break; } }", restorePointId),
|
String.format("foreach($point in $points) { if ($point.Id -eq '%s') { $restorePoint = $point; break; } }", restorePointId),
|
||||||
String.format("$server = Get-VBRServer -Name \"%s\"", hostIp),
|
String.format("$server = Get-VBRServer -Name \"%s\"", hostIp),
|
||||||
String.format("$ds = Find-VBRViDatastore -Server:$server -Name \"%s\"", datastoreId),
|
String.format("$ds = Find-VBRViDatastore -Server:$server -Name \"%s\"", datastoreId),
|
||||||
String.format("$job = Start-VBRRestoreVM -RestorePoint:$point -Server:$server -Datastore:$ds -VMName \"%s\" -RunAsync", restoreLocation),
|
String.format("$job = Start-VBRRestoreVM -RestorePoint:$restorePoint -Server:$server -Datastore:$ds -VMName \"%s\" -RunAsync", restoreLocation),
|
||||||
"while (-not (Get-VBRRestoreSession -Id $job.Id).IsCompleted) { Start-Sleep -Seconds 10 }"
|
"while (-not (Get-VBRRestoreSession -Id $job.Id).IsCompleted) { Start-Sleep -Seconds 10 }"
|
||||||
);
|
);
|
||||||
Pair<Boolean, String> result = executePowerShellCommands(cmds);
|
Pair<Boolean, String> result = executePowerShellCommands(cmds);
|
||||||
|
|||||||
@ -93,13 +93,14 @@ public class VeeamBackupProviderTest {
|
|||||||
backup.setExternalId("abc");
|
backup.setExternalId("abc");
|
||||||
backup.setType("Full");
|
backup.setType("Full");
|
||||||
backup.setZoneId(3l);
|
backup.setZoneId(3l);
|
||||||
|
backup.setBackupOfferingId(4l);
|
||||||
|
|
||||||
Mockito.when(vmInstanceDao.findByIdIncludingRemoved(Mockito.anyLong())).thenReturn(vmInstanceVO);
|
Mockito.when(vmInstanceDao.findByIdIncludingRemoved(Mockito.anyLong())).thenReturn(vmInstanceVO);
|
||||||
Mockito.doReturn(client).when(backupProvider).getClient(2l);
|
Mockito.doReturn(client).when(backupProvider).getClient(2l);
|
||||||
Mockito.doReturn(true).when(client).deleteBackup("abc");
|
Mockito.doReturn(true).when(client).deleteBackup("abc");
|
||||||
List<Backup> backups = new ArrayList<>();
|
List<Backup> backups = new ArrayList<>();
|
||||||
backups.add(backup);
|
backups.add(backup);
|
||||||
Mockito.when(backupDao.listByVmId(3l, 1l)).thenReturn(backups);
|
Mockito.when(backupDao.listByVmIdAndOffering(3l, 1l, 4l)).thenReturn(backups);
|
||||||
Mockito.verify(backupDao, Mockito.never()).remove(Mockito.anyLong());
|
Mockito.verify(backupDao, Mockito.never()).remove(Mockito.anyLong());
|
||||||
boolean result = backupProvider.deleteBackup(backup, true);
|
boolean result = backupProvider.deleteBackup(backup, true);
|
||||||
assertEquals(true, result);
|
assertEquals(true, result);
|
||||||
@ -115,6 +116,7 @@ public class VeeamBackupProviderTest {
|
|||||||
Mockito.when(backup.getVmId()).thenReturn(1l);
|
Mockito.when(backup.getVmId()).thenReturn(1l);
|
||||||
Mockito.when(backup.getExternalId()).thenReturn("abc");
|
Mockito.when(backup.getExternalId()).thenReturn("abc");
|
||||||
Mockito.when(backup.getZoneId()).thenReturn(3l);
|
Mockito.when(backup.getZoneId()).thenReturn(3l);
|
||||||
|
Mockito.when(backup.getBackupOfferingId()).thenReturn(4l);
|
||||||
|
|
||||||
BackupVO backup2 = Mockito.mock(BackupVO.class);
|
BackupVO backup2 = Mockito.mock(BackupVO.class);
|
||||||
Mockito.when(backup2.getId()).thenReturn(2l);
|
Mockito.when(backup2.getId()).thenReturn(2l);
|
||||||
@ -122,10 +124,7 @@ public class VeeamBackupProviderTest {
|
|||||||
Mockito.when(vmInstanceDao.findByIdIncludingRemoved(Mockito.anyLong())).thenReturn(vmInstanceVO);
|
Mockito.when(vmInstanceDao.findByIdIncludingRemoved(Mockito.anyLong())).thenReturn(vmInstanceVO);
|
||||||
Mockito.doReturn(client).when(backupProvider).getClient(2l);
|
Mockito.doReturn(client).when(backupProvider).getClient(2l);
|
||||||
Mockito.doReturn(true).when(client).deleteBackup("abc");
|
Mockito.doReturn(true).when(client).deleteBackup("abc");
|
||||||
List<Backup> backups = new ArrayList<>();
|
Mockito.when(backupDao.listByVmIdAndOffering(3l, 1l, 4l)).thenReturn(List.of(backup, backup2));
|
||||||
backups.add(backup);
|
|
||||||
backups.add(backup2);
|
|
||||||
Mockito.when(backupDao.listByVmId(3l, 1l)).thenReturn(backups);
|
|
||||||
boolean result = backupProvider.deleteBackup(backup, true);
|
boolean result = backupProvider.deleteBackup(backup, true);
|
||||||
Mockito.verify(backupDao, Mockito.times(1)).remove(2l);
|
Mockito.verify(backupDao, Mockito.times(1)).remove(2l);
|
||||||
assertEquals(true, result);
|
assertEquals(true, result);
|
||||||
|
|||||||
@ -209,32 +209,46 @@ public class VeeamClientTest {
|
|||||||
|
|
||||||
|
|
||||||
private void verifyBackupMetrics(Map<String, Backup.Metric> metrics) {
|
private void verifyBackupMetrics(Map<String, Backup.Metric> metrics) {
|
||||||
Assert.assertEquals(2, metrics.size());
|
Assert.assertEquals(7, metrics.size());
|
||||||
|
|
||||||
Assert.assertTrue(metrics.containsKey("d1bd8abd-fc73-4b77-9047-7be98a2ecb72"));
|
Assert.assertTrue(metrics.containsKey("d93d7c7d-068a-4e8f-ba54-e08cea3cb9d2"));
|
||||||
Assert.assertEquals(537776128L, (long) metrics.get("d1bd8abd-fc73-4b77-9047-7be98a2ecb72").getBackupSize());
|
Assert.assertEquals(537776128L, (long) metrics.get("d93d7c7d-068a-4e8f-ba54-e08cea3cb9d2").getBackupSize());
|
||||||
Assert.assertEquals(2147506644L, (long) metrics.get("d1bd8abd-fc73-4b77-9047-7be98a2ecb72").getDataSize());
|
Assert.assertEquals(2147506644L, (long) metrics.get("d93d7c7d-068a-4e8f-ba54-e08cea3cb9d2").getDataSize());
|
||||||
|
|
||||||
Assert.assertTrue(metrics.containsKey("0d752ca6-d628-4d85-a739-75275e4661e6"));
|
Assert.assertTrue(metrics.containsKey("d2110f5f-aa22-4e67-8084-5d8597f26d63"));
|
||||||
Assert.assertEquals(1268682752L, (long) metrics.get("0d752ca6-d628-4d85-a739-75275e4661e6").getBackupSize());
|
Assert.assertEquals(579756032L, (long) metrics.get("d2110f5f-aa22-4e67-8084-5d8597f26d63").getBackupSize());
|
||||||
Assert.assertEquals(15624049921L, (long) metrics.get("0d752ca6-d628-4d85-a739-75275e4661e6").getDataSize());
|
Assert.assertEquals(7516219400L, (long) metrics.get("d2110f5f-aa22-4e67-8084-5d8597f26d63").getDataSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessPowerShellResultForBackupMetrics() {
|
public void testProcessPowerShellResultForBackupMetrics() {
|
||||||
String result = "i-2-3-VM-CSBKP-d1bd8abd-fc73-4b77-9047-7be98a2ecb72\r\n" +
|
String result = "d93d7c7d-068a-4e8f-ba54-e08cea3cb9d2\r\n" +
|
||||||
"537776128\r\n" +
|
"537776128\r\n" +
|
||||||
"2147506644\r\n" +
|
"2147506644\r\n" +
|
||||||
"=====\r\n" +
|
"=====\r\n" +
|
||||||
"i-13-22-VM-CSBKP-b3b3cb75-cfbf-4496-9c63-a08a93347276\r\n" +
|
"4b1181fd-7b1e-4af1-a76b-8284a8953b99\r\n" +
|
||||||
|
"12398592\r\n" +
|
||||||
|
"71329948\r\n" +
|
||||||
"=====\r\n" +
|
"=====\r\n" +
|
||||||
"backup-job-based-on-sla\r\n" +
|
"8e9a854e-9bb8-4a34-815c-a6ab17a1e72f\r\n" +
|
||||||
|
"11870208\r\n" +
|
||||||
|
"72378524\r\n" +
|
||||||
"=====\r\n" +
|
"=====\r\n" +
|
||||||
"i-12-20-VM-CSBKP-9f292f11-00ec-4915-84f0-e3895828640e\r\n" +
|
"7c54d13d-7b9c-465a-8ec8-7a276bde57dd\r\n" +
|
||||||
|
"12083200\r\n" +
|
||||||
|
"69232800\r\n" +
|
||||||
"=====\r\n" +
|
"=====\r\n" +
|
||||||
"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\r\n" +
|
"094564ff-02a1-46c7-b9e5-e249b8b9acf6\r\n" +
|
||||||
"1268682752\r\n" +
|
"14217216\r\n" +
|
||||||
"15624049921\r\n" +
|
"76572832\r\n" +
|
||||||
|
"=====\r\n" +
|
||||||
|
"1f6f5c49-92ef-4757-b327-e63ae9f1fdea\r\n" +
|
||||||
|
"12460032\r\n" +
|
||||||
|
"72378524\r\n" +
|
||||||
|
"=====\r\n" +
|
||||||
|
"d2110f5f-aa22-4e67-8084-5d8597f26d63\r\n" +
|
||||||
|
"579756032\r\n" +
|
||||||
|
"7516219400\r\n" +
|
||||||
"=====\r\n";
|
"=====\r\n";
|
||||||
|
|
||||||
Map<String, Backup.Metric> metrics = client.processPowerShellResultForBackupMetrics(result);
|
Map<String, Backup.Metric> metrics = client.processPowerShellResultForBackupMetrics(result);
|
||||||
@ -294,22 +308,6 @@ public class VeeamClientTest {
|
|||||||
" <CreationTimeUtc>2023-11-01T00:00:35.163Z</CreationTimeUtc>\n" +
|
" <CreationTimeUtc>2023-11-01T00:00:35.163Z</CreationTimeUtc>\n" +
|
||||||
" <FileType>vib</FileType>\n" +
|
" <FileType>vib</FileType>\n" +
|
||||||
" </BackupFile>\n" +
|
" </BackupFile>\n" +
|
||||||
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/66b39f48-af76-4373-b333-996fc04da894?format=Entity\" Type=\"BackupFile\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-04T000109_2AC1.vbk\" UID=\"urn:veeam:BackupFile:66b39f48-af76-4373-b333-996fc04da894\">\n" +
|
|
||||||
" <Links>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupServers/bb188236-7b8b-4763-b35a-5d6645d3e95b\" Name=\"10.0.3.141\" Type=\"BackupServerReference\" Rel=\"Up\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/66b39f48-af76-4373-b333-996fc04da894\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-04T000109_2AC1.vbk\" Type=\"BackupFileReference\" Rel=\"Alternate\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/66b39f48-af76-4373-b333-996fc04da894/restorePoints\" Type=\"RestorePointReferenceList\" Rel=\"Related\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/66b39f48-af76-4373-b333-996fc04da894/vmRestorePoints\" Type=\"VmRestorePointReferenceList\" Rel=\"Down\"/>\n" +
|
|
||||||
" </Links>\n" +
|
|
||||||
" <FilePath>V:\\Backup\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-04T000109_2AC1.vbk</FilePath>\n" +
|
|
||||||
" <BackupSize>581083136</BackupSize>\n" +
|
|
||||||
" <DataSize>7516219404</DataSize>\n" +
|
|
||||||
" <DeduplicationRatio>5.82</DeduplicationRatio>\n" +
|
|
||||||
" <CompressRatio>2.22</CompressRatio>\n" +
|
|
||||||
" <CreationTimeUtc>2023-11-04T00:00:24.973Z</CreationTimeUtc>\n" +
|
|
||||||
" <FileType>vbk</FileType>\n" +
|
|
||||||
" </BackupFile>\n" +
|
|
||||||
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/8e9a854e-9bb8-4a34-815c-a6ab17a1e72f?format=Entity\" Type=\"BackupFile\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-10-29T000033_F468.vib\" UID=\"urn:veeam:BackupFile:8e9a854e-9bb8-4a34-815c-a6ab17a1e72f\">\n" +
|
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/8e9a854e-9bb8-4a34-815c-a6ab17a1e72f?format=Entity\" Type=\"BackupFile\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-10-29T000033_F468.vib\" UID=\"urn:veeam:BackupFile:8e9a854e-9bb8-4a34-815c-a6ab17a1e72f\">\n" +
|
||||||
" <Links>\n" +
|
" <Links>\n" +
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
||||||
@ -326,54 +324,6 @@ public class VeeamClientTest {
|
|||||||
" <CreationTimeUtc>2023-10-28T23:00:33.233Z</CreationTimeUtc>\n" +
|
" <CreationTimeUtc>2023-10-28T23:00:33.233Z</CreationTimeUtc>\n" +
|
||||||
" <FileType>vib</FileType>\n" +
|
" <FileType>vib</FileType>\n" +
|
||||||
" </BackupFile>\n" +
|
" </BackupFile>\n" +
|
||||||
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/cf4536c0-d752-4ba5-ad7f-bbc17c7e107b?format=Entity\" Type=\"BackupFile\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-10-30T000022_0CE3.vib\" UID=\"urn:veeam:BackupFile:cf4536c0-d752-4ba5-ad7f-bbc17c7e107b\">\n" +
|
|
||||||
" <Links>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupServers/bb188236-7b8b-4763-b35a-5d6645d3e95b\" Name=\"10.0.3.141\" Type=\"BackupServerReference\" Rel=\"Up\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/cf4536c0-d752-4ba5-ad7f-bbc17c7e107b\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-10-30T000022_0CE3.vib\" Type=\"BackupFileReference\" Rel=\"Alternate\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/cf4536c0-d752-4ba5-ad7f-bbc17c7e107b/restorePoints\" Type=\"RestorePointReferenceList\" Rel=\"Related\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/cf4536c0-d752-4ba5-ad7f-bbc17c7e107b/vmRestorePoints\" Type=\"VmRestorePointReferenceList\" Rel=\"Down\"/>\n" +
|
|
||||||
" </Links>\n" +
|
|
||||||
" <FilePath>V:\\Backup\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-10-30T000022_0CE3.vib</FilePath>\n" +
|
|
||||||
" <BackupSize>14409728</BackupSize>\n" +
|
|
||||||
" <DataSize>76572828</DataSize>\n" +
|
|
||||||
" <DeduplicationRatio>1</DeduplicationRatio>\n" +
|
|
||||||
" <CompressRatio>6.25</CompressRatio>\n" +
|
|
||||||
" <CreationTimeUtc>2023-10-30T00:00:22.7Z</CreationTimeUtc>\n" +
|
|
||||||
" <FileType>vib</FileType>\n" +
|
|
||||||
" </BackupFile>\n" +
|
|
||||||
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/2dd7f5b6-8a10-406d-9c4f-c0dfa987e85c?format=Entity\" Type=\"BackupFile\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-06T000018_055B.vib\" UID=\"urn:veeam:BackupFile:2dd7f5b6-8a10-406d-9c4f-c0dfa987e85c\">\n" +
|
|
||||||
" <Links>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupServers/bb188236-7b8b-4763-b35a-5d6645d3e95b\" Name=\"10.0.3.141\" Type=\"BackupServerReference\" Rel=\"Up\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/2dd7f5b6-8a10-406d-9c4f-c0dfa987e85c\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-06T000018_055B.vib\" Type=\"BackupFileReference\" Rel=\"Alternate\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/2dd7f5b6-8a10-406d-9c4f-c0dfa987e85c/restorePoints\" Type=\"RestorePointReferenceList\" Rel=\"Related\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/2dd7f5b6-8a10-406d-9c4f-c0dfa987e85c/vmRestorePoints\" Type=\"VmRestorePointReferenceList\" Rel=\"Down\"/>\n" +
|
|
||||||
" </Links>\n" +
|
|
||||||
" <FilePath>V:\\Backup\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-06T000018_055B.vib</FilePath>\n" +
|
|
||||||
" <BackupSize>17883136</BackupSize>\n" +
|
|
||||||
" <DataSize>80767136</DataSize>\n" +
|
|
||||||
" <DeduplicationRatio>1</DeduplicationRatio>\n" +
|
|
||||||
" <CompressRatio>5</CompressRatio>\n" +
|
|
||||||
" <CreationTimeUtc>2023-11-06T00:00:18.253Z</CreationTimeUtc>\n" +
|
|
||||||
" <FileType>vib</FileType>\n" +
|
|
||||||
" </BackupFile>\n" +
|
|
||||||
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/3fd6da3a-47bf-45fa-a4c8-c436e3cd34a7?format=Entity\" Type=\"BackupFile\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-02T000029_65BE.vib\" UID=\"urn:veeam:BackupFile:3fd6da3a-47bf-45fa-a4c8-c436e3cd34a7\">\n" +
|
|
||||||
" <Links>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupServers/bb188236-7b8b-4763-b35a-5d6645d3e95b\" Name=\"10.0.3.141\" Type=\"BackupServerReference\" Rel=\"Up\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/3fd6da3a-47bf-45fa-a4c8-c436e3cd34a7\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-02T000029_65BE.vib\" Type=\"BackupFileReference\" Rel=\"Alternate\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/3fd6da3a-47bf-45fa-a4c8-c436e3cd34a7/restorePoints\" Type=\"RestorePointReferenceList\" Rel=\"Related\"/>\n" +
|
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/3fd6da3a-47bf-45fa-a4c8-c436e3cd34a7/vmRestorePoints\" Type=\"VmRestorePointReferenceList\" Rel=\"Down\"/>\n" +
|
|
||||||
" </Links>\n" +
|
|
||||||
" <FilePath>V:\\Backup\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-02T000029_65BE.vib</FilePath>\n" +
|
|
||||||
" <BackupSize>12521472</BackupSize>\n" +
|
|
||||||
" <DataSize>72378525</DataSize>\n" +
|
|
||||||
" <DeduplicationRatio>1</DeduplicationRatio>\n" +
|
|
||||||
" <CompressRatio>6.67</CompressRatio>\n" +
|
|
||||||
" <CreationTimeUtc>2023-11-02T00:00:29.05Z</CreationTimeUtc>\n" +
|
|
||||||
" <FileType>vib</FileType>\n" +
|
|
||||||
" </BackupFile>\n" +
|
|
||||||
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/d93d7c7d-068a-4e8f-ba54-e08cea3cb9d2?format=Entity\" Type=\"BackupFile\" Name=\"i-2-3-VM-CSBKP-d1bd8abd-fc73-4b77-9047-7be98aD2023-10-25T145951_8062.vbk\" UID=\"urn:veeam:BackupFile:d93d7c7d-068a-4e8f-ba54-e08cea3cb9d2\">\n" +
|
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/d93d7c7d-068a-4e8f-ba54-e08cea3cb9d2?format=Entity\" Type=\"BackupFile\" Name=\"i-2-3-VM-CSBKP-d1bd8abd-fc73-4b77-9047-7be98aD2023-10-25T145951_8062.vbk\" UID=\"urn:veeam:BackupFile:d93d7c7d-068a-4e8f-ba54-e08cea3cb9d2\">\n" +
|
||||||
" <Links>\n" +
|
" <Links>\n" +
|
||||||
" <Link Href=\"https://10.0.3.141:9398/api/backups/a34cae53-2d9e-454b-8d3e-0aaa7b34c228\" Name=\"i-2-3-VM-CSBKP-d1bd8abd-fc73-4b77-9047-7be98a2ecb72\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
" <Link Href=\"https://10.0.3.141:9398/api/backups/a34cae53-2d9e-454b-8d3e-0aaa7b34c228\" Name=\"i-2-3-VM-CSBKP-d1bd8abd-fc73-4b77-9047-7be98a2ecb72\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
||||||
@ -463,14 +413,72 @@ public class VeeamClientTest {
|
|||||||
Map<String, Backup.Metric> metrics = client.getBackupMetricsViaVeeamAPI();
|
Map<String, Backup.Metric> metrics = client.getBackupMetricsViaVeeamAPI();
|
||||||
|
|
||||||
Assert.assertEquals(1, metrics.size());
|
Assert.assertEquals(1, metrics.size());
|
||||||
Assert.assertTrue(metrics.containsKey("506760dc-ed77-40d6-a91d-e0914e7a1ad8"));
|
Assert.assertTrue(metrics.containsKey("6bf10cad-9181-45d9-9cc5-dd669366a381"));
|
||||||
Assert.assertEquals(535875584L, (long) metrics.get("506760dc-ed77-40d6-a91d-e0914e7a1ad8").getBackupSize());
|
Assert.assertEquals(535875584L, (long) metrics.get("6bf10cad-9181-45d9-9cc5-dd669366a381").getBackupSize());
|
||||||
Assert.assertEquals(2147507235L, (long) metrics.get("506760dc-ed77-40d6-a91d-e0914e7a1ad8").getDataSize());
|
Assert.assertEquals(2147507235L, (long) metrics.get("6bf10cad-9181-45d9-9cc5-dd669366a381").getDataSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListVmRestorePointsViaVeeamAPI() {
|
public void testListVmRestorePointsViaVeeamAPI() {
|
||||||
String xmlResponse = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
|
String backupFilesXmlResponse = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
|
||||||
|
"<BackupFiles xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.veeam.com/ent/v1.0\">\n" +
|
||||||
|
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/d2110f5f-aa22-4e67-8084-5d8597f26d63?format=Entity\" Type=\"BackupFile\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-10-28T000059_745D.vbk\" UID=\"urn:veeam:BackupFile:d2110f5f-aa22-4e67-8084-5d8597f26d63\">\n" +
|
||||||
|
" <Links>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupServers/bb188236-7b8b-4763-b35a-5d6645d3e95b\" Name=\"10.0.3.141\" Type=\"BackupServerReference\" Rel=\"Up\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/d2110f5f-aa22-4e67-8084-5d8597f26d63\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-10-28T000059_745D.vbk\" Type=\"BackupFileReference\" Rel=\"Alternate\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/d2110f5f-aa22-4e67-8084-5d8597f26d63/restorePoints\" Type=\"RestorePointReferenceList\" Rel=\"Related\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/d2110f5f-aa22-4e67-8084-5d8597f26d63/vmRestorePoints\" Type=\"VmRestorePointReferenceList\" Rel=\"Down\"/>\n" +
|
||||||
|
" </Links>\n" +
|
||||||
|
" <FilePath>V:\\Backup\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-10-28T000059_745D.vbk</FilePath>\n" +
|
||||||
|
" <BackupSize>579756032</BackupSize>\n" +
|
||||||
|
" <DataSize>7516219400</DataSize>\n" +
|
||||||
|
" <DeduplicationRatio>5.83</DeduplicationRatio>\n" +
|
||||||
|
" <CompressRatio>2.22</CompressRatio>\n" +
|
||||||
|
" <CreationTimeUtc>2023-10-27T23:00:13.74Z</CreationTimeUtc>\n" +
|
||||||
|
" <FileType>vbk</FileType>\n" +
|
||||||
|
" </BackupFile>\n" +
|
||||||
|
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/6bf10cad-9181-45d9-9cc5-dd669366a381?format=Entity\" Type=\"BackupFile\" Name=\"i-2-4-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-1036D2023-11-03T162535_89D6.vbk\" UID=\"urn:veeam:BackupFile:6bf10cad-9181-45d9-9cc5-dd669366a381\">\n" +
|
||||||
|
" <Links>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-4-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupServers/bb188236-7b8b-4763-b35a-5d6645d3e95b\" Name=\"10.0.3.141\" Type=\"BackupServerReference\" Rel=\"Up\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/6bf10cad-9181-45d9-9cc5-dd669366a381\" Name=\"i-2-4-VM.vm-1036D2023-11-03T162535_89D6.vbk\" Type=\"BackupFileReference\" Rel=\"Alternate\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/6bf10cad-9181-45d9-9cc5-dd669366a381/restorePoints\" Type=\"RestorePointReferenceList\" Rel=\"Related\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/6bf10cad-9181-45d9-9cc5-dd669366a381/vmRestorePoints\" Type=\"VmRestorePointReferenceList\" Rel=\"Down\"/>\n" +
|
||||||
|
" </Links>\n" +
|
||||||
|
" <FilePath>V:\\Backup\\i-2-4-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\\i-2-4-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-1036D2023-11-03T162535_89D6.vbk</FilePath>\n" +
|
||||||
|
" <BackupSize>12083200</BackupSize>\n" +
|
||||||
|
" <DataSize>69232800</DataSize>\n" +
|
||||||
|
" <DeduplicationRatio>1</DeduplicationRatio>\n" +
|
||||||
|
" <CompressRatio>6.67</CompressRatio>\n" +
|
||||||
|
" <CreationTimeUtc>2023-11-05T00:00:22.827Z</CreationTimeUtc>\n" +
|
||||||
|
" <FileType>vib</FileType>\n" +
|
||||||
|
" </BackupFile>\n" +
|
||||||
|
" <BackupFile Href=\"https://10.0.3.141:9398/api/backupFiles/4b1181fd-7b1e-4af1-a76b-8284a8953b99?format=Entity\" Type=\"BackupFile\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-01T000035_BEBF.vib\" UID=\"urn:veeam:BackupFile:4b1181fd-7b1e-4af1-a76b-8284a8953b99\">\n" +
|
||||||
|
" <Links>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backups/e7484f82-b01b-47cf-92ad-ac5e8379a4fe\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\" Type=\"BackupReference\" Rel=\"Up\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupServers/bb188236-7b8b-4763-b35a-5d6645d3e95b\" Name=\"10.0.3.141\" Type=\"BackupServerReference\" Rel=\"Up\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/4b1181fd-7b1e-4af1-a76b-8284a8953b99\" Name=\"i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-01T000035_BEBF.vib\" Type=\"BackupFileReference\" Rel=\"Alternate\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/4b1181fd-7b1e-4af1-a76b-8284a8953b99/restorePoints\" Type=\"RestorePointReferenceList\" Rel=\"Related\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupFiles/4b1181fd-7b1e-4af1-a76b-8284a8953b99/vmRestorePoints\" Type=\"VmRestorePointReferenceList\" Rel=\"Down\"/>\n" +
|
||||||
|
" </Links>\n" +
|
||||||
|
" <FilePath>V:\\Backup\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275e4661e6\\i-2-5-VM-CSBKP-0d752ca6-d628-4d85-a739-75275eD2023-11-01T000035_BEBF.vib</FilePath>\n" +
|
||||||
|
" <BackupSize>12398592</BackupSize>\n" +
|
||||||
|
" <DataSize>71329948</DataSize>\n" +
|
||||||
|
" <DeduplicationRatio>1</DeduplicationRatio>\n" +
|
||||||
|
" <CompressRatio>6.67</CompressRatio>\n" +
|
||||||
|
" <CreationTimeUtc>2023-11-01T00:00:35.163Z</CreationTimeUtc>\n" +
|
||||||
|
" <FileType>vib</FileType>\n" +
|
||||||
|
" </BackupFile>\n" +
|
||||||
|
"</BackupFiles>\n";
|
||||||
|
|
||||||
|
wireMockRule.stubFor(get(urlMatching(".*/backupFiles\\?format=Entity"))
|
||||||
|
.willReturn(aResponse()
|
||||||
|
.withHeader("content-type", "application/xml")
|
||||||
|
.withStatus(200)
|
||||||
|
.withBody(backupFilesXmlResponse)));
|
||||||
|
|
||||||
|
String vmRestorePointsXmlResponse = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
|
||||||
"<VmRestorePoints\n" +
|
"<VmRestorePoints\n" +
|
||||||
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
|
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
|
||||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
|
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
|
||||||
@ -489,7 +497,7 @@ public class VeeamClientTest {
|
|||||||
" <VmName>i-2-4-VM</VmName>\n" +
|
" <VmName>i-2-4-VM</VmName>\n" +
|
||||||
" <Algorithm>Full</Algorithm>\n" +
|
" <Algorithm>Full</Algorithm>\n" +
|
||||||
" <PointType>Full</PointType>\n" +
|
" <PointType>Full</PointType>\n" +
|
||||||
" <HierarchyObjRef>urn:VMware:Vm:adb5423b-b578-4c26-8ab8-cde9c1faec55.vm-1036</HierarchyObjRef>\n" +
|
" <HierarchyObjRef>urn:VMware:Vm:24490b30-81db-4038-821f-59694cd89519.vm-1036</HierarchyObjRef>\n" +
|
||||||
" </VmRestorePoint>\n" +
|
" </VmRestorePoint>\n" +
|
||||||
"</VmRestorePoints>\n";
|
"</VmRestorePoints>\n";
|
||||||
String vmName = "i-2-4-VM";
|
String vmName = "i-2-4-VM";
|
||||||
@ -498,13 +506,38 @@ public class VeeamClientTest {
|
|||||||
.willReturn(aResponse()
|
.willReturn(aResponse()
|
||||||
.withHeader("content-type", "application/xml")
|
.withHeader("content-type", "application/xml")
|
||||||
.withStatus(200)
|
.withStatus(200)
|
||||||
.withBody(xmlResponse)));
|
.withBody(vmRestorePointsXmlResponse)));
|
||||||
List<Backup.RestorePoint> vmRestorePointList = client.listVmRestorePointsViaVeeamAPI(vmName);
|
|
||||||
|
String hierarchyXmlResponse = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
|
||||||
|
"<EntityReferences\n" +
|
||||||
|
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n" +
|
||||||
|
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
|
||||||
|
" xmlns=\"http://www.veeam.com/ent/v1.0\">\n" +
|
||||||
|
" <Ref UID=\"urn:veeam:HierarchyRoot:24490b30-81db-4038-821f-59694cd89519\" Name=\"10.0.32.153\" Href=\"https://10.0.3.141:9398/api/hierarchyRoots/24490b30-81db-4038-821f-59694cd89519\" Type=\"HierarchyRootReference\">\n" +
|
||||||
|
" <Links>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/backupServers/bb188236-7b8b-4763-b35a-5d6645d3e95b\" Name=\"10.0.3.141\" Type=\"BackupServerReference\" Rel=\"Up\"/>\n" +
|
||||||
|
" <Link Href=\"https://10.0.3.141:9398/api/hierarchyRoots/24490b30-81db-4038-821f-59694cd89519?format=Entity\" Name=\"10.0.32.153\" Type=\"HierarchyRoot\" Rel=\"Alternate\"/>\n" +
|
||||||
|
" </Links>\n" +
|
||||||
|
" </Ref>" +
|
||||||
|
"</EntityReferences>";
|
||||||
|
String vmwareDcName = "10.0.32.153";
|
||||||
|
String hierarchyId = "urn:VMware:Vm:24490b30-81db-4038-821f-59694cd89519";
|
||||||
|
|
||||||
|
wireMockRule.stubFor(get(urlMatching(".*/hierarchyRoots"))
|
||||||
|
.willReturn(aResponse()
|
||||||
|
.withHeader("content-type", "application/xml")
|
||||||
|
.withStatus(200)
|
||||||
|
.withBody(hierarchyXmlResponse)));
|
||||||
|
|
||||||
|
Map<String, Backup.Metric> metricsMap = client.getBackupMetrics();
|
||||||
|
List<Backup.RestorePoint> vmRestorePointList = client.listVmRestorePointsViaVeeamAPI(vmwareDcName, vmName, metricsMap);
|
||||||
|
|
||||||
Assert.assertEquals(1, vmRestorePointList.size());
|
Assert.assertEquals(1, vmRestorePointList.size());
|
||||||
Assert.assertEquals("f6d504cf-eafe-4cd2-8dfc-e9cfe2f1e977", vmRestorePointList.get(0).getId());
|
Assert.assertEquals("f6d504cf-eafe-4cd2-8dfc-e9cfe2f1e977", vmRestorePointList.get(0).getId());
|
||||||
Assert.assertEquals("2023-11-03 16:26:12", newDateFormat.format(vmRestorePointList.get(0).getCreated()));
|
Assert.assertEquals("2023-11-03 16:26:12", newDateFormat.format(vmRestorePointList.get(0).getCreated()));
|
||||||
Assert.assertEquals("Full", vmRestorePointList.get(0).getType());
|
Assert.assertEquals("Full", vmRestorePointList.get(0).getType());
|
||||||
|
Assert.assertEquals(12083200L, (long) vmRestorePointList.get(0).getBackupSize());
|
||||||
|
Assert.assertEquals(69232800L, (long) vmRestorePointList.get(0).getDataSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// 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.hypervisor.kvm.resource.wrapper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.backup.BackupStorageStatsAnswer;
|
||||||
|
import org.apache.cloudstack.backup.GetBackupStorageStatsCommand;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||||
|
import com.cloud.resource.CommandWrapper;
|
||||||
|
import com.cloud.resource.ResourceWrapper;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.script.Script;
|
||||||
|
|
||||||
|
@ResourceWrapper(handles = GetBackupStorageStatsCommand.class)
|
||||||
|
public class LibvirtGetBackupStatsCommandWrapper extends CommandWrapper<GetBackupStorageStatsCommand, Answer, LibvirtComputingResource> {
|
||||||
|
@Override
|
||||||
|
public Answer execute(GetBackupStorageStatsCommand command, LibvirtComputingResource libvirtComputingResource) {
|
||||||
|
final String backupRepoType = command.getBackupRepoType();
|
||||||
|
final String backupRepoAddress = command.getBackupRepoAddress();
|
||||||
|
final String mountOptions = command.getMountOptions();
|
||||||
|
|
||||||
|
List<String[]> commands = new ArrayList<>();
|
||||||
|
commands.add(new String[]{
|
||||||
|
libvirtComputingResource.getNasBackupPath(),
|
||||||
|
"-o", "stats",
|
||||||
|
"-t", backupRepoType,
|
||||||
|
"-s", backupRepoAddress,
|
||||||
|
"-m", mountOptions
|
||||||
|
});
|
||||||
|
|
||||||
|
Pair<Integer, String> result = Script.executePipedCommands(commands, libvirtComputingResource.getCmdsTimeout());
|
||||||
|
|
||||||
|
logger.debug(String.format("Get backup storage stats result: %s , exit code: %s", result.second(), result.first()));
|
||||||
|
|
||||||
|
if (result.first() != 0) {
|
||||||
|
logger.debug(String.format("Failed to get backup storage stats: %s", result.second()));
|
||||||
|
return new BackupStorageStatsAnswer(command, false, result.second());
|
||||||
|
}
|
||||||
|
|
||||||
|
BackupStorageStatsAnswer answer = new BackupStorageStatsAnswer(command, false, result.second());
|
||||||
|
|
||||||
|
String [] stats = result.second().split("\\s+");
|
||||||
|
Long total = Long.parseLong(stats[1]) * 1024;
|
||||||
|
Long used = Long.parseLong(stats[2]) * 1024;
|
||||||
|
answer.setTotalSize(total);
|
||||||
|
answer.setUsedSize(used);
|
||||||
|
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -58,21 +58,22 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||||||
String mountOptions = command.getMountOptions();
|
String mountOptions = command.getMountOptions();
|
||||||
Boolean vmExists = command.isVmExists();
|
Boolean vmExists = command.isVmExists();
|
||||||
String diskType = command.getDiskType();
|
String diskType = command.getDiskType();
|
||||||
List<String> volumePaths = command.getVolumePaths();
|
List<String> backedVolumeUUIDs = command.getBackupVolumesUUIDs();
|
||||||
|
List<String> restoreVolumePaths = command.getRestoreVolumePaths();
|
||||||
String restoreVolumeUuid = command.getRestoreVolumeUUID();
|
String restoreVolumeUuid = command.getRestoreVolumeUUID();
|
||||||
|
|
||||||
String newVolumeId = null;
|
String newVolumeId = null;
|
||||||
try {
|
try {
|
||||||
if (Objects.isNull(vmExists)) {
|
if (Objects.isNull(vmExists)) {
|
||||||
String volumePath = volumePaths.get(0);
|
String volumePath = restoreVolumePaths.get(0);
|
||||||
int lastIndex = volumePath.lastIndexOf("/");
|
int lastIndex = volumePath.lastIndexOf("/");
|
||||||
newVolumeId = volumePath.substring(lastIndex + 1);
|
newVolumeId = volumePath.substring(lastIndex + 1);
|
||||||
restoreVolume(backupPath, backupRepoType, backupRepoAddress, volumePath, diskType, restoreVolumeUuid,
|
restoreVolume(backupPath, backupRepoType, backupRepoAddress, volumePath, diskType, restoreVolumeUuid,
|
||||||
new Pair<>(vmName, command.getVmState()), mountOptions);
|
new Pair<>(vmName, command.getVmState()), mountOptions);
|
||||||
} else if (Boolean.TRUE.equals(vmExists)) {
|
} else if (Boolean.TRUE.equals(vmExists)) {
|
||||||
restoreVolumesOfExistingVM(volumePaths, backupPath, backupRepoType, backupRepoAddress, mountOptions);
|
restoreVolumesOfExistingVM(restoreVolumePaths, backedVolumeUUIDs, backupPath, backupRepoType, backupRepoAddress, mountOptions);
|
||||||
} else {
|
} else {
|
||||||
restoreVolumesOfDestroyedVMs(volumePaths, vmName, backupPath, backupRepoType, backupRepoAddress, mountOptions);
|
restoreVolumesOfDestroyedVMs(restoreVolumePaths, vmName, backupPath, backupRepoType, backupRepoAddress, mountOptions);
|
||||||
}
|
}
|
||||||
} catch (CloudRuntimeException e) {
|
} catch (CloudRuntimeException e) {
|
||||||
String errorMessage = "Failed to restore backup for VM: " + vmName + ".";
|
String errorMessage = "Failed to restore backup for VM: " + vmName + ".";
|
||||||
@ -86,24 +87,24 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||||||
return new BackupAnswer(command, true, newVolumeId);
|
return new BackupAnswer(command, true, newVolumeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreVolumesOfExistingVM(List<String> volumePaths, String backupPath,
|
private void restoreVolumesOfExistingVM(List<String> restoreVolumePaths, List<String> backedVolumesUUIDs, String backupPath,
|
||||||
String backupRepoType, String backupRepoAddress, String mountOptions) {
|
String backupRepoType, String backupRepoAddress, String mountOptions) {
|
||||||
String diskType = "root";
|
String diskType = "root";
|
||||||
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions);
|
String mountDirectory = mountBackupDirectory(backupRepoAddress, backupRepoType, mountOptions);
|
||||||
try {
|
try {
|
||||||
for (int idx = 0; idx < volumePaths.size(); idx++) {
|
for (int idx = 0; idx < restoreVolumePaths.size(); idx++) {
|
||||||
String volumePath = volumePaths.get(idx);
|
String restoreVolumePath = restoreVolumePaths.get(idx);
|
||||||
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
|
String backupVolumeUuid = backedVolumesUUIDs.get(idx);
|
||||||
|
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, null, backupPath, diskType, backupVolumeUuid);
|
||||||
diskType = "datadisk";
|
diskType = "datadisk";
|
||||||
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
|
if (!replaceVolumeWithBackup(restoreVolumePath, bkpPathAndVolUuid.first())) {
|
||||||
throw new CloudRuntimeException(String.format("Unable to restore backup for volume [%s].", bkpPathAndVolUuid.second()));
|
throw new CloudRuntimeException(String.format("Unable to restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
unmountBackupDirectory(mountDirectory);
|
unmountBackupDirectory(mountDirectory);
|
||||||
deleteTemporaryDirectory(mountDirectory);
|
deleteTemporaryDirectory(mountDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreVolumesOfDestroyedVMs(List<String> volumePaths, String vmName, String backupPath,
|
private void restoreVolumesOfDestroyedVMs(List<String> volumePaths, String vmName, String backupPath,
|
||||||
@ -116,7 +117,7 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||||||
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
|
Pair<String, String> bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, null);
|
||||||
diskType = "datadisk";
|
diskType = "datadisk";
|
||||||
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
|
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
|
||||||
throw new CloudRuntimeException(String.format("Unable to restore backup for volume [%s].", bkpPathAndVolUuid.second()));
|
throw new CloudRuntimeException(String.format("Unable to restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -132,7 +133,7 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||||||
try {
|
try {
|
||||||
bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, volumeUUID);
|
bkpPathAndVolUuid = getBackupPath(mountDirectory, volumePath, backupPath, diskType, volumeUUID);
|
||||||
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
|
if (!replaceVolumeWithBackup(volumePath, bkpPathAndVolUuid.first())) {
|
||||||
throw new CloudRuntimeException(String.format("Unable to restore backup for volume [%s].", bkpPathAndVolUuid.second()));
|
throw new CloudRuntimeException(String.format("Unable to restore contents from the backup volume [%s].", bkpPathAndVolUuid.second()));
|
||||||
}
|
}
|
||||||
if (VirtualMachine.State.Running.equals(vmNameAndState.second())) {
|
if (VirtualMachine.State.Running.equals(vmNameAndState.second())) {
|
||||||
if (!attachVolumeToVm(vmNameAndState.first(), volumePath)) {
|
if (!attachVolumeToVm(vmNameAndState.first(), volumePath)) {
|
||||||
@ -190,8 +191,7 @@ public class LibvirtRestoreBackupCommandWrapper extends CommandWrapper<RestoreBa
|
|||||||
|
|
||||||
private Pair<String, String> getBackupPath(String mountDirectory, String volumePath, String backupPath, String diskType, String volumeUuid) {
|
private Pair<String, String> getBackupPath(String mountDirectory, String volumePath, String backupPath, String diskType, String volumeUuid) {
|
||||||
String bkpPath = String.format(FILE_PATH_PLACEHOLDER, mountDirectory, backupPath);
|
String bkpPath = String.format(FILE_PATH_PLACEHOLDER, mountDirectory, backupPath);
|
||||||
int lastIndex = volumePath.lastIndexOf(File.separator);
|
String volUuid = Objects.isNull(volumeUuid) ? volumePath.substring(volumePath.lastIndexOf(File.separator) + 1) : volumeUuid;
|
||||||
String volUuid = Objects.isNull(volumeUuid) ? volumePath.substring(lastIndex + 1) : volumeUuid;
|
|
||||||
String backupFileName = String.format("%s.%s.qcow2", diskType.toLowerCase(Locale.ROOT), volUuid);
|
String backupFileName = String.format("%s.%s.qcow2", diskType.toLowerCase(Locale.ROOT), volUuid);
|
||||||
bkpPath = String.format(FILE_PATH_PLACEHOLDER, bkpPath, backupFileName);
|
bkpPath = String.format(FILE_PATH_PLACEHOLDER, bkpPath, backupFileName);
|
||||||
return new Pair<>(bkpPath, volUuid);
|
return new Pair<>(bkpPath, volUuid);
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
@ResourceWrapper(handles = TakeBackupCommand.class)
|
@ResourceWrapper(handles = TakeBackupCommand.class)
|
||||||
public class LibvirtTakeBackupCommandWrapper extends CommandWrapper<TakeBackupCommand, Answer, LibvirtComputingResource> {
|
public class LibvirtTakeBackupCommandWrapper extends CommandWrapper<TakeBackupCommand, Answer, LibvirtComputingResource> {
|
||||||
|
private static final Integer EXIT_CLEANUP_FAILED = 20;
|
||||||
@Override
|
@Override
|
||||||
public Answer execute(TakeBackupCommand command, LibvirtComputingResource libvirtComputingResource) {
|
public Answer execute(TakeBackupCommand command, LibvirtComputingResource libvirtComputingResource) {
|
||||||
final String vmName = command.getVmName();
|
final String vmName = command.getVmName();
|
||||||
@ -54,6 +55,7 @@ public class LibvirtTakeBackupCommandWrapper extends CommandWrapper<TakeBackupCo
|
|||||||
"-s", backupRepoAddress,
|
"-s", backupRepoAddress,
|
||||||
"-m", Objects.nonNull(mountOptions) ? mountOptions : "",
|
"-m", Objects.nonNull(mountOptions) ? mountOptions : "",
|
||||||
"-p", backupPath,
|
"-p", backupPath,
|
||||||
|
"-q", command.getQuiesce() != null && command.getQuiesce() ? "true" : "false",
|
||||||
"-d", (Objects.nonNull(diskPaths) && !diskPaths.isEmpty()) ? String.join(",", diskPaths) : ""
|
"-d", (Objects.nonNull(diskPaths) && !diskPaths.isEmpty()) ? String.join(",", diskPaths) : ""
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -61,7 +63,12 @@ public class LibvirtTakeBackupCommandWrapper extends CommandWrapper<TakeBackupCo
|
|||||||
|
|
||||||
if (result.first() != 0) {
|
if (result.first() != 0) {
|
||||||
logger.debug("Failed to take VM backup: " + result.second());
|
logger.debug("Failed to take VM backup: " + result.second());
|
||||||
return new BackupAnswer(command, false, result.second().trim());
|
BackupAnswer answer = new BackupAnswer(command, false, result.second().trim());
|
||||||
|
if (result.first() == EXIT_CLEANUP_FAILED) {
|
||||||
|
logger.debug("Backup cleanup failed");
|
||||||
|
answer.setNeedsCleanup(true);
|
||||||
|
}
|
||||||
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
long backupSize = 0L;
|
long backupSize = 0L;
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
package com.cloud.simulator;
|
package com.cloud.simulator;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -35,8 +36,8 @@ import com.cloud.storage.dao.VolumeDao;
|
|||||||
import com.cloud.vm.VMInstanceVO;
|
import com.cloud.vm.VMInstanceVO;
|
||||||
import com.cloud.vm.VirtualMachine;
|
import com.cloud.vm.VirtualMachine;
|
||||||
import com.cloud.vm.VirtualMachineProfile;
|
import com.cloud.vm.VirtualMachineProfile;
|
||||||
import com.cloud.vm.dao.NicDao;
|
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
|
import com.cloud.vm.dao.NicDao;
|
||||||
|
|
||||||
public class SimulatorGuru extends HypervisorGuruBase implements HypervisorGuru {
|
public class SimulatorGuru extends HypervisorGuruBase implements HypervisorGuru {
|
||||||
@Inject
|
@Inject
|
||||||
@ -90,6 +91,29 @@ public class SimulatorGuru extends HypervisorGuruBase implements HypervisorGuru
|
|||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean attachRestoredVolumeToVirtualMachine(long zoneId, String location, Backup.VolumeInfo volumeInfo, VirtualMachine vm, long poolId, Backup backup) {
|
||||||
|
|
||||||
|
VMInstanceVO targetVM = instanceDao.findVMByInstanceNameIncludingRemoved(vm.getName());
|
||||||
|
List<VolumeVO> vmVolumes = volumeDao.findByInstance(targetVM.getId());
|
||||||
|
VolumeVO restoredVolume = volumeDao.findByUuid(location);
|
||||||
|
if (restoredVolume != null) {
|
||||||
|
try {
|
||||||
|
volumeDao.attachVolume(restoredVolume.getId(), vm.getId(), getNextAvailableDeviceId(vmVolumes));
|
||||||
|
restoredVolume.setState(Volume.State.Ready);
|
||||||
|
volumeDao.update(restoredVolume.getId(), restoredVolume);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
restoredVolume.setDisplay(false);
|
||||||
|
restoredVolume.setDisplayVolume(false);
|
||||||
|
restoredVolume.setState(Volume.State.Destroy);
|
||||||
|
volumeDao.update(restoredVolume.getId(), restoredVolume);
|
||||||
|
throw new RuntimeException("Unable to attach volume " + restoredVolume.getName() + " to VM" + vm.getName() + " due to : " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean trackVmHostChange() {
|
public boolean trackVmHostChange() {
|
||||||
return false;
|
return false;
|
||||||
@ -100,4 +124,11 @@ public class SimulatorGuru extends HypervisorGuruBase implements HypervisorGuru
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getNextAvailableDeviceId(List<VolumeVO> vmVolumes) {
|
||||||
|
if (vmVolumes == null || vmVolumes.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
long maxDeviceId = vmVolumes.stream() .mapToLong(VolumeVO::getDeviceId) .max() .orElse(-1);
|
||||||
|
return maxDeviceId + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -870,7 +870,9 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||||||
try {
|
try {
|
||||||
List<Backup.VolumeInfo> list = new ArrayList<>();
|
List<Backup.VolumeInfo> list = new ArrayList<>();
|
||||||
for (VolumeVO vol : vmVolumes) {
|
for (VolumeVO vol : vmVolumes) {
|
||||||
list.add(new Backup.VolumeInfo(vol.getUuid(), vol.getPath(), vol.getVolumeType(), vol.getSize()));
|
DiskOfferingVO diskOffering = diskOfferingDao.findById(vol.getDiskOfferingId());
|
||||||
|
list.add(new Backup.VolumeInfo(vol.getUuid(), vol.getPath(), vol.getVolumeType(), vol.getSize(),
|
||||||
|
vol.getDeviceId(), diskOffering.getUuid(), vol.getMinIops(), vol.getMaxIops()));
|
||||||
}
|
}
|
||||||
return GSON.toJson(list.toArray(), Backup.VolumeInfo[].class);
|
return GSON.toJson(list.toArray(), Backup.VolumeInfo[].class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@ -69,12 +69,14 @@ import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
|
|||||||
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||||
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
import com.cloud.hypervisor.vmware.util.VmwareContext;
|
||||||
import com.cloud.hypervisor.vmware.util.VmwareHelper;
|
import com.cloud.hypervisor.vmware.util.VmwareHelper;
|
||||||
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.Storage.ProvisioningType;
|
import com.cloud.storage.Storage.ProvisioningType;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.StoragePoolHostVO;
|
import com.cloud.storage.StoragePoolHostVO;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.VolumeVO;
|
import com.cloud.storage.VolumeVO;
|
||||||
|
import com.cloud.storage.dao.DiskOfferingDao;
|
||||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.UuidUtils;
|
import com.cloud.utils.UuidUtils;
|
||||||
@ -110,6 +112,9 @@ public class VMwareGuruTest {
|
|||||||
@Mock
|
@Mock
|
||||||
ClusterDetailsDao _clusterDetailsDao;
|
ClusterDetailsDao _clusterDetailsDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
DiskOfferingDao diskOfferingDao;
|
||||||
|
|
||||||
AutoCloseable closeable;
|
AutoCloseable closeable;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@ -187,19 +192,26 @@ public class VMwareGuruTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createVolumeInfoFromVolumesTestCorrectlyConvertOfVolumes() {
|
public void createVolumeInfoFromVolumesTestCorrectlyConvertOfVolumes() {
|
||||||
|
Long diskOfferingId = 5L;
|
||||||
|
DiskOfferingVO diskOffering = Mockito.mock(DiskOfferingVO.class);
|
||||||
|
Mockito.when(diskOffering.getUuid()).thenReturn("disk-offering-uuid");
|
||||||
|
Mockito.when(diskOfferingDao.findById(diskOfferingId)).thenReturn(diskOffering);
|
||||||
|
|
||||||
List<VolumeVO> volumesToTest = new ArrayList<>();
|
List<VolumeVO> volumesToTest = new ArrayList<>();
|
||||||
|
|
||||||
VolumeVO root = new VolumeVO("test", 1l, 1l, 1l, 1l, 1l, "test", "/root/dir", ProvisioningType.THIN, 555l, Volume.Type.ROOT);
|
VolumeVO root = new VolumeVO("test", 1l, 1l, 1l, 1l, 6l, "test", "/root/dir", ProvisioningType.THIN, 555l, Volume.Type.ROOT);
|
||||||
|
root.setDiskOfferingId(diskOfferingId);
|
||||||
String rootUuid = root.getUuid();
|
String rootUuid = root.getUuid();
|
||||||
|
|
||||||
VolumeVO data = new VolumeVO("test", 1l, 1l, 1l, 1l, 1l, "test", "/root/dir/data", ProvisioningType.THIN, 1111000l, Volume.Type.DATADISK);
|
VolumeVO data = new VolumeVO("test", 1l, 1l, 1l, 1l, 1l, "test", "/root/dir/data", ProvisioningType.THIN, 1111000l, Volume.Type.DATADISK);
|
||||||
|
data.setDiskOfferingId(diskOfferingId);
|
||||||
String dataUuid = data.getUuid();
|
String dataUuid = data.getUuid();
|
||||||
|
|
||||||
volumesToTest.add(root);
|
volumesToTest.add(root);
|
||||||
volumesToTest.add(data);
|
volumesToTest.add(data);
|
||||||
|
|
||||||
String result = vMwareGuru.createVolumeInfoFromVolumes(volumesToTest);
|
String result = vMwareGuru.createVolumeInfoFromVolumes(volumesToTest);
|
||||||
String expected = String.format("[{\"uuid\":\"%s\",\"type\":\"ROOT\",\"size\":555,\"path\":\"/root/dir\"},{\"uuid\":\"%s\",\"type\":\"DATADISK\",\"size\":1111000,\"path\":\"/root/dir/data\"}]", rootUuid, dataUuid);
|
String expected = String.format("[{\"uuid\":\"%s\",\"type\":\"ROOT\",\"size\":555,\"path\":\"/root/dir\",\"diskOfferingId\":\"disk-offering-uuid\"},{\"uuid\":\"%s\",\"type\":\"DATADISK\",\"size\":1111000,\"path\":\"/root/dir/data\",\"diskOfferingId\":\"disk-offering-uuid\"}]", rootUuid, dataUuid);
|
||||||
|
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -421,13 +421,13 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
|
|||||||
List<Long> securityGroupIds = new ArrayList<>();
|
List<Long> securityGroupIds = new ArrayList<>();
|
||||||
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
||||||
nodeVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, workerNodeTemplate, networkIds, securityGroupIds, owner,
|
nodeVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, workerNodeTemplate, networkIds, securityGroupIds, owner,
|
||||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
hostName, hostName, null, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
||||||
null, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
null, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
||||||
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null,
|
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null,
|
||||||
null, true, null, UserVmManager.CKS_NODE, null, null);
|
null, true, null, UserVmManager.CKS_NODE, null, null);
|
||||||
} else {
|
} else {
|
||||||
nodeVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, workerNodeTemplate, networkIds, owner,
|
nodeVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, workerNodeTemplate, networkIds, owner,
|
||||||
hostName, hostName, null, null, null,
|
hostName, hostName, null, null, null, null,
|
||||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
||||||
null, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
null, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
||||||
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null, null, null);
|
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null, null, null);
|
||||||
|
|||||||
@ -276,13 +276,13 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
|||||||
List<Long> securityGroupIds = new ArrayList<>();
|
List<Long> securityGroupIds = new ArrayList<>();
|
||||||
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
||||||
controlVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, controlNodeTemplate, networkIds, securityGroupIds, owner,
|
controlVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, controlNodeTemplate, networkIds, securityGroupIds, owner,
|
||||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, userDataId, userDataDetails, keypairs,
|
hostName, hostName, null, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, userDataId, userDataDetails, keypairs,
|
||||||
requestedIps, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
requestedIps, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
||||||
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null,
|
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null,
|
||||||
null, true, null, UserVmManager.CKS_NODE, null, null);
|
null, true, null, UserVmManager.CKS_NODE, null, null);
|
||||||
} else {
|
} else {
|
||||||
controlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, controlNodeTemplate, networkIds, owner,
|
controlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, controlNodeTemplate, networkIds, owner,
|
||||||
hostName, hostName, null, null, null,
|
hostName, hostName, null, null, null, null,
|
||||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, userDataId, userDataDetails, keypairs,
|
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, userDataId, userDataDetails, keypairs,
|
||||||
requestedIps, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
requestedIps, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
||||||
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null, null, null);
|
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null, null, null);
|
||||||
@ -444,13 +444,13 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
|||||||
List<Long> securityGroupIds = new ArrayList<>();
|
List<Long> securityGroupIds = new ArrayList<>();
|
||||||
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
||||||
additionalControlVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, controlNodeTemplate, networkIds, securityGroupIds, owner,
|
additionalControlVm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, controlNodeTemplate, networkIds, securityGroupIds, owner,
|
||||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
hostName, hostName, null, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
||||||
null, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
null, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
||||||
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null,
|
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null,
|
||||||
null, true, null, UserVmManager.CKS_NODE, null, null);
|
null, true, null, UserVmManager.CKS_NODE, null, null);
|
||||||
} else {
|
} else {
|
||||||
additionalControlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, controlNodeTemplate, networkIds, owner,
|
additionalControlVm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, controlNodeTemplate, networkIds, owner,
|
||||||
hostName, hostName, null, null, null,
|
hostName, hostName, null, null, null, null,
|
||||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
||||||
null, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
null, addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
||||||
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null, null, null);
|
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null, null, null);
|
||||||
@ -488,13 +488,13 @@ public class KubernetesClusterStartWorker extends KubernetesClusterResourceModif
|
|||||||
List<Long> securityGroupIds = new ArrayList<>();
|
List<Long> securityGroupIds = new ArrayList<>();
|
||||||
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
securityGroupIds.add(kubernetesCluster.getSecurityGroupId());
|
||||||
etcdNode = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, etcdTemplate, networkIds, securityGroupIds, owner,
|
etcdNode = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, etcdTemplate, networkIds, securityGroupIds, owner,
|
||||||
hostName, hostName, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
hostName, hostName, null, null, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST,base64UserData, null, null, keypairs,
|
||||||
Map.of(kubernetesCluster.getNetworkId(), requestedIps.get(etcdNodeIndex)), addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
Map.of(kubernetesCluster.getNetworkId(), requestedIps.get(etcdNodeIndex)), addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
||||||
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null,
|
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null,
|
||||||
null, true, null, null, null, null);
|
null, true, null, null, null, null);
|
||||||
} else {
|
} else {
|
||||||
etcdNode = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, etcdTemplate, networkIds, owner,
|
etcdNode = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, etcdTemplate, networkIds, owner,
|
||||||
hostName, hostName, null, null, null,
|
hostName, hostName, null, null, null, null,
|
||||||
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData, null, null, keypairs,
|
||||||
Map.of(kubernetesCluster.getNetworkId(), requestedIps.get(etcdNodeIndex)), addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
Map.of(kubernetesCluster.getNetworkId(), requestedIps.get(etcdNodeIndex)), addrs, null, null, Objects.nonNull(affinityGroupId) ?
|
||||||
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null, null, null);
|
Collections.singletonList(affinityGroupId) : null, customParameterMap, null, null, null, null, true, UserVmManager.CKS_NODE, null, null, null);
|
||||||
|
|||||||
@ -54,6 +54,7 @@ public class CephObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {
|
|||||||
public DataStore initialize(Map<String, Object> dsInfos) {
|
public DataStore initialize(Map<String, Object> dsInfos) {
|
||||||
String url = (String)dsInfos.get("url");
|
String url = (String)dsInfos.get("url");
|
||||||
String name = (String)dsInfos.get("name");
|
String name = (String)dsInfos.get("name");
|
||||||
|
Long size = (Long)dsInfos.get("size");
|
||||||
String providerName = (String)dsInfos.get("providerName");
|
String providerName = (String)dsInfos.get("providerName");
|
||||||
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||||
if (details == null) {
|
if (details == null) {
|
||||||
@ -67,6 +68,7 @@ public class CephObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {
|
|||||||
Map<String, Object> objectStoreParameters = new HashMap();
|
Map<String, Object> objectStoreParameters = new HashMap();
|
||||||
objectStoreParameters.put("name", name);
|
objectStoreParameters.put("name", name);
|
||||||
objectStoreParameters.put("url", url);
|
objectStoreParameters.put("url", url);
|
||||||
|
objectStoreParameters.put("size", size);
|
||||||
|
|
||||||
objectStoreParameters.put("providerName", providerName);
|
objectStoreParameters.put("providerName", providerName);
|
||||||
objectStoreParameters.put("accesskey", accessKey);
|
objectStoreParameters.put("accesskey", accessKey);
|
||||||
|
|||||||
@ -53,6 +53,7 @@ public class MinIOObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {
|
|||||||
|
|
||||||
String url = (String)dsInfos.get("url");
|
String url = (String)dsInfos.get("url");
|
||||||
String name = (String)dsInfos.get("name");
|
String name = (String)dsInfos.get("name");
|
||||||
|
Long size = (Long)dsInfos.get("size");
|
||||||
String providerName = (String)dsInfos.get("providerName");
|
String providerName = (String)dsInfos.get("providerName");
|
||||||
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||||
if(details == null){
|
if(details == null){
|
||||||
@ -65,6 +66,7 @@ public class MinIOObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {
|
|||||||
Map<String, Object> objectStoreParameters = new HashMap();
|
Map<String, Object> objectStoreParameters = new HashMap();
|
||||||
objectStoreParameters.put("name", name);
|
objectStoreParameters.put("name", name);
|
||||||
objectStoreParameters.put("url", url);
|
objectStoreParameters.put("url", url);
|
||||||
|
objectStoreParameters.put("size", size);
|
||||||
|
|
||||||
objectStoreParameters.put("providerName", providerName);
|
objectStoreParameters.put("providerName", providerName);
|
||||||
objectStoreParameters.put("accesskey", accessKey);
|
objectStoreParameters.put("accesskey", accessKey);
|
||||||
|
|||||||
@ -65,12 +65,14 @@ public class SimulatorObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {
|
|||||||
String url = (String)dsInfos.get("url");
|
String url = (String)dsInfos.get("url");
|
||||||
String name = (String)dsInfos.get("name");
|
String name = (String)dsInfos.get("name");
|
||||||
String providerName = (String)dsInfos.get("providerName");
|
String providerName = (String)dsInfos.get("providerName");
|
||||||
|
Long size = (Long)dsInfos.get("size");
|
||||||
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
|
||||||
|
|
||||||
Map<String, Object> objectStoreParameters = new HashMap();
|
Map<String, Object> objectStoreParameters = new HashMap();
|
||||||
objectStoreParameters.put("name", name);
|
objectStoreParameters.put("name", name);
|
||||||
objectStoreParameters.put("url", url);
|
objectStoreParameters.put("url", url);
|
||||||
objectStoreParameters.put("providerName", providerName);
|
objectStoreParameters.put("providerName", providerName);
|
||||||
|
objectStoreParameters.put("size", size);
|
||||||
|
|
||||||
ObjectStoreVO ids = objectStoreHelper.createObjectStore(objectStoreParameters, details);
|
ObjectStoreVO ids = objectStoreHelper.createObjectStore(objectStoreParameters, details);
|
||||||
return objectStoreMgr.getObjectStore(ids.getId());
|
return objectStoreMgr.getObjectStore(ids.getId());
|
||||||
|
|||||||
@ -195,7 +195,7 @@ public class StorageVmSharedFSLifeCycle implements SharedFSLifeCycle {
|
|||||||
CallContext vmContext = CallContext.register(CallContext.current(), ApiCommandResourceType.VirtualMachine);
|
CallContext vmContext = CallContext.register(CallContext.current(), ApiCommandResourceType.VirtualMachine);
|
||||||
try {
|
try {
|
||||||
vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, hostName, hostName,
|
vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, hostName, hostName,
|
||||||
diskOfferingId, size, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData,
|
diskOfferingId, size, null, null, Hypervisor.HypervisorType.None, BaseCmd.HTTPMethod.POST, base64UserData,
|
||||||
null, null, keypairs, null, addrs, null, null, null,
|
null, null, keypairs, null, addrs, null, null, null,
|
||||||
customParameterMap, null, null, null, null,
|
customParameterMap, null, null, null, null,
|
||||||
true, UserVmManager.SHAREDFSVM, null, null, null);
|
true, UserVmManager.SHAREDFSVM, null, null, null);
|
||||||
|
|||||||
@ -254,7 +254,7 @@ public class StorageVmSharedFSLifeCycleTest {
|
|||||||
when(vm.getId()).thenReturn(s_vmId);
|
when(vm.getId()).thenReturn(s_vmId);
|
||||||
when(userVmService.createAdvancedVirtualMachine(
|
when(userVmService.createAdvancedVirtualMachine(
|
||||||
any(DataCenter.class), any(ServiceOffering.class), any(VirtualMachineTemplate.class), anyList(), any(Account.class), anyString(),
|
any(DataCenter.class), any(ServiceOffering.class), any(VirtualMachineTemplate.class), anyList(), any(Account.class), anyString(),
|
||||||
anyString(), anyLong(), anyLong(), isNull(), any(Hypervisor.HypervisorType.class), any(BaseCmd.HTTPMethod.class), anyString(),
|
anyString(), anyLong(), anyLong(), any(), isNull(), any(Hypervisor.HypervisorType.class), any(BaseCmd.HTTPMethod.class), anyString(),
|
||||||
isNull(), isNull(), anyList(), isNull(), any(Network.IpAddresses.class), isNull(), isNull(), isNull(),
|
isNull(), isNull(), anyList(), isNull(), any(Network.IpAddresses.class), isNull(), isNull(), isNull(),
|
||||||
anyMap(), isNull(), isNull(), isNull(), isNull(),
|
anyMap(), isNull(), isNull(), isNull(), isNull(),
|
||||||
anyBoolean(), anyString(), isNull(), isNull(), isNull())).thenReturn(vm);
|
anyBoolean(), anyString(), isNull(), isNull(), isNull())).thenReturn(vm);
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
## specific language governing permissions and limitations
|
## specific language governing permissions and limitations
|
||||||
## under the License.
|
## under the License.
|
||||||
|
|
||||||
set -e
|
set -eo pipefail
|
||||||
|
|
||||||
# CloudStack B&R NAS Backup and Recovery Tool for KVM
|
# CloudStack B&R NAS Backup and Recovery Tool for KVM
|
||||||
|
|
||||||
@ -31,8 +31,11 @@ NAS_ADDRESS=""
|
|||||||
MOUNT_OPTS=""
|
MOUNT_OPTS=""
|
||||||
BACKUP_DIR=""
|
BACKUP_DIR=""
|
||||||
DISK_PATHS=""
|
DISK_PATHS=""
|
||||||
|
QUIESCE=""
|
||||||
logFile="/var/log/cloudstack/agent/agent.log"
|
logFile="/var/log/cloudstack/agent/agent.log"
|
||||||
|
|
||||||
|
EXIT_CLEANUP_FAILED=20
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
[[ "$verb" -eq 1 ]] && builtin echo "$@"
|
[[ "$verb" -eq 1 ]] && builtin echo "$@"
|
||||||
if [[ "$1" == "-ne" || "$1" == "-e" || "$1" == "-n" ]]; then
|
if [[ "$1" == "-ne" || "$1" == "-e" || "$1" == "-n" ]]; then
|
||||||
@ -88,7 +91,7 @@ sanity_checks() {
|
|||||||
|
|
||||||
backup_running_vm() {
|
backup_running_vm() {
|
||||||
mount_operation
|
mount_operation
|
||||||
mkdir -p $dest
|
mkdir -p "$dest" || { echo "Failed to create backup directory $dest"; exit 1; }
|
||||||
|
|
||||||
name="root"
|
name="root"
|
||||||
echo "<domainbackup mode='push'><disks>" > $dest/backup.xml
|
echo "<domainbackup mode='push'><disks>" > $dest/backup.xml
|
||||||
@ -99,8 +102,31 @@ backup_running_vm() {
|
|||||||
done
|
done
|
||||||
echo "</disks></domainbackup>" >> $dest/backup.xml
|
echo "</disks></domainbackup>" >> $dest/backup.xml
|
||||||
|
|
||||||
|
local thaw=0
|
||||||
|
if [[ ${QUIESCE} == "true" ]]; then
|
||||||
|
if virsh -c qemu:///system qemu-agent-command "$VM" '{"execute":"guest-fsfreeze-freeze"}' > /dev/null 2>/dev/null; then
|
||||||
|
thaw=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Start push backup
|
# Start push backup
|
||||||
virsh -c qemu:///system backup-begin --domain $VM --backupxml $dest/backup.xml > /dev/null 2>/dev/null
|
local backup_begin=0
|
||||||
|
if virsh -c qemu:///system backup-begin --domain $VM --backupxml $dest/backup.xml 2>&1 > /dev/null; then
|
||||||
|
backup_begin=1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $thaw -eq 1 ]]; then
|
||||||
|
if ! response=$(virsh -c qemu:///system qemu-agent-command "$VM" '{"execute":"guest-fsfreeze-thaw"}' 2>&1 > /dev/null); then
|
||||||
|
echo "Failed to thaw the filesystem for vm $VM: $response"
|
||||||
|
cleanup
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $backup_begin -ne 1 ]]; then
|
||||||
|
cleanup
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Backup domain information
|
# Backup domain information
|
||||||
virsh -c qemu:///system dumpxml $VM > $dest/domain-config.xml 2>/dev/null
|
virsh -c qemu:///system dumpxml $VM > $dest/domain-config.xml 2>/dev/null
|
||||||
@ -108,9 +134,18 @@ backup_running_vm() {
|
|||||||
virsh -c qemu:///system domiflist $VM > $dest/domiflist.xml 2>/dev/null
|
virsh -c qemu:///system domiflist $VM > $dest/domiflist.xml 2>/dev/null
|
||||||
virsh -c qemu:///system domblklist $VM > $dest/domblklist.xml 2>/dev/null
|
virsh -c qemu:///system domblklist $VM > $dest/domblklist.xml 2>/dev/null
|
||||||
|
|
||||||
until virsh -c qemu:///system domjobinfo $VM --completed --keep-completed 2>/dev/null | grep "Completed" > /dev/null; do
|
while true; do
|
||||||
|
status=$(virsh -c qemu:///system domjobinfo $VM --completed --keep-completed | awk '/Job type:/ {print $3}')
|
||||||
|
case "$status" in
|
||||||
|
Completed)
|
||||||
|
break ;;
|
||||||
|
Failed)
|
||||||
|
echo "Virsh backup job failed"
|
||||||
|
cleanup ;;
|
||||||
|
esac
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
|
|
||||||
rm -f $dest/backup.xml
|
rm -f $dest/backup.xml
|
||||||
sync
|
sync
|
||||||
|
|
||||||
@ -124,14 +159,18 @@ backup_running_vm() {
|
|||||||
|
|
||||||
backup_stopped_vm() {
|
backup_stopped_vm() {
|
||||||
mount_operation
|
mount_operation
|
||||||
mkdir -p $dest
|
mkdir -p "$dest" || { echo "Failed to create backup directory $dest"; exit 1; }
|
||||||
|
|
||||||
IFS=","
|
IFS=","
|
||||||
|
|
||||||
name="root"
|
name="root"
|
||||||
for disk in $DISK_PATHS; do
|
for disk in $DISK_PATHS; do
|
||||||
volUuid="${disk##*/}"
|
volUuid="${disk##*/}"
|
||||||
qemu-img convert -O qcow2 $disk $dest/$name.$volUuid.qcow2 | tee -a "$logFile"
|
output="$dest/$name.$volUuid.qcow2"
|
||||||
|
if ! qemu-img convert -O qcow2 "$disk" "$output" > "$logFile" 2> >(cat >&2); then
|
||||||
|
echo "qemu-img convert failed for $disk $output"
|
||||||
|
cleanup
|
||||||
|
fi
|
||||||
name="datadisk"
|
name="datadisk"
|
||||||
done
|
done
|
||||||
sync
|
sync
|
||||||
@ -148,13 +187,22 @@ delete_backup() {
|
|||||||
rmdir $mount_point
|
rmdir $mount_point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_backup_stats() {
|
||||||
|
mount_operation
|
||||||
|
|
||||||
|
echo $mount_point
|
||||||
|
df -P $mount_point 2>/dev/null | awk 'NR==2 {print $2, $3}'
|
||||||
|
umount $mount_point
|
||||||
|
rmdir $mount_point
|
||||||
|
}
|
||||||
|
|
||||||
mount_operation() {
|
mount_operation() {
|
||||||
mount_point=$(mktemp -d -t csbackup.XXXXX)
|
mount_point=$(mktemp -d -t csbackup.XXXXX)
|
||||||
dest="$mount_point/${BACKUP_DIR}"
|
dest="$mount_point/${BACKUP_DIR}"
|
||||||
if [ ${NAS_TYPE} == "cifs" ]; then
|
if [ ${NAS_TYPE} == "cifs" ]; then
|
||||||
MOUNT_OPTS="${MOUNT_OPTS},nobrl"
|
MOUNT_OPTS="${MOUNT_OPTS},nobrl"
|
||||||
fi
|
fi
|
||||||
mount -t ${NAS_TYPE} ${NAS_ADDRESS} ${mount_point} $([[ ! -z "${MOUNT_OPTS}" ]] && echo -o ${MOUNT_OPTS}) | tee -a "$logFile"
|
mount -t ${NAS_TYPE} ${NAS_ADDRESS} ${mount_point} $([[ ! -z "${MOUNT_OPTS}" ]] && echo -o ${MOUNT_OPTS}) 2>&1 | tee -a "$logFile"
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
log -ne "Successfully mounted ${NAS_TYPE} store"
|
log -ne "Successfully mounted ${NAS_TYPE} store"
|
||||||
else
|
else
|
||||||
@ -163,9 +211,22 @@ mount_operation() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
local status=0
|
||||||
|
|
||||||
|
rm -rf "$dest" || { echo "Failed to delete $dest"; status=1; }
|
||||||
|
umount "$mount_point" || { echo "Failed to unmount $mount_point"; status=1; }
|
||||||
|
rmdir "$mount_point" || { echo "Failed to remove mount point $mount_point"; status=1; }
|
||||||
|
|
||||||
|
if [[ $status -ne 0 ]]; then
|
||||||
|
echo "Backup cleanup failed"
|
||||||
|
exit $EXIT_CLEANUP_FAILED
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
function usage {
|
function usage {
|
||||||
echo ""
|
echo ""
|
||||||
echo "Usage: $0 -o <operation> -v|--vm <domain name> -t <storage type> -s <storage address> -m <mount options> -p <backup path> -d <disks path>"
|
echo "Usage: $0 -o <operation> -v|--vm <domain name> -t <storage type> -s <storage address> -m <mount options> -p <backup path> -d <disks path> -q|--quiesce <true|false>"
|
||||||
echo ""
|
echo ""
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
@ -202,6 +263,11 @@ while [[ $# -gt 0 ]]; do
|
|||||||
shift
|
shift
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
-q|--quiesce)
|
||||||
|
QUIESCE="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-d|--diskpaths)
|
-d|--diskpaths)
|
||||||
DISK_PATHS="$2"
|
DISK_PATHS="$2"
|
||||||
shift
|
shift
|
||||||
@ -222,12 +288,14 @@ done
|
|||||||
sanity_checks
|
sanity_checks
|
||||||
|
|
||||||
if [ "$OP" = "backup" ]; then
|
if [ "$OP" = "backup" ]; then
|
||||||
STATE=$(virsh -c qemu:///system list | grep $VM | awk '{print $3}')
|
STATE=$(virsh -c qemu:///system list | awk -v vm="$VM" '$2 == vm {print $3}')
|
||||||
if [ "$STATE" = "running" ]; then
|
if [ -n "$STATE" ] && [ "$STATE" = "running" ]; then
|
||||||
backup_running_vm
|
backup_running_vm
|
||||||
else
|
else
|
||||||
backup_stopped_vm
|
backup_stopped_vm
|
||||||
fi
|
fi
|
||||||
elif [ "$OP" = "delete" ]; then
|
elif [ "$OP" = "delete" ]; then
|
||||||
delete_backup
|
delete_backup
|
||||||
|
elif [ "$OP" = "stats" ]; then
|
||||||
|
get_backup_stats
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -37,11 +37,17 @@ import javax.inject.Inject;
|
|||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.dc.Pod;
|
||||||
|
import com.cloud.org.Cluster;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.backup.BackupManager;
|
||||||
import org.apache.cloudstack.framework.config.ConfigDepot;
|
import org.apache.cloudstack.framework.config.ConfigDepot;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
|
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
|
||||||
|
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.utils.mailing.MailAddress;
|
import org.apache.cloudstack.utils.mailing.MailAddress;
|
||||||
@ -64,11 +70,9 @@ import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity;
|
|||||||
import com.cloud.configuration.Config;
|
import com.cloud.configuration.Config;
|
||||||
import com.cloud.configuration.ConfigurationManager;
|
import com.cloud.configuration.ConfigurationManager;
|
||||||
import com.cloud.dc.ClusterVO;
|
import com.cloud.dc.ClusterVO;
|
||||||
import com.cloud.dc.DataCenter;
|
|
||||||
import com.cloud.dc.DataCenter.NetworkType;
|
import com.cloud.dc.DataCenter.NetworkType;
|
||||||
import com.cloud.dc.DataCenterVO;
|
import com.cloud.dc.DataCenterVO;
|
||||||
import com.cloud.dc.HostPodVO;
|
import com.cloud.dc.HostPodVO;
|
||||||
import com.cloud.dc.Pod;
|
|
||||||
import com.cloud.dc.Vlan.VlanType;
|
import com.cloud.dc.Vlan.VlanType;
|
||||||
import com.cloud.dc.dao.ClusterDao;
|
import com.cloud.dc.dao.ClusterDao;
|
||||||
import com.cloud.dc.dao.DataCenterDao;
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
@ -82,7 +86,6 @@ import com.cloud.host.HostVO;
|
|||||||
import com.cloud.host.dao.HostDao;
|
import com.cloud.host.dao.HostDao;
|
||||||
import com.cloud.network.Ipv6Service;
|
import com.cloud.network.Ipv6Service;
|
||||||
import com.cloud.network.dao.IPAddressDao;
|
import com.cloud.network.dao.IPAddressDao;
|
||||||
import com.cloud.org.Cluster;
|
|
||||||
import com.cloud.org.Grouping.AllocationState;
|
import com.cloud.org.Grouping.AllocationState;
|
||||||
import com.cloud.resource.ResourceManager;
|
import com.cloud.resource.ResourceManager;
|
||||||
import com.cloud.storage.StorageManager;
|
import com.cloud.storage.StorageManager;
|
||||||
@ -143,8 +146,12 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
@Inject
|
@Inject
|
||||||
ConfigurationManager _configMgr;
|
ConfigurationManager _configMgr;
|
||||||
@Inject
|
@Inject
|
||||||
|
protected BackupManager backupManager;
|
||||||
|
@Inject
|
||||||
protected ConfigDepot _configDepot;
|
protected ConfigDepot _configDepot;
|
||||||
@Inject
|
@Inject
|
||||||
|
private ObjectStoreDao _objectStoreDao;
|
||||||
|
@Inject
|
||||||
Ipv6Service ipv6Service;
|
Ipv6Service ipv6Service;
|
||||||
@Inject
|
@Inject
|
||||||
HostDao hostDao;
|
HostDao hostDao;
|
||||||
@ -157,6 +164,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
private double _vlanCapacityThreshold = 0.75;
|
private double _vlanCapacityThreshold = 0.75;
|
||||||
private double _directNetworkPublicIpCapacityThreshold = 0.75;
|
private double _directNetworkPublicIpCapacityThreshold = 0.75;
|
||||||
private double _localStorageCapacityThreshold = 0.75;
|
private double _localStorageCapacityThreshold = 0.75;
|
||||||
|
private double _backupStorageCapacityThreshold = 0.75;
|
||||||
|
private double _objectStorageCapacityThreshold = 0.75;
|
||||||
Map<Short, Double> _capacityTypeThresholdMap = new HashMap<>();
|
Map<Short, Double> _capacityTypeThresholdMap = new HashMap<>();
|
||||||
|
|
||||||
private final ExecutorService _executor;
|
private final ExecutorService _executor;
|
||||||
@ -199,6 +208,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
String vlanCapacityThreshold = _configDao.getValue(Config.VlanCapacityThreshold.key());
|
String vlanCapacityThreshold = _configDao.getValue(Config.VlanCapacityThreshold.key());
|
||||||
String directNetworkPublicIpCapacityThreshold = _configDao.getValue(Config.DirectNetworkPublicIpCapacityThreshold.key());
|
String directNetworkPublicIpCapacityThreshold = _configDao.getValue(Config.DirectNetworkPublicIpCapacityThreshold.key());
|
||||||
String localStorageCapacityThreshold = _configDao.getValue(Config.LocalStorageCapacityThreshold.key());
|
String localStorageCapacityThreshold = _configDao.getValue(Config.LocalStorageCapacityThreshold.key());
|
||||||
|
String backupStorageCapacityThreshold = _configDao.getValue(BackupManager.BackupStorageCapacityThreshold.key());
|
||||||
|
String objectStorageCapacityThreshold = _configDao.getValue(_storageMgr.ObjectStorageCapacityThreshold.key());
|
||||||
|
|
||||||
if (publicIPCapacityThreshold != null) {
|
if (publicIPCapacityThreshold != null) {
|
||||||
_publicIPCapacityThreshold = Double.parseDouble(publicIPCapacityThreshold);
|
_publicIPCapacityThreshold = Double.parseDouble(publicIPCapacityThreshold);
|
||||||
@ -218,6 +229,12 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
if (localStorageCapacityThreshold != null) {
|
if (localStorageCapacityThreshold != null) {
|
||||||
_localStorageCapacityThreshold = Double.parseDouble(localStorageCapacityThreshold);
|
_localStorageCapacityThreshold = Double.parseDouble(localStorageCapacityThreshold);
|
||||||
}
|
}
|
||||||
|
if (backupStorageCapacityThreshold != null) {
|
||||||
|
_backupStorageCapacityThreshold = Double.parseDouble(backupStorageCapacityThreshold);
|
||||||
|
}
|
||||||
|
if (objectStorageCapacityThreshold != null) {
|
||||||
|
_objectStorageCapacityThreshold = Double.parseDouble(objectStorageCapacityThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP, _publicIPCapacityThreshold);
|
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP, _publicIPCapacityThreshold);
|
||||||
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_PRIVATE_IP, _privateIPCapacityThreshold);
|
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_PRIVATE_IP, _privateIPCapacityThreshold);
|
||||||
@ -226,6 +243,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP, _directNetworkPublicIpCapacityThreshold);
|
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP, _directNetworkPublicIpCapacityThreshold);
|
||||||
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_LOCAL_STORAGE, _localStorageCapacityThreshold);
|
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_LOCAL_STORAGE, _localStorageCapacityThreshold);
|
||||||
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, Ipv6SubnetCapacityThreshold.value());
|
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET, Ipv6SubnetCapacityThreshold.value());
|
||||||
|
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_BACKUP_STORAGE, _backupStorageCapacityThreshold);
|
||||||
|
_capacityTypeThresholdMap.put(Capacity.CAPACITY_TYPE_OBJECT_STORAGE, _objectStorageCapacityThreshold);
|
||||||
|
|
||||||
String capacityCheckPeriodStr = configs.get("capacity.check.period");
|
String capacityCheckPeriodStr = configs.get("capacity.check.period");
|
||||||
if (capacityCheckPeriodStr != null) {
|
if (capacityCheckPeriodStr != null) {
|
||||||
@ -549,7 +568,9 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
for (Short capacityType : dataCenterCapacityTypes) {
|
for (Short capacityType : dataCenterCapacityTypes) {
|
||||||
List<SummedCapacity> capacity = _capacityDao.findCapacityBy(capacityType.intValue(), dc.getId(), null, null);
|
List<SummedCapacity> capacity = _capacityDao.findCapacityBy(capacityType.intValue(), dc.getId(), null, null);
|
||||||
|
|
||||||
if (capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE) {
|
if (capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE ||
|
||||||
|
capacityType == Capacity.CAPACITY_TYPE_OBJECT_STORAGE ||
|
||||||
|
capacityType == Capacity.CAPACITY_TYPE_BACKUP_STORAGE) {
|
||||||
capacity.add(getUsedStats(capacityType, dc.getId(), null, null));
|
capacity.add(getUsedStats(capacityType, dc.getId(), null, null));
|
||||||
}
|
}
|
||||||
if (capacity == null || capacity.isEmpty()) {
|
if (capacity == null || capacity.isEmpty()) {
|
||||||
@ -618,18 +639,22 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SummedCapacity getUsedStats(short capacityType, long zoneId, Long podId, Long clusterId) {
|
private SummedCapacity getUsedStats(short capacityType, long zoneId, Long podId, Long clusterId) {
|
||||||
CapacityVO capacity;
|
CapacityVO capacity = null;
|
||||||
|
|
||||||
if (capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE) {
|
if (capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE) {
|
||||||
capacity = _storageMgr.getSecondaryStorageUsedStats(null, zoneId);
|
capacity = _storageMgr.getSecondaryStorageUsedStats(null, zoneId);
|
||||||
} else {
|
} else if (capacityType == Capacity.CAPACITY_TYPE_STORAGE) {
|
||||||
capacity = _storageMgr.getStoragePoolUsedStats(null, clusterId, podId, zoneId);
|
capacity = _storageMgr.getStoragePoolUsedStats(null, clusterId, podId, zoneId);
|
||||||
|
} else if (capacityType == Capacity.CAPACITY_TYPE_OBJECT_STORAGE) {
|
||||||
|
capacity = _storageMgr.getObjectStorageUsedStats(zoneId);
|
||||||
|
} else if (capacityType == Capacity.CAPACITY_TYPE_BACKUP_STORAGE) {
|
||||||
|
capacity = (CapacityVO) backupManager.getBackupStorageUsedStats(zoneId);
|
||||||
}
|
}
|
||||||
if (capacity != null) {
|
if (capacity != null) {
|
||||||
return new SummedCapacity(capacity.getUsedCapacity(), 0, capacity.getTotalCapacity(), capacityType, clusterId, podId);
|
return new SummedCapacity(capacity.getUsedCapacity(), 0, capacity.getTotalCapacity(), capacityType, clusterId, podId);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateEmailAlert(DataCenterVO dc, HostPodVO pod, ClusterVO cluster, double totalCapacity, double usedCapacity, short capacityType) {
|
private void generateEmailAlert(DataCenterVO dc, HostPodVO pod, ClusterVO cluster, double totalCapacity, double usedCapacity, short capacityType) {
|
||||||
@ -706,6 +731,16 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
msgContent = String.format("Number of unallocated virtual network guest IPv6 subnets is low, total: [%s], allocated: [%s] (%s%%).", totalInString, usedInString, percentual);
|
msgContent = String.format("Number of unallocated virtual network guest IPv6 subnets is low, total: [%s], allocated: [%s] (%s%%).", totalInString, usedInString, percentual);
|
||||||
alertType = AlertManager.AlertType.ALERT_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET;
|
alertType = AlertManager.AlertType.ALERT_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET;
|
||||||
break;
|
break;
|
||||||
|
case Capacity.CAPACITY_TYPE_BACKUP_STORAGE:
|
||||||
|
msgSubject = "System Alert: Low Available Backup Storage in availability zone " + dc.getName();
|
||||||
|
msgContent = "Available backup storage space is low, total: " + totalInString + " MB, used: " + usedInString + " MB (" + percentual + "%)";
|
||||||
|
alertType = AlertManager.AlertType.ALERT_TYPE_BACKUP_STORAGE;
|
||||||
|
break;
|
||||||
|
case Capacity.CAPACITY_TYPE_OBJECT_STORAGE:
|
||||||
|
msgSubject = "System Alert: Low Available Object Storage in availability zone " + dc.getName();
|
||||||
|
msgContent = "Available object storage space is low, total: " + totalInString + " MB, used: " + usedInString + " MB (" + percentual + "%)";
|
||||||
|
alertType = AlertManager.AlertType.ALERT_TYPE_OBJECT_STORAGE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -724,6 +759,8 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
|
|||||||
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE);
|
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE);
|
||||||
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_VLAN);
|
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_VLAN);
|
||||||
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET);
|
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_IPV6_SUBNET);
|
||||||
|
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_BACKUP_STORAGE);
|
||||||
|
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_OBJECT_STORAGE);
|
||||||
return dataCenterCapacityTypes;
|
return dataCenterCapacityTypes;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,6 @@ import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
|||||||
import org.apache.cloudstack.api.response.AccountResponse;
|
import org.apache.cloudstack.api.response.AccountResponse;
|
||||||
import org.apache.cloudstack.api.response.AsyncJobResponse;
|
import org.apache.cloudstack.api.response.AsyncJobResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupResponse;
|
|
||||||
import org.apache.cloudstack.api.response.BackupScheduleResponse;
|
import org.apache.cloudstack.api.response.BackupScheduleResponse;
|
||||||
import org.apache.cloudstack.api.response.DiskOfferingResponse;
|
import org.apache.cloudstack.api.response.DiskOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.DomainResponse;
|
import org.apache.cloudstack.api.response.DomainResponse;
|
||||||
@ -75,7 +74,6 @@ import org.apache.cloudstack.api.response.UserVmResponse;
|
|||||||
import org.apache.cloudstack.api.response.VolumeResponse;
|
import org.apache.cloudstack.api.response.VolumeResponse;
|
||||||
import org.apache.cloudstack.api.response.VpcOfferingResponse;
|
import org.apache.cloudstack.api.response.VpcOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.backup.Backup;
|
|
||||||
import org.apache.cloudstack.backup.BackupOffering;
|
import org.apache.cloudstack.backup.BackupOffering;
|
||||||
import org.apache.cloudstack.backup.BackupSchedule;
|
import org.apache.cloudstack.backup.BackupSchedule;
|
||||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||||
@ -1065,6 +1063,10 @@ public class ApiDBUtils {
|
|||||||
return s_storageMgr.getSecondaryStorageUsedStats(hostId, zoneId);
|
return s_storageMgr.getSecondaryStorageUsedStats(hostId, zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CapacityVO getObjectStorageUsedStats(Long zoneId) {
|
||||||
|
return s_storageMgr.getObjectStorageUsedStats(zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
// ///////////////////////////////////////////////////////////
|
// ///////////////////////////////////////////////////////////
|
||||||
// Dao methods //
|
// Dao methods //
|
||||||
// ///////////////////////////////////////////////////////////
|
// ///////////////////////////////////////////////////////////
|
||||||
@ -1102,7 +1104,7 @@ public class ApiDBUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DiskOfferingVO findDiskOfferingById(Long diskOfferingId) {
|
public static DiskOfferingVO findNonComputeDiskOfferingById(Long diskOfferingId) {
|
||||||
if (diskOfferingId == null) {
|
if (diskOfferingId == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1113,6 +1115,14 @@ public class ApiDBUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DiskOfferingVO findDiskOfferingById(Long diskOfferingId) {
|
||||||
|
if (diskOfferingId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DiskOfferingVO off = s_diskOfferingDao.findByIdIncludingRemoved(diskOfferingId);
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
public static ServiceOfferingVO findServiceOfferingByComputeOnlyDiskOffering(Long diskOfferingId, boolean includingRemoved) {
|
public static ServiceOfferingVO findServiceOfferingByComputeOnlyDiskOffering(Long diskOfferingId, boolean includingRemoved) {
|
||||||
ServiceOfferingVO off = s_serviceOfferingDao.findServiceOfferingByComputeOnlyDiskOffering(diskOfferingId, includingRemoved);
|
ServiceOfferingVO off = s_serviceOfferingDao.findServiceOfferingByComputeOnlyDiskOffering(diskOfferingId, includingRemoved);
|
||||||
return off;
|
return off;
|
||||||
@ -2264,10 +2274,6 @@ public class ApiDBUtils {
|
|||||||
return s_resourceIconDao.findByResourceUuid(resourceUUID, resourceType);
|
return s_resourceIconDao.findByResourceUuid(resourceUUID, resourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BackupResponse newBackupResponse(Backup backup) {
|
|
||||||
return s_backupDao.newBackupResponse(backup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BackupScheduleResponse newBackupScheduleResponse(BackupSchedule schedule) {
|
public static BackupScheduleResponse newBackupScheduleResponse(BackupSchedule schedule) {
|
||||||
return s_backupScheduleDao.newBackupScheduleResponse(schedule);
|
return s_backupScheduleDao.newBackupScheduleResponse(schedule);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,7 +77,6 @@ import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
|
|||||||
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
|
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
import org.apache.cloudstack.api.response.BackupOfferingResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupRepositoryResponse;
|
import org.apache.cloudstack.api.response.BackupRepositoryResponse;
|
||||||
import org.apache.cloudstack.api.response.BackupResponse;
|
|
||||||
import org.apache.cloudstack.api.response.BackupScheduleResponse;
|
import org.apache.cloudstack.api.response.BackupScheduleResponse;
|
||||||
import org.apache.cloudstack.api.response.BgpPeerResponse;
|
import org.apache.cloudstack.api.response.BgpPeerResponse;
|
||||||
import org.apache.cloudstack.api.response.BucketResponse;
|
import org.apache.cloudstack.api.response.BucketResponse;
|
||||||
@ -198,7 +197,6 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse;
|
|||||||
import org.apache.cloudstack.api.response.VpcResponse;
|
import org.apache.cloudstack.api.response.VpcResponse;
|
||||||
import org.apache.cloudstack.api.response.VpnUsersResponse;
|
import org.apache.cloudstack.api.response.VpnUsersResponse;
|
||||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||||
import org.apache.cloudstack.backup.Backup;
|
|
||||||
import org.apache.cloudstack.backup.BackupOffering;
|
import org.apache.cloudstack.backup.BackupOffering;
|
||||||
import org.apache.cloudstack.backup.BackupRepository;
|
import org.apache.cloudstack.backup.BackupRepository;
|
||||||
import org.apache.cloudstack.backup.BackupSchedule;
|
import org.apache.cloudstack.backup.BackupSchedule;
|
||||||
@ -1483,6 +1481,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
capacities.add(ApiDBUtils.getStoragePoolUsedStats(poolId, clusterId, podId, zoneId));
|
capacities.add(ApiDBUtils.getStoragePoolUsedStats(poolId, clusterId, podId, zoneId));
|
||||||
if (clusterId == null && podId == null) {
|
if (clusterId == null && podId == null) {
|
||||||
capacities.add(ApiDBUtils.getSecondaryStorageUsedStats(poolId, zoneId));
|
capacities.add(ApiDBUtils.getSecondaryStorageUsedStats(poolId, zoneId));
|
||||||
|
capacities.add(ApiDBUtils.getObjectStorageUsedStats(zoneId));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CapacityResponse> capacityResponses = new ArrayList<CapacityResponse>();
|
List<CapacityResponse> capacityResponses = new ArrayList<CapacityResponse>();
|
||||||
@ -2140,6 +2139,11 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
List<CapacityResponse> capacityResponses = new ArrayList<CapacityResponse>();
|
List<CapacityResponse> capacityResponses = new ArrayList<CapacityResponse>();
|
||||||
|
|
||||||
for (Capacity summedCapacity : result) {
|
for (Capacity summedCapacity : result) {
|
||||||
|
if (summedCapacity.getTotalCapacity() == 0 &&
|
||||||
|
(summedCapacity.getCapacityType() == Capacity.CAPACITY_TYPE_BACKUP_STORAGE ||
|
||||||
|
summedCapacity.getCapacityType() == Capacity.CAPACITY_TYPE_OBJECT_STORAGE)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
CapacityResponse capacityResponse = new CapacityResponse();
|
CapacityResponse capacityResponse = new CapacityResponse();
|
||||||
capacityResponse.setCapacityTotal(summedCapacity.getTotalCapacity());
|
capacityResponse.setCapacityTotal(summedCapacity.getTotalCapacity());
|
||||||
if (summedCapacity.getAllocatedCapacity() != null) {
|
if (summedCapacity.getAllocatedCapacity() != null) {
|
||||||
@ -5058,11 +5062,6 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BackupResponse createBackupResponse(Backup backup) {
|
|
||||||
return ApiDBUtils.newBackupResponse(backup);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BackupScheduleResponse createBackupScheduleResponse(BackupSchedule schedule) {
|
public BackupScheduleResponse createBackupScheduleResponse(BackupSchedule schedule) {
|
||||||
return ApiDBUtils.newBackupScheduleResponse(schedule);
|
return ApiDBUtils.newBackupScheduleResponse(schedule);
|
||||||
|
|||||||
@ -253,7 +253,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
|||||||
userVmResponse.setServiceOfferingName(userVm.getServiceOfferingName());
|
userVmResponse.setServiceOfferingName(userVm.getServiceOfferingName());
|
||||||
}
|
}
|
||||||
if (details.contains(VMDetails.all) || details.contains(VMDetails.diskoff)) {
|
if (details.contains(VMDetails.all) || details.contains(VMDetails.diskoff)) {
|
||||||
DiskOfferingVO diskOfferingVO = ApiDBUtils.findDiskOfferingById(userVm.getDiskOfferingId());
|
DiskOfferingVO diskOfferingVO = ApiDBUtils.findNonComputeDiskOfferingById(userVm.getDiskOfferingId());
|
||||||
if (diskOfferingVO != null) {
|
if (diskOfferingVO != null) {
|
||||||
userVmResponse.setDiskOfferingId(userVm.getDiskOfferingUuid());
|
userVmResponse.setDiskOfferingId(userVm.getDiskOfferingUuid());
|
||||||
userVmResponse.setDiskOfferingName(userVm.getDiskOfferingName());
|
userVmResponse.setDiskOfferingName(userVm.getDiskOfferingName());
|
||||||
|
|||||||
@ -6400,4 +6400,20 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
}
|
}
|
||||||
return Networks.BroadcastDomainType.getValue(nic.getBroadcastUri());
|
return Networks.BroadcastDomainType.getValue(nic.getBroadcastUri());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Network.IpAddresses getIpAddressesFromIps(String ipAddress, String ip6Address, String macAddress) {
|
||||||
|
if (ip6Address != null) {
|
||||||
|
ip6Address = NetUtils.standardizeIp6Address(ip6Address);
|
||||||
|
}
|
||||||
|
if (macAddress != null) {
|
||||||
|
if (!NetUtils.isValidMac(macAddress)) {
|
||||||
|
throw new InvalidParameterValueException("Mac address is not valid: " + macAddress);
|
||||||
|
} else if (!NetUtils.isUnicastMac(macAddress)) {
|
||||||
|
throw new InvalidParameterValueException("Mac address is not unicast: " + macAddress);
|
||||||
|
}
|
||||||
|
macAddress = NetUtils.standardizeMacAddress(macAddress);
|
||||||
|
}
|
||||||
|
return new Network.IpAddresses(ipAddress, ip6Address, macAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1816,7 +1816,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
|
|||||||
|
|
||||||
if (zone.getNetworkType() == NetworkType.Basic) {
|
if (zone.getNetworkType() == NetworkType.Basic) {
|
||||||
vm = userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, vmHostName,
|
vm = userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, null, owner, vmHostName,
|
||||||
vmHostName, diskOfferingId, dataDiskSize, null,
|
vmHostName, diskOfferingId, dataDiskSize, null, null,
|
||||||
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
|
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
|
||||||
null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
|
null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
|
||||||
null, true, overrideDiskOfferingId, null, null);
|
null, true, overrideDiskOfferingId, null, null);
|
||||||
@ -1824,13 +1824,13 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage
|
|||||||
if (networkModel.checkSecurityGroupSupportForNetwork(owner, zone, networkIds,
|
if (networkModel.checkSecurityGroupSupportForNetwork(owner, zone, networkIds,
|
||||||
Collections.emptyList())) {
|
Collections.emptyList())) {
|
||||||
vm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, null,
|
vm = userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, null,
|
||||||
owner, vmHostName,vmHostName, diskOfferingId, dataDiskSize, null,
|
owner, vmHostName,vmHostName, diskOfferingId, dataDiskSize, null, null,
|
||||||
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
|
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
|
||||||
null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
|
null, null, true, null, affinityGroupIdList, customParameters, null, null, null,
|
||||||
null, true, overrideDiskOfferingId, null, null, null);
|
null, true, overrideDiskOfferingId, null, null, null);
|
||||||
} else {
|
} else {
|
||||||
vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, vmHostName, vmHostName,
|
vm = userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, vmHostName, vmHostName,
|
||||||
diskOfferingId, dataDiskSize, null,
|
diskOfferingId, dataDiskSize, null, null,
|
||||||
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
|
hypervisorType, HTTPMethod.GET, userData, userDataId, userDataDetails, sshKeyPairs,
|
||||||
null, addrs, true, null, affinityGroupIdList, customParameters, null, null, null,
|
null, addrs, true, null, affinityGroupIdList, customParameters, null, null, null,
|
||||||
null, true, null, overrideDiskOfferingId, null, null);
|
null, true, null, overrideDiskOfferingId, null, null);
|
||||||
|
|||||||
@ -631,6 +631,7 @@ import org.apache.cloudstack.api.command.user.vpn.UpdateVpnGatewayCmd;
|
|||||||
import org.apache.cloudstack.api.command.user.zone.ListZonesCmd;
|
import org.apache.cloudstack.api.command.user.zone.ListZonesCmd;
|
||||||
import org.apache.cloudstack.auth.UserAuthenticator;
|
import org.apache.cloudstack.auth.UserAuthenticator;
|
||||||
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
|
import org.apache.cloudstack.auth.UserTwoFactorAuthenticator;
|
||||||
|
import org.apache.cloudstack.backup.BackupManager;
|
||||||
import org.apache.cloudstack.config.ApiServiceConfiguration;
|
import org.apache.cloudstack.config.ApiServiceConfiguration;
|
||||||
import org.apache.cloudstack.config.Configuration;
|
import org.apache.cloudstack.config.Configuration;
|
||||||
import org.apache.cloudstack.config.ConfigurationGroup;
|
import org.apache.cloudstack.config.ConfigurationGroup;
|
||||||
@ -1045,6 +1046,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
@Inject
|
@Inject
|
||||||
StoragePoolTagsDao storagePoolTagsDao;
|
StoragePoolTagsDao storagePoolTagsDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
private BackupManager backupManager;
|
||||||
|
@Inject
|
||||||
protected ManagementServerJoinDao managementServerJoinDao;
|
protected ManagementServerJoinDao managementServerJoinDao;
|
||||||
@Inject
|
@Inject
|
||||||
ClusterManager _clusterMgr;
|
ClusterManager _clusterMgr;
|
||||||
@ -3560,7 +3563,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<SummedCapacity> getStorageCapacities(Long clusterId, Long podId, Long zoneId, List<Long> poolIds, Short capacityType) {
|
List<SummedCapacity> getStorageCapacities(Long clusterId, Long podId, Long zoneId, List<Long> poolIds, Short capacityType) {
|
||||||
List<Short> capacityTypes = Arrays.asList(Capacity.CAPACITY_TYPE_STORAGE, Capacity.CAPACITY_TYPE_SECONDARY_STORAGE);
|
List<Short> capacityTypes = Arrays.asList(Capacity.CAPACITY_TYPE_STORAGE, Capacity.CAPACITY_TYPE_SECONDARY_STORAGE,
|
||||||
|
Capacity.CAPACITY_TYPE_BACKUP_STORAGE, Capacity.CAPACITY_TYPE_OBJECT_STORAGE);
|
||||||
if (capacityType != null && !capacityTypes.contains(capacityType)) {
|
if (capacityType != null && !capacityTypes.contains(capacityType)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -3568,7 +3572,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
capacityTypes = capacityTypes.stream().filter(x -> x.equals(capacityType)).collect(Collectors.toList());
|
capacityTypes = capacityTypes.stream().filter(x -> x.equals(capacityType)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(poolIds)) {
|
if (CollectionUtils.isNotEmpty(poolIds)) {
|
||||||
capacityTypes = capacityTypes.stream().filter(x -> x != Capacity.CAPACITY_TYPE_SECONDARY_STORAGE).collect(Collectors.toList());
|
capacityTypes = capacityTypes.stream().filter(x -> x == Capacity.CAPACITY_TYPE_STORAGE).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isEmpty(capacityTypes)) {
|
if (CollectionUtils.isEmpty(capacityTypes)) {
|
||||||
return null;
|
return null;
|
||||||
@ -3594,6 +3598,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
if (capacityTypes.contains(Capacity.CAPACITY_TYPE_STORAGE)) {
|
if (capacityTypes.contains(Capacity.CAPACITY_TYPE_STORAGE)) {
|
||||||
capacities.add(_storageMgr.getStoragePoolUsedStats(dc.getId(), podId, clusterId, poolIds));
|
capacities.add(_storageMgr.getStoragePoolUsedStats(dc.getId(), podId, clusterId, poolIds));
|
||||||
}
|
}
|
||||||
|
if (capacityTypes.contains(Capacity.CAPACITY_TYPE_OBJECT_STORAGE)) {
|
||||||
|
capacities.add(_storageMgr.getObjectStorageUsedStats(dc.getId()));
|
||||||
|
}
|
||||||
|
if (capacityTypes.contains(Capacity.CAPACITY_TYPE_BACKUP_STORAGE)) {
|
||||||
|
capacities.add((CapacityVO) backupManager.getBackupStorageUsedStats(dc.getId()));
|
||||||
|
}
|
||||||
for (CapacityVO capacity : capacities) {
|
for (CapacityVO capacity : capacities) {
|
||||||
if (capacity.getTotalCapacity() != 0) {
|
if (capacity.getTotalCapacity() != 0) {
|
||||||
capacity.setUsedPercentage((float)capacity.getUsedCapacity() / capacity.getTotalCapacity());
|
capacity.setUsedPercentage((float)capacity.getUsedCapacity() / capacity.getTotalCapacity());
|
||||||
@ -3608,6 +3618,22 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addZoneWideCapacitiesByType(final Integer capacityType, Long zId, List<CapacityVO> taggedCapacities) {
|
||||||
|
if (capacityType == null) {
|
||||||
|
taggedCapacities.add(_storageMgr.getSecondaryStorageUsedStats(null, zId));
|
||||||
|
taggedCapacities.add(_storageMgr.getObjectStorageUsedStats(zId));
|
||||||
|
taggedCapacities.add((CapacityVO) backupManager.getBackupStorageUsedStats(zId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE) {
|
||||||
|
taggedCapacities.add(_storageMgr.getSecondaryStorageUsedStats(null, zId));
|
||||||
|
} else if (capacityType == Capacity.CAPACITY_TYPE_OBJECT_STORAGE) {
|
||||||
|
taggedCapacities.add(_storageMgr.getObjectStorageUsedStats(zId));
|
||||||
|
} else if (capacityType == Capacity.CAPACITY_TYPE_BACKUP_STORAGE) {
|
||||||
|
taggedCapacities.add((CapacityVO) backupManager.getBackupStorageUsedStats(zId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected List<CapacityVO> listCapacitiesWithDetails(final Long zoneId, final Long podId, Long clusterId,
|
protected List<CapacityVO> listCapacitiesWithDetails(final Long zoneId, final Long podId, Long clusterId,
|
||||||
final Integer capacityType, final String tag, List<Long> dcList) {
|
final Integer capacityType, final String tag, List<Long> dcList) {
|
||||||
@ -3636,11 +3662,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
|
|||||||
for (final Long zId : dcList) {
|
for (final Long zId : dcList) {
|
||||||
// op_host_Capacity contains only allocated stats and the real time
|
// op_host_Capacity contains only allocated stats and the real time
|
||||||
// stats are stored "in memory".
|
// stats are stored "in memory".
|
||||||
// List secondary storage capacity only when the api is invoked for the zone layer.
|
// List secondary, object and backup storage capacities only when the api is invoked for the zone layer.
|
||||||
if ((capacityType == null || capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE) &&
|
if (podId == null && clusterId == null && StringUtils.isEmpty(t)) {
|
||||||
podId == null && clusterId == null &&
|
addZoneWideCapacitiesByType(capacityType, zId, taggedCapacities);
|
||||||
StringUtils.isEmpty(t)) {
|
|
||||||
taggedCapacities.add(_storageMgr.getSecondaryStorageUsedStats(null, zId));
|
|
||||||
}
|
}
|
||||||
if ((capacityType == null || capacityType == Capacity.CAPACITY_TYPE_STORAGE) && storagePoolIdsForCapacity.first()) {
|
if ((capacityType == null || capacityType == Capacity.CAPACITY_TYPE_STORAGE) && storagePoolIdsForCapacity.first()) {
|
||||||
taggedCapacities.add(_storageMgr.getStoragePoolUsedStats(zId, podId, clusterId, storagePoolIdsForCapacity.second()));
|
taggedCapacities.add(_storageMgr.getStoragePoolUsedStats(zId, podId, clusterId, storagePoolIdsForCapacity.second()));
|
||||||
|
|||||||
@ -4588,7 +4588,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
VmwareAllowParallelExecution,
|
VmwareAllowParallelExecution,
|
||||||
DataStoreDownloadFollowRedirects,
|
DataStoreDownloadFollowRedirects,
|
||||||
AllowVolumeReSizeBeyondAllocation,
|
AllowVolumeReSizeBeyondAllocation,
|
||||||
StoragePoolHostConnectWorkers
|
StoragePoolHostConnectWorkers,
|
||||||
|
ObjectStorageCapacityThreshold
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4637,7 +4638,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_OBJECT_STORE_CREATE, eventDescription = "creating object storage")
|
@ActionEvent(eventType = EventTypes.EVENT_OBJECT_STORE_CREATE, eventDescription = "creating object storage")
|
||||||
public ObjectStore discoverObjectStore(String name, String url, String providerName, Map details)
|
public ObjectStore discoverObjectStore(String name, String url, Long size, String providerName, Map details)
|
||||||
throws IllegalArgumentException, InvalidParameterValueException {
|
throws IllegalArgumentException, InvalidParameterValueException {
|
||||||
DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(providerName);
|
DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(providerName);
|
||||||
|
|
||||||
@ -4667,6 +4668,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.put("url", url);
|
params.put("url", url);
|
||||||
params.put("name", name);
|
params.put("name", name);
|
||||||
|
if (size == null) {
|
||||||
|
params.put("size", 0L);
|
||||||
|
} else {
|
||||||
|
params.put("size", size);
|
||||||
|
}
|
||||||
params.put("providerName", storeProvider.getName());
|
params.put("providerName", storeProvider.getName());
|
||||||
params.put("role", DataStoreRole.Object);
|
params.put("role", DataStoreRole.Object);
|
||||||
params.put("details", details);
|
params.put("details", details);
|
||||||
@ -4750,8 +4756,28 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
if(cmd.getName() != null ) {
|
if(cmd.getName() != null ) {
|
||||||
objectStoreVO.setName(cmd.getName());
|
objectStoreVO.setName(cmd.getName());
|
||||||
}
|
}
|
||||||
|
if (cmd.getSize() != null) {
|
||||||
|
objectStoreVO.setTotalSize(cmd.getSize() * ResourceType.bytesToGiB);
|
||||||
|
}
|
||||||
_objectStoreDao.update(id, objectStoreVO);
|
_objectStoreDao.update(id, objectStoreVO);
|
||||||
logger.debug("Successfully updated object store: {}", objectStoreVO);
|
logger.debug("Successfully updated object store: {}", objectStoreVO);
|
||||||
return objectStoreVO;
|
return objectStoreVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CapacityVO getObjectStorageUsedStats(Long zoneId) {
|
||||||
|
List<ObjectStoreVO> objectStores = _objectStoreDao.listObjectStores();
|
||||||
|
Long allocated = 0L;
|
||||||
|
Long total = 0L;
|
||||||
|
for (ObjectStoreVO objectStore: objectStores) {
|
||||||
|
if (objectStore.getAllocatedSize() != null) {
|
||||||
|
allocated += objectStore.getAllocatedSize();
|
||||||
|
}
|
||||||
|
if (objectStore.getTotalSize() != null) {
|
||||||
|
total += objectStore.getTotalSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CapacityVO capacity = new CapacityVO(null, zoneId, null, null, allocated, total, Capacity.CAPACITY_TYPE_OBJECT_STORAGE);
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -954,7 +954,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
|
|
||||||
String userSpecifiedName = getVolumeNameFromCommand(cmd);
|
String userSpecifiedName = getVolumeNameFromCommand(cmd);
|
||||||
|
|
||||||
return commitVolume(cmd, caller, owner, displayVolume, zoneId, diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, userSpecifiedName,
|
return commitVolume(cmd.getSnapshotId(), caller, owner, displayVolume, zoneId, diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, userSpecifiedName,
|
||||||
_uuidMgr.generateUuid(Volume.class, cmd.getCustomId()), details);
|
_uuidMgr.generateUuid(Volume.class, cmd.getCustomId()), details);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -968,7 +968,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private VolumeVO commitVolume(final CreateVolumeCmd cmd, final Account caller, final Account owner, final Boolean displayVolume, final Long zoneId, final Long diskOfferingId,
|
private VolumeVO commitVolume(final Long snapshotId, final Account caller, final Account owner, final Boolean displayVolume, final Long zoneId, final Long diskOfferingId,
|
||||||
final Storage.ProvisioningType provisioningType, final Long size, final Long minIops, final Long maxIops, final VolumeVO parentVolume, final String userSpecifiedName, final String uuid, final Map<String, String> details) {
|
final Storage.ProvisioningType provisioningType, final Long size, final Long minIops, final Long maxIops, final VolumeVO parentVolume, final String userSpecifiedName, final String uuid, final Map<String, String> details) {
|
||||||
return Transaction.execute(new TransactionCallback<VolumeVO>() {
|
return Transaction.execute(new TransactionCallback<VolumeVO>() {
|
||||||
@Override
|
@Override
|
||||||
@ -996,7 +996,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
|
|
||||||
volume = _volsDao.persist(volume);
|
volume = _volsDao.persist(volume);
|
||||||
|
|
||||||
if (cmd.getSnapshotId() == null && displayVolume) {
|
if (snapshotId == null && displayVolume) {
|
||||||
// for volume created from snapshot, create usage event after volume creation
|
// for volume created from snapshot, create usage event after volume creation
|
||||||
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size,
|
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size,
|
||||||
Volume.class.getName(), volume.getUuid(), displayVolume);
|
Volume.class.getName(), volume.getUuid(), displayVolume);
|
||||||
@ -2867,7 +2867,10 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||||||
try {
|
try {
|
||||||
List<Backup.VolumeInfo> list = new ArrayList<>();
|
List<Backup.VolumeInfo> list = new ArrayList<>();
|
||||||
for (VolumeVO vol : vmVolumes) {
|
for (VolumeVO vol : vmVolumes) {
|
||||||
list.add(new Backup.VolumeInfo(vol.getUuid(), vol.getPath(), vol.getVolumeType(), vol.getSize()));
|
DiskOfferingVO diskOffering = _diskOfferingDao.findById(vol.getDiskOfferingId());
|
||||||
|
String diskOfferingUuid = diskOffering != null ? diskOffering.getUuid() : null;
|
||||||
|
list.add(new Backup.VolumeInfo(vol.getUuid(), vol.getPath(), vol.getVolumeType(), vol.getSize(),
|
||||||
|
vol.getDeviceId(), diskOfferingUuid, vol.getMinIops(), vol.getMaxIops()));
|
||||||
}
|
}
|
||||||
return GsonHelper.getGson().toJson(list.toArray(), Backup.VolumeInfo[].class);
|
return GsonHelper.getGson().toJson(list.toArray(), Backup.VolumeInfo[].class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import static org.apache.cloudstack.api.ApiConstants.MIN_IOPS;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -74,10 +75,13 @@ import org.apache.cloudstack.api.ApiConstants;
|
|||||||
import org.apache.cloudstack.api.BaseCmd;
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
|
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
|
||||||
|
import org.apache.cloudstack.api.command.admin.vm.CreateVMFromBackupCmdByAdmin;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.DeployVMCmdByAdmin;
|
import org.apache.cloudstack.api.command.admin.vm.DeployVMCmdByAdmin;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.ExpungeVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.ExpungeVMCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.BaseDeployVMCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.CreateVMFromBackupCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
|
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
|
||||||
@ -98,8 +102,8 @@ import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
|
|||||||
import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
|
import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
|
||||||
import org.apache.cloudstack.api.command.user.volume.ChangeOfferingForVolumeCmd;
|
import org.apache.cloudstack.api.command.user.volume.ChangeOfferingForVolumeCmd;
|
||||||
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
||||||
import org.apache.cloudstack.backup.Backup;
|
|
||||||
import org.apache.cloudstack.backup.BackupManager;
|
import org.apache.cloudstack.backup.BackupManager;
|
||||||
|
import org.apache.cloudstack.backup.BackupVO;
|
||||||
import org.apache.cloudstack.backup.dao.BackupDao;
|
import org.apache.cloudstack.backup.dao.BackupDao;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity;
|
import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity;
|
||||||
@ -399,6 +403,8 @@ import com.cloud.vm.dao.VmStatsDao;
|
|||||||
import com.cloud.vm.snapshot.VMSnapshotManager;
|
import com.cloud.vm.snapshot.VMSnapshotManager;
|
||||||
import com.cloud.vm.snapshot.VMSnapshotVO;
|
import com.cloud.vm.snapshot.VMSnapshotVO;
|
||||||
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
|
||||||
public class UserVmManagerImpl extends ManagerBase implements UserVmManager, VirtualMachineGuru, Configurable {
|
public class UserVmManagerImpl extends ManagerBase implements UserVmManager, VirtualMachineGuru, Configurable {
|
||||||
@ -1008,14 +1014,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_VM_RESETSSHKEY, eventDescription = "resetting Vm SSHKey", async = true)
|
@ActionEvent(eventType = EventTypes.EVENT_VM_RESETSSHKEY, eventDescription = "resetting Vm SSHKey", async = true)
|
||||||
public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException {
|
public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException {
|
||||||
|
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
Account owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), cmd.getDomainId(), cmd.getProjectId());
|
Account owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), cmd.getDomainId(), cmd.getProjectId());
|
||||||
Long vmId = cmd.getId();
|
|
||||||
UserVmVO userVm = _vmDao.findById(cmd.getId());
|
UserVmVO userVm = _vmDao.findById(cmd.getId());
|
||||||
|
|
||||||
if (userVm == null) {
|
if (userVm == null) {
|
||||||
throw new InvalidParameterValueException("unable to find a virtual machine by id" + cmd.getId());
|
throw new InvalidParameterValueException("unable to find a virtual machine by id " + cmd.getId());
|
||||||
}
|
}
|
||||||
if (UserVmManager.SHAREDFSVM.equals(userVm.getUserVmType())) {
|
if (UserVmManager.SHAREDFSVM.equals(userVm.getUserVmType())) {
|
||||||
throw new InvalidParameterValueException("Operation not supported on Shared FileSystem Instance");
|
throw new InvalidParameterValueException("Operation not supported on Shared FileSystem Instance");
|
||||||
@ -1027,10 +1031,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
userVm.getName()));
|
userVm.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(userVm.getTemplateId());
|
|
||||||
|
|
||||||
// Do parameters input validation
|
// Do parameters input validation
|
||||||
|
|
||||||
if (userVm.getState() == State.Error || userVm.getState() == State.Expunging) {
|
if (userVm.getState() == State.Error || userVm.getState() == State.Expunging) {
|
||||||
logger.error("vm ({}) is not in the right state: {}", userVm, userVm.getState());
|
logger.error("vm ({}) is not in the right state: {}", userVm, userVm.getState());
|
||||||
throw new InvalidParameterValueException("Vm with specified id is not in the right state");
|
throw new InvalidParameterValueException("Vm with specified id is not in the right state");
|
||||||
@ -1040,32 +1041,40 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
throw new InvalidParameterValueException("Vm " + userVm + " should be stopped to do SSH Key reset");
|
throw new InvalidParameterValueException("Vm " + userVm + " should be stopped to do SSH Key reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd.getNames() == null || cmd.getNames().isEmpty()) {
|
List<String> names = cmd.getNames();
|
||||||
|
if (CollectionUtils.isEmpty(names)) {
|
||||||
throw new InvalidParameterValueException("'keypair' or 'keypairs' must be specified");
|
throw new InvalidParameterValueException("'keypair' or 'keypairs' must be specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userVm = resetVMSSHKeyInternal(userVm, owner, names);
|
||||||
|
return userVm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserVmVO resetVMSSHKeyInternal(UserVmVO userVm, Account owner, List<String> names) throws ResourceUnavailableException, InsufficientCapacityException {
|
||||||
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
|
|
||||||
String keypairnames = "";
|
String keypairnames = "";
|
||||||
String sshPublicKeys = "";
|
String sshPublicKeys = "";
|
||||||
List<SSHKeyPairVO> pairs = new ArrayList<>();
|
List<SSHKeyPairVO> pairs = new ArrayList<>();
|
||||||
|
|
||||||
pairs = _sshKeyPairDao.findByNames(owner.getAccountId(), owner.getDomainId(), cmd.getNames());
|
pairs = _sshKeyPairDao.findByNames(owner.getAccountId(), owner.getDomainId(), names);
|
||||||
if (pairs == null || pairs.size() != cmd.getNames().size()) {
|
if (pairs == null || pairs.size() != names.size()) {
|
||||||
throw new InvalidParameterValueException("Not all specified keypairs exist");
|
throw new InvalidParameterValueException("Not all specified keypairs exist");
|
||||||
}
|
}
|
||||||
sshPublicKeys = pairs.stream().map(p -> p.getPublicKey()).collect(Collectors.joining("\n"));
|
sshPublicKeys = pairs.stream().map(p -> p.getPublicKey()).collect(Collectors.joining("\n"));
|
||||||
keypairnames = String.join(",", cmd.getNames());
|
keypairnames = String.join(",", names);
|
||||||
|
|
||||||
_accountMgr.checkAccess(caller, null, true, userVm);
|
_accountMgr.checkAccess(caller, null, true, userVm);
|
||||||
|
|
||||||
boolean result = resetVMSSHKeyInternal(vmId, sshPublicKeys, keypairnames);
|
boolean result = resetVMSSHKeyInternal(userVm.getId(), sshPublicKeys, keypairnames);
|
||||||
|
|
||||||
UserVmVO vm = _vmDao.findById(vmId);
|
UserVmVO vm = _vmDao.findById(userVm.getId());
|
||||||
_vmDao.loadDetails(vm);
|
_vmDao.loadDetails(vm);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
throw new CloudRuntimeException("Failed to reset SSH Key for the virtual machine ");
|
throw new CloudRuntimeException("Failed to reset SSH Key for the virtual machine ");
|
||||||
}
|
}
|
||||||
|
|
||||||
removeEncryptedPasswordFromUserVmVoDetails(vmId);
|
removeEncryptedPasswordFromUserVmVoDetails(userVm.getId());
|
||||||
|
|
||||||
_vmDao.loadDetails(userVm);
|
_vmDao.loadDetails(userVm);
|
||||||
return userVm;
|
return userVm;
|
||||||
@ -2515,17 +2524,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (vm.getBackupOfferingId() != null) {
|
backupManager.checkAndRemoveBackupOfferingBeforeExpunge(vm);
|
||||||
List<Backup> backupsForVm = backupDao.listByVmId(vm.getDataCenterId(), vm.getId());
|
|
||||||
if (CollectionUtils.isEmpty(backupsForVm)) {
|
|
||||||
backupManager.removeVMFromBackupOffering(vm.getId(), true);
|
|
||||||
} else {
|
|
||||||
throw new CloudRuntimeException(String.format("This VM [uuid: %s, name: %s] has a "
|
|
||||||
+ "Backup Offering [id: %s, external id: %s] with %s backups. Please, remove the backup offering "
|
|
||||||
+ "before proceeding to VM exclusion!", vm.getUuid(), vm.getInstanceName(), vm.getBackupOfferingId(),
|
|
||||||
vm.getBackupExternalId(), backupsForVm.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
autoScaleManager.removeVmFromVmGroup(vm.getId());
|
autoScaleManager.removeVmFromVmGroup(vm.getId());
|
||||||
|
|
||||||
@ -3523,6 +3522,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
final ControlledEntity[] volumesToDelete = volumesToBeDeleted.toArray(new ControlledEntity[0]);
|
final ControlledEntity[] volumesToDelete = volumesToBeDeleted.toArray(new ControlledEntity[0]);
|
||||||
_accountMgr.checkAccess(ctx.getCallingAccount(), null, true, volumesToDelete);
|
_accountMgr.checkAccess(ctx.getCallingAccount(), null, true, volumesToDelete);
|
||||||
|
|
||||||
|
if (expunge) {
|
||||||
|
backupManager.checkAndRemoveBackupOfferingBeforeExpunge(vm);
|
||||||
|
}
|
||||||
|
|
||||||
stopVirtualMachine(vmId, VmDestroyForcestop.value());
|
stopVirtualMachine(vmId, VmDestroyForcestop.value());
|
||||||
|
|
||||||
// Detach all data disks from VM
|
// Detach all data disks from VM
|
||||||
@ -3752,7 +3755,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
||||||
public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
|
public UserVm createBasicSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> securityGroupIdList,
|
||||||
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
|
Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, String group, HypervisorType hypervisor, HTTPMethod httpmethod,
|
||||||
String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard, List<Long> affinityGroupIdList,
|
||||||
Map<String, String> customParametes, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
Map<String, String> customParametes, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||||
@ -3802,7 +3805,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod,
|
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, dataDiskInfoList, networkList, securityGroupIdList, group, httpmethod,
|
||||||
userData, userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId, dhcpOptionMap,
|
userData, userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParametes, customId, dhcpOptionMap,
|
||||||
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId, volume, snapshot);
|
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId, volume, snapshot);
|
||||||
|
|
||||||
@ -3811,7 +3814,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
||||||
public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
|
public UserVm createAdvancedSecurityGroupVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList,
|
||||||
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor,
|
List<Long> securityGroupIdList, Account owner, String hostName, String displayName, Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, String group, HypervisorType hypervisor,
|
||||||
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayVm, String keyboard,
|
||||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
|
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap, Map<String, String> userVmOVFProperties, boolean dynamicScalingEnabled, Long overrideDiskOfferingId, String vmType, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, StorageUnavailableException, ResourceAllocationException {
|
||||||
@ -3915,7 +3918,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod,
|
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, dataDiskInfoList, networkList, securityGroupIdList, group, httpmethod,
|
||||||
userData, userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
userData, userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
||||||
userVmOVFProperties, dynamicScalingEnabled, vmType, overrideDiskOfferingId, volume, snapshot);
|
userVmOVFProperties, dynamicScalingEnabled, vmType, overrideDiskOfferingId, volume, snapshot);
|
||||||
}
|
}
|
||||||
@ -3923,7 +3926,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", create = true)
|
||||||
public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
|
public UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate template, List<Long> networkIdList, Account owner,
|
||||||
String hostName, String displayName, Long diskOfferingId, Long diskSize, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
|
String hostName, String displayName, Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, String group, HypervisorType hypervisor, HTTPMethod httpmethod, String userData,
|
||||||
Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> affinityGroupIdList,
|
Long userDataId, String userDataDetails, List<String> sshKeyPairs, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean displayvm, String keyboard, List<Long> affinityGroupIdList,
|
||||||
Map<String, String> customParametrs, String customId, Map<String, Map<Integer, String>> dhcpOptionsMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
Map<String, String> customParametrs, String customId, Map<String, Map<Integer, String>> dhcpOptionsMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||||
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, Long overrideDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
|
||||||
@ -3977,7 +3980,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
verifyExtraDhcpOptionsNetwork(dhcpOptionsMap, networkList);
|
verifyExtraDhcpOptionsNetwork(dhcpOptionsMap, networkList);
|
||||||
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, networkList, null, group, httpmethod, userData,
|
return createVirtualMachine(zone, serviceOffering, template, hostName, displayName, owner, diskOfferingId, diskSize, dataDiskInfoList, networkList, null, group, httpmethod, userData,
|
||||||
userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId, dhcpOptionsMap,
|
userDataId, userDataDetails, sshKeyPairs, hypervisor, caller, requestedIps, defaultIps, displayvm, keyboard, affinityGroupIdList, customParametrs, customId, dhcpOptionsMap,
|
||||||
dataDiskTemplateToDiskOfferingMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, overrideDiskOfferingId, volume, snapshot);
|
dataDiskTemplateToDiskOfferingMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, overrideDiskOfferingId, volume, snapshot);
|
||||||
}
|
}
|
||||||
@ -4107,7 +4110,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
|
|
||||||
@DB
|
@DB
|
||||||
private UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate tmplt, String hostName, String displayName, Account owner,
|
private UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffering, VirtualMachineTemplate tmplt, String hostName, String displayName, Account owner,
|
||||||
Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData,
|
Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group, HTTPMethod httpmethod, String userData,
|
||||||
Long userDataId, String userDataDetails, List<String> sshKeyPairs, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard,
|
Long userDataId, String userDataDetails, List<String> sshKeyPairs, HypervisorType hypervisor, Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm, String keyboard,
|
||||||
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId, Map<String, Map<Integer, String>> dhcpOptionMap,
|
||||||
Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
||||||
@ -4206,12 +4209,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
throw new InvalidParameterValueException("Root volume encryption is not supported for hypervisor type " + hypervisorType);
|
throw new InvalidParameterValueException("Root volume encryption is not supported for hypervisor type " + hypervisorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
long additionalDiskSize = 0L;
|
UserVm vm = getCheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, dataDiskInfoList, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize, volume, snapshot);
|
||||||
if (!isIso && diskOfferingId != null) {
|
|
||||||
DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
|
||||||
additionalDiskSize = verifyAndGetDiskSize(diskOffering, diskSize);
|
|
||||||
}
|
|
||||||
UserVm vm = getCheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize, additionalDiskSize, volume, snapshot);
|
|
||||||
|
|
||||||
_securityGroupMgr.addInstanceToGroups(vm, securityGroupIdList);
|
_securityGroupMgr.addInstanceToGroups(vm, securityGroupIdList);
|
||||||
|
|
||||||
@ -4224,14 +4222,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
|
|
||||||
private UserVm getCheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner,
|
private UserVm getCheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner,
|
||||||
Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group,
|
Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group,
|
||||||
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs,
|
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs,
|
||||||
Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm,
|
Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm,
|
||||||
String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId,
|
String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId,
|
||||||
Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
||||||
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template,
|
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template,
|
||||||
HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso,
|
HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso,
|
||||||
Long rootDiskOfferingId, long volumesSize, long additionalDiskSize, Volume volume, Snapshot snapshot) throws ResourceAllocationException {
|
Long rootDiskOfferingId, long volumesSize, Volume volume, Snapshot snapshot) throws ResourceAllocationException {
|
||||||
if (!VirtualMachineManager.ResourceCountRunningVMsonly.value()) {
|
if (!VirtualMachineManager.ResourceCountRunningVMsonly.value()) {
|
||||||
List<String> resourceLimitHostTags = resourceLimitService.getResourceLimitHostTags(offering, template);
|
List<String> resourceLimitHostTags = resourceLimitService.getResourceLimitHostTags(offering, template);
|
||||||
try (CheckedReservation vmReservation = new CheckedReservation(owner, ResourceType.user_vm, resourceLimitHostTags, 1l, reservationDao, resourceLimitService);
|
try (CheckedReservation vmReservation = new CheckedReservation(owner, ResourceType.user_vm, resourceLimitHostTags, 1l, reservationDao, resourceLimitService);
|
||||||
@ -4240,7 +4238,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
CheckedReservation gpuReservation = offering.getGpuCount() != null && offering.getGpuCount() > 0 ?
|
CheckedReservation gpuReservation = offering.getGpuCount() != null && offering.getGpuCount() > 0 ?
|
||||||
new CheckedReservation(owner, ResourceType.gpu, resourceLimitHostTags, Long.valueOf(offering.getGpuCount()), reservationDao, resourceLimitService) : null;
|
new CheckedReservation(owner, ResourceType.gpu, resourceLimitHostTags, Long.valueOf(offering.getGpuCount()), reservationDao, resourceLimitService) : null;
|
||||||
) {
|
) {
|
||||||
return getUncheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize, additionalDiskSize, volume, snapshot);
|
return getUncheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, dataDiskInfoList, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize, volume, snapshot);
|
||||||
} catch (ResourceAllocationException | CloudRuntimeException e) {
|
} catch (ResourceAllocationException | CloudRuntimeException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -4249,7 +4247,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return getUncheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize, additionalDiskSize, volume, snapshot);
|
return getUncheckedUserVmResource(zone, hostName, displayName, owner, diskOfferingId, diskSize, dataDiskInfoList, networkList, securityGroupIdList, group, httpmethod, userData, userDataId, userDataDetails, sshKeyPairs, caller, requestedIps, defaultIps, isDisplayVm, keyboard, affinityGroupIdList, customParameters, customId, dhcpOptionMap, datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, template, hypervisorType, accountId, offering, isIso, rootDiskOfferingId, volumesSize, volume, snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4258,24 +4256,53 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
return resourceLimitService.getResourceLimitStorageTags(diskOfferingVO);
|
return resourceLimitService.getResourceLimitStorageTags(diskOfferingVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<CheckedReservation> reserveStorageResourcesForVm(Account owner, Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, Long rootDiskOfferingId, ServiceOfferingVO offering, Long rootDiskSize) throws ResourceAllocationException {
|
||||||
|
List <CheckedReservation> checkedReservations = new ArrayList<>();
|
||||||
|
|
||||||
|
List<String> rootResourceLimitStorageTags = getResourceLimitStorageTags(rootDiskOfferingId != null ? rootDiskOfferingId : offering.getDiskOfferingId());
|
||||||
|
CheckedReservation rootVolumeReservation = new CheckedReservation(owner, ResourceType.volume, rootResourceLimitStorageTags, 1L, reservationDao, resourceLimitService);
|
||||||
|
checkedReservations.add(rootVolumeReservation);
|
||||||
|
CheckedReservation rootPrimaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, rootResourceLimitStorageTags, rootDiskSize, reservationDao, resourceLimitService);
|
||||||
|
checkedReservations.add(rootPrimaryStorageReservation);
|
||||||
|
|
||||||
|
if (diskOfferingId != null) {
|
||||||
|
List<String> additionalResourceLimitStorageTags = diskOfferingId != null ? getResourceLimitStorageTags(diskOfferingId) : null;
|
||||||
|
DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||||
|
Long size = verifyAndGetDiskSize(diskOffering, diskSize);
|
||||||
|
CheckedReservation additionalVolumeReservation = diskOfferingId != null ? new CheckedReservation(owner, ResourceType.volume, additionalResourceLimitStorageTags, 1L, reservationDao, resourceLimitService) : null;
|
||||||
|
checkedReservations.add(additionalVolumeReservation);
|
||||||
|
CheckedReservation additionalPrimaryStorageReservation = diskOfferingId != null ? new CheckedReservation(owner, ResourceType.primary_storage, additionalResourceLimitStorageTags, size, reservationDao, resourceLimitService) : null;
|
||||||
|
checkedReservations.add(additionalPrimaryStorageReservation);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataDiskInfoList != null) {
|
||||||
|
for (VmDiskInfo vmDiskInfo : dataDiskInfoList) {
|
||||||
|
DiskOffering diskOffering = vmDiskInfo.getDiskOffering();
|
||||||
|
List<String> additionalResourceLimitStorageTagsForDataDisk = getResourceLimitStorageTags(vmDiskInfo.getDiskOffering().getId());
|
||||||
|
Long size = verifyAndGetDiskSize(diskOffering, vmDiskInfo.getSize());
|
||||||
|
CheckedReservation additionalVolumeReservation = new CheckedReservation(owner, ResourceType.volume, additionalResourceLimitStorageTagsForDataDisk, 1L, reservationDao, resourceLimitService);
|
||||||
|
checkedReservations.add(additionalVolumeReservation);
|
||||||
|
CheckedReservation additionalPrimaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, additionalResourceLimitStorageTagsForDataDisk, size, reservationDao, resourceLimitService);
|
||||||
|
checkedReservations.add(additionalPrimaryStorageReservation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return checkedReservations;
|
||||||
|
}
|
||||||
|
|
||||||
private UserVm getUncheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner,
|
private UserVm getUncheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner,
|
||||||
Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group,
|
Long diskOfferingId, Long diskSize, List<VmDiskInfo> dataDiskInfoList, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group,
|
||||||
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs,
|
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs,
|
||||||
Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm,
|
Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm,
|
||||||
String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId,
|
String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId,
|
||||||
Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
|
||||||
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template,
|
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template,
|
||||||
HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso,
|
HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso,
|
||||||
Long rootDiskOfferingId, long volumesSize, long additionalDiskSize, Volume volume, Snapshot snapshot) throws ResourceAllocationException
|
Long rootDiskOfferingId, long volumesSize, Volume volume, Snapshot snapshot) throws ResourceAllocationException {
|
||||||
{
|
List<CheckedReservation> checkedReservations = new ArrayList<>();
|
||||||
List<String> rootResourceLimitStorageTags = getResourceLimitStorageTags(rootDiskOfferingId != null ? rootDiskOfferingId : offering.getDiskOfferingId());
|
|
||||||
List<String> additionalResourceLimitStorageTags = diskOfferingId != null ? getResourceLimitStorageTags(diskOfferingId) : null;
|
|
||||||
|
|
||||||
try (CheckedReservation rootVolumeReservation = new CheckedReservation(owner, ResourceType.volume, rootResourceLimitStorageTags, 1L, reservationDao, resourceLimitService);
|
try {
|
||||||
CheckedReservation additionalVolumeReservation = diskOfferingId != null ? new CheckedReservation(owner, ResourceType.volume, additionalResourceLimitStorageTags, 1L, reservationDao, resourceLimitService) : null;
|
checkedReservations = reserveStorageResourcesForVm(owner, diskOfferingId, diskSize, dataDiskInfoList, rootDiskOfferingId, offering, volumesSize);
|
||||||
CheckedReservation rootPrimaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, rootResourceLimitStorageTags, volumesSize, reservationDao, resourceLimitService);
|
|
||||||
CheckedReservation additionalPrimaryStorageReservation = diskOfferingId != null ? new CheckedReservation(owner, ResourceType.primary_storage, additionalResourceLimitStorageTags, additionalDiskSize, reservationDao, resourceLimitService) : null;
|
|
||||||
) {
|
|
||||||
|
|
||||||
// verify security group ids
|
// verify security group ids
|
||||||
if (securityGroupIdList != null) {
|
if (securityGroupIdList != null) {
|
||||||
@ -4557,15 +4584,24 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
|
|
||||||
UserVmVO vm = commitUserVm(zone, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, userDataId, userDataDetails, caller, isDisplayVm, keyboard, accountId, userId, offering,
|
UserVmVO vm = commitUserVm(zone, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, userDataId, userDataDetails, caller, isDisplayVm, keyboard, accountId, userId, offering,
|
||||||
isIso, sshPublicKeys, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, dhcpOptionMap,
|
isIso, sshPublicKeys, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, dhcpOptionMap,
|
||||||
datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, rootDiskOfferingId, keypairnames, volume, snapshot);
|
datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, rootDiskOfferingId, keypairnames, dataDiskInfoList, volume, snapshot);
|
||||||
|
|
||||||
assignInstanceToGroup(group, id);
|
assignInstanceToGroup(group, id);
|
||||||
return vm;
|
return vm;
|
||||||
} catch (ResourceAllocationException | CloudRuntimeException e) {
|
} catch (ResourceAllocationException | CloudRuntimeException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("error during resource reservation and allocation", e);
|
logger.error("error during resource reservation and allocation", e);
|
||||||
throw new CloudRuntimeException(e);
|
throw new CloudRuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
for (CheckedReservation checkedReservation : checkedReservations) {
|
||||||
|
try {
|
||||||
|
checkedReservation.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("error during resource reservation and allocation", e);
|
||||||
|
throw new CloudRuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4583,7 +4619,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long verifyAndGetDiskSize(DiskOfferingVO diskOffering, Long diskSize) {
|
private long verifyAndGetDiskSize(DiskOffering diskOffering, Long diskSize) {
|
||||||
long size = 0l;
|
long size = 0l;
|
||||||
if (diskOffering == null) {
|
if (diskOffering == null) {
|
||||||
throw new InvalidParameterValueException("Specified disk offering cannot be found");
|
throw new InvalidParameterValueException("Specified disk offering cannot be found");
|
||||||
@ -4698,7 +4734,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
final long accountId, final long userId, final ServiceOffering offering, final boolean isIso, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
final long accountId, final long userId, final ServiceOffering offering, final boolean isIso, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
||||||
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
|
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
|
||||||
final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||||
final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
|
final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs,
|
||||||
|
List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
|
||||||
UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, template.getGuestOSId(), offering.isOfferHA(),
|
UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, template.getGuestOSId(), offering.isOfferHA(),
|
||||||
offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, userDataId, userDataDetails, hostName);
|
offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, userDataId, userDataDetails, hostName);
|
||||||
vm.setUuid(uuidName);
|
vm.setUuid(uuidName);
|
||||||
@ -4816,7 +4853,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
|
|
||||||
orchestrateVirtualMachineCreate(vm, guestOSCategory, computeTags, rootDiskTags, plan, rootDiskSize, template, hostName, displayName, owner,
|
orchestrateVirtualMachineCreate(vm, guestOSCategory, computeTags, rootDiskTags, plan, rootDiskSize, template, hostName, displayName, owner,
|
||||||
diskOfferingId, diskSize, offering, isIso,networkNicMap, hypervisorType, extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
diskOfferingId, diskSize, offering, isIso,networkNicMap, hypervisorType, extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
||||||
rootDiskOfferingId, volume, snapshot);
|
rootDiskOfferingId, dataDiskInfoList, volume, snapshot);
|
||||||
|
|
||||||
}
|
}
|
||||||
CallContext.current().setEventDetails("Vm Id: " + vm.getUuid());
|
CallContext.current().setEventDetails("Vm Id: " + vm.getUuid());
|
||||||
@ -4849,16 +4886,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
ServiceOffering offering, boolean isIso, LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
ServiceOffering offering, boolean isIso, LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
||||||
HypervisorType hypervisorType,
|
HypervisorType hypervisorType,
|
||||||
Map<String, Map<Integer, String>> extraDhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
Map<String, Map<Integer, String>> extraDhcpOptionMap, Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||||
Long rootDiskOfferingId, Volume volume, Snapshot snapshot) throws InsufficientCapacityException{
|
Long rootDiskOfferingId, List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException{
|
||||||
try {
|
try {
|
||||||
if (isIso) {
|
if (isIso) {
|
||||||
_orchSrvc.createVirtualMachineFromScratch(vm.getUuid(), Long.toString(owner.getAccountId()), vm.getIsoId().toString(), hostName, displayName,
|
_orchSrvc.createVirtualMachineFromScratch(vm.getUuid(), Long.toString(owner.getAccountId()), vm.getIsoId().toString(), hostName, displayName,
|
||||||
hypervisorType.name(), guestOSCategory.getName(), offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags,
|
hypervisorType.name(), guestOSCategory.getName(), offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags,
|
||||||
networkNicMap, plan, extraDhcpOptionMap, rootDiskOfferingId, volume, snapshot);
|
networkNicMap, plan, extraDhcpOptionMap, rootDiskOfferingId, dataDiskInfoList, volume, snapshot);
|
||||||
} else {
|
} else {
|
||||||
_orchSrvc.createVirtualMachine(vm.getUuid(), Long.toString(owner.getAccountId()), Long.toString(template.getId()), hostName, displayName, hypervisorType.name(),
|
_orchSrvc.createVirtualMachine(vm.getUuid(), Long.toString(owner.getAccountId()), Long.toString(template.getId()), hostName, displayName, hypervisorType.name(),
|
||||||
offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, plan, rootDiskSize, extraDhcpOptionMap,
|
offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, plan, rootDiskSize, extraDhcpOptionMap,
|
||||||
dataDiskTemplateToDiskOfferingMap, diskOfferingId, rootDiskOfferingId, volume, snapshot);
|
dataDiskTemplateToDiskOfferingMap, diskOfferingId, rootDiskOfferingId, dataDiskInfoList, volume, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
@ -4979,14 +5016,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
final Long diskOfferingId, final Long diskSize, final String userData, Long userDataId, String userDataDetails, final Account caller, final Boolean isDisplayVm, final String keyboard,
|
final Long diskOfferingId, final Long diskSize, final String userData, Long userDataId, String userDataDetails, final Account caller, final Boolean isDisplayVm, final String keyboard,
|
||||||
final long accountId, final long userId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
final long accountId, final long userId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
|
||||||
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final Map<String,
|
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final Map<String,
|
||||||
Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
|
||||||
Map<String, String> userVmOVFPropertiesMap, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
|
Map<String, String> userVmOVFPropertiesMap, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs,
|
||||||
|
List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
|
||||||
return commitUserVm(false, zone, null, null, template, hostName, displayName, owner,
|
return commitUserVm(false, zone, null, null, template, hostName, displayName, owner,
|
||||||
diskOfferingId, diskSize, userData, userDataId, userDataDetails, isDisplayVm, keyboard,
|
diskOfferingId, diskSize, userData, userDataId, userDataDetails, isDisplayVm, keyboard,
|
||||||
accountId, userId, offering, isIso, sshPublicKeys, networkNicMap,
|
accountId, userId, offering, isIso, sshPublicKeys, networkNicMap,
|
||||||
id, instanceName, uuidName, hypervisorType, customParameters,
|
id, instanceName, uuidName, hypervisorType, customParameters,
|
||||||
extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
|
||||||
userVmOVFPropertiesMap, null, dynamicScalingEnabled, vmType, rootDiskOfferingId, sshkeypairs, volume, snapshot);
|
userVmOVFPropertiesMap, null, dynamicScalingEnabled, vmType, rootDiskOfferingId, sshkeypairs, dataDiskInfoList, volume, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateRootDiskResize(final HypervisorType hypervisorType, Long rootDiskSize, VMTemplateVO templateVO, UserVmVO vm, final Map<String, String> customParameters) throws InvalidParameterValueException
|
public void validateRootDiskResize(final HypervisorType hypervisorType, Long rootDiskSize, VMTemplateVO templateVO, UserVmVO vm, final Map<String, String> customParameters) throws InvalidParameterValueException
|
||||||
@ -6169,6 +6207,50 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verifyServiceOffering(BaseDeployVMCmd cmd, ServiceOffering serviceOffering) {
|
||||||
|
if (ServiceOffering.State.Inactive.equals(serviceOffering.getState())) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Service offering is inactive: [%s].", serviceOffering.getUuid()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Long overrideDiskOfferingId = cmd.getOverrideDiskOfferingId();
|
||||||
|
if (serviceOffering.getDiskOfferingStrictness() && overrideDiskOfferingId != null) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Cannot override disk offering id %d since provided service offering is strictly mapped to its disk offering", overrideDiskOfferingId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serviceOffering.isDynamic()) {
|
||||||
|
for(String detail: cmd.getDetails().keySet()) {
|
||||||
|
if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) {
|
||||||
|
throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyTemplate(BaseDeployVMCmd cmd, VirtualMachineTemplate template, Long serviceOfferingId) {
|
||||||
|
if (TemplateType.VNF.equals(template.getTemplateType())) {
|
||||||
|
vnfTemplateManager.validateVnfApplianceNics(template, cmd.getNetworkIds());
|
||||||
|
} else if (cmd instanceof DeployVnfApplianceCmd) {
|
||||||
|
throw new InvalidParameterValueException("Can't deploy VNF appliance from a non-VNF template");
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceOfferingJoinVO svcOffering = serviceOfferingJoinDao.findById(serviceOfferingId);
|
||||||
|
|
||||||
|
if (template.isDeployAsIs()) {
|
||||||
|
if (svcOffering != null && svcOffering.getRootDiskSize() != null && svcOffering.getRootDiskSize() > 0) {
|
||||||
|
throw new InvalidParameterValueException("Failed to deploy Virtual Machine as a service offering with root disk size specified cannot be used with a deploy as-is template");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.getDetails().get("rootdisksize") != null) {
|
||||||
|
throw new InvalidParameterValueException("Overriding root disk size isn't supported for VMs deployed from deploy as-is templates");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootmode and boottype are not supported on VMWare dpeloy-as-is templates (since 4.15)
|
||||||
|
if ((cmd.getBootMode() != null || cmd.getBootType() != null)) {
|
||||||
|
throw new InvalidParameterValueException("Boot type and boot mode are not supported on VMware for templates registered as deploy-as-is, as we honour what is defined in the template.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
|
public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
|
||||||
StorageUnavailableException, ResourceAllocationException {
|
StorageUnavailableException, ResourceAllocationException {
|
||||||
@ -6185,28 +6267,16 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
|
|
||||||
Long serviceOfferingId = cmd.getServiceOfferingId();
|
Long serviceOfferingId = cmd.getServiceOfferingId();
|
||||||
|
if (serviceOfferingId == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to execute API command deployvirtualmachine due to missing parameter serviceofferingid");
|
||||||
|
}
|
||||||
Long overrideDiskOfferingId = cmd.getOverrideDiskOfferingId();
|
Long overrideDiskOfferingId = cmd.getOverrideDiskOfferingId();
|
||||||
|
|
||||||
ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId);
|
ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId);
|
||||||
if (serviceOffering == null) {
|
if (serviceOffering == null) {
|
||||||
throw new InvalidParameterValueException("Unable to find service offering: " + serviceOfferingId);
|
throw new InvalidParameterValueException("Unable to find service offering: " + serviceOffering.getId());
|
||||||
}
|
|
||||||
|
|
||||||
if (ServiceOffering.State.Inactive.equals(serviceOffering.getState())) {
|
|
||||||
throw new InvalidParameterValueException(String.format("Service offering is inactive: [%s].", serviceOffering.getUuid()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serviceOffering.getDiskOfferingStrictness() && overrideDiskOfferingId != null) {
|
|
||||||
throw new InvalidParameterValueException(String.format("Cannot override disk offering id %d since provided service offering is strictly mapped to its disk offering", overrideDiskOfferingId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serviceOffering.isDynamic()) {
|
|
||||||
for(String detail: cmd.getDetails().keySet()) {
|
|
||||||
if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) {
|
|
||||||
throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
verifyServiceOffering(cmd, serviceOffering);
|
||||||
|
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
Long callerId = caller.getId();
|
Long callerId = caller.getId();
|
||||||
@ -6234,44 +6304,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
overrideDiskOfferingId = volumeOfSnapshot.getDiskOfferingId();
|
overrideDiskOfferingId = volumeOfSnapshot.getDiskOfferingId();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean dynamicScalingEnabled = cmd.isDynamicScalingEnabled();
|
|
||||||
|
|
||||||
VirtualMachineTemplate template = null;
|
VirtualMachineTemplate template = null;
|
||||||
if (volume != null || snapshot != null) {
|
if (volume != null || snapshot != null) {
|
||||||
template = _entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, templateId);
|
template = _entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, templateId);
|
||||||
} else {
|
} else {
|
||||||
template = _entityMgr.findById(VirtualMachineTemplate.class, templateId);
|
template = _entityMgr.findById(VirtualMachineTemplate.class, templateId);
|
||||||
}
|
}
|
||||||
// Make sure a valid template ID was specified
|
|
||||||
if (template == null) {
|
|
||||||
throw new InvalidParameterValueException("Unable to use template " + templateId);
|
|
||||||
}
|
|
||||||
if (TemplateType.VNF.equals(template.getTemplateType())) {
|
|
||||||
vnfTemplateManager.validateVnfApplianceNics(template, cmd.getNetworkIds());
|
|
||||||
} else if (cmd instanceof DeployVnfApplianceCmd) {
|
|
||||||
throw new InvalidParameterValueException("Can't deploy VNF appliance from a non-VNF template");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd.isVolumeOrSnapshotProvided() &&
|
if (cmd.isVolumeOrSnapshotProvided() &&
|
||||||
(!(HypervisorType.KVM.equals(template.getHypervisorType()) || HypervisorType.KVM.equals(cmd.getHypervisor())))) {
|
(!(HypervisorType.KVM.equals(template.getHypervisorType()) || HypervisorType.KVM.equals(cmd.getHypervisor())))) {
|
||||||
throw new InvalidParameterValueException("Deploying a virtual machine with existing volume/snapshot is supported only from KVM hypervisors");
|
throw new InvalidParameterValueException("Deploying a virtual machine with existing volume/snapshot is supported only from KVM hypervisors");
|
||||||
}
|
}
|
||||||
ServiceOfferingJoinVO svcOffering = serviceOfferingJoinDao.findById(serviceOfferingId);
|
// Make sure a valid template ID was specified
|
||||||
|
if (template == null) {
|
||||||
if (template.isDeployAsIs()) {
|
throw new InvalidParameterValueException("Unable to use template " + templateId);
|
||||||
if (svcOffering != null && svcOffering.getRootDiskSize() != null && svcOffering.getRootDiskSize() > 0) {
|
|
||||||
throw new InvalidParameterValueException("Failed to deploy Virtual Machine as a service offering with root disk size specified cannot be used with a deploy as-is template");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd.getDetails().get("rootdisksize") != null) {
|
|
||||||
throw new InvalidParameterValueException("Overriding root disk size isn't supported for VMs deployed from deploy as-is templates");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bootmode and boottype are not supported on VMWare dpeloy-as-is templates (since 4.15)
|
|
||||||
if ((cmd.getBootMode() != null || cmd.getBootType() != null)) {
|
|
||||||
throw new InvalidParameterValueException("Boot type and boot mode are not supported on VMware for templates registered as deploy-as-is, as we honour what is defined in the template.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
verifyTemplate(cmd, template, serviceOfferingId);
|
||||||
|
|
||||||
Long diskOfferingId = cmd.getDiskOfferingId();
|
Long diskOfferingId = cmd.getDiskOfferingId();
|
||||||
DiskOffering diskOffering = null;
|
DiskOffering diskOffering = null;
|
||||||
@ -6285,6 +6332,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<VmDiskInfo> dataDiskInfoList = cmd.getDataDiskInfoList();
|
||||||
|
if (dataDiskInfoList != null && diskOfferingId != null) {
|
||||||
|
new InvalidParameterValueException("Cannot specify both disk offering id and data disk offering details");
|
||||||
|
}
|
||||||
|
|
||||||
if (!zone.isLocalStorageEnabled()) {
|
if (!zone.isLocalStorageEnabled()) {
|
||||||
DiskOffering diskOfferingMappedInServiceOffering = _entityMgr.findById(DiskOffering.class, serviceOffering.getDiskOfferingId());
|
DiskOffering diskOfferingMappedInServiceOffering = _entityMgr.findById(DiskOffering.class, serviceOffering.getDiskOfferingId());
|
||||||
if (diskOfferingMappedInServiceOffering.isUseLocalStorage()) {
|
if (diskOfferingMappedInServiceOffering.isUseLocalStorage()) {
|
||||||
@ -6295,25 +6347,48 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isLeaseFeatureEnabled = VMLeaseManager.InstanceLeaseEnabled.value();
|
|
||||||
if (isLeaseFeatureEnabled) {
|
|
||||||
validateLeaseProperties(cmd.getLeaseDuration(), cmd.getLeaseExpiryAction());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Long> networkIds = cmd.getNetworkIds();
|
List<Long> networkIds = cmd.getNetworkIds();
|
||||||
LinkedHashMap<Integer, Long> userVmNetworkMap = getVmOvfNetworkMapping(zone, owner, template, cmd.getVmNetworkMap());
|
LinkedHashMap<Integer, Long> userVmNetworkMap = getVmOvfNetworkMapping(zone, owner, template, cmd.getVmNetworkMap());
|
||||||
if (MapUtils.isNotEmpty(userVmNetworkMap)) {
|
if (MapUtils.isNotEmpty(userVmNetworkMap)) {
|
||||||
networkIds = new ArrayList<>(userVmNetworkMap.values());
|
networkIds = new ArrayList<>(userVmNetworkMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
String userData = cmd.getUserData();
|
return createVirtualMachine(cmd, zone, owner, serviceOffering, template, cmd.getHypervisor(), diskOfferingId, cmd.getSize(), overrideDiskOfferingId, dataDiskInfoList, networkIds, cmd.getIpToNetworkMap(), volume, snapshot);
|
||||||
Long userDataId = cmd.getUserdataId();
|
}
|
||||||
String userDataDetails = null;
|
|
||||||
if (MapUtils.isNotEmpty(cmd.getUserdataDetails())) {
|
private UserVm createVirtualMachine(BaseDeployVMCmd cmd, DataCenter zone, Account owner, ServiceOffering serviceOffering, VirtualMachineTemplate template,
|
||||||
userDataDetails = cmd.getUserdataDetails().toString();
|
HypervisorType hypervisor, Long diskOfferingId, Long size, Long overrideDiskOfferingId, List<VmDiskInfo> dataDiskInfoList,
|
||||||
|
List<Long> networkIds, Map<Long, IpAddresses> ipToNetworkMap, Volume volume, Snapshot snapshot) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, ResourceAllocationException {
|
||||||
|
|
||||||
|
ServiceOfferingJoinVO svcOffering = serviceOfferingJoinDao.findById(serviceOffering.getId());
|
||||||
|
boolean isLeaseFeatureEnabled = VMLeaseManager.InstanceLeaseEnabled.value();
|
||||||
|
if (isLeaseFeatureEnabled) {
|
||||||
|
validateLeaseProperties(cmd.getLeaseDuration(), cmd.getLeaseExpiryAction());
|
||||||
}
|
}
|
||||||
userData = finalizeUserData(userData, userDataId, template);
|
|
||||||
userData = userDataManager.validateUserData(userData, cmd.getHttpMethod());
|
String userData = null;
|
||||||
|
Long userDataId = null;
|
||||||
|
String userDataDetails = null;
|
||||||
|
List<String> sshKeyPairNames = new ArrayList<String>();
|
||||||
|
if (cmd instanceof CreateVMFromBackupCmd) {
|
||||||
|
if (cmd.getUserData() != null) {
|
||||||
|
throw new InvalidParameterValueException("User data not supported for instance created from backup");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
userData = cmd.getUserData();
|
||||||
|
userDataId = cmd.getUserdataId();
|
||||||
|
userDataDetails = null;
|
||||||
|
if (MapUtils.isNotEmpty(cmd.getUserdataDetails())) {
|
||||||
|
userDataDetails = cmd.getUserdataDetails().toString();
|
||||||
|
}
|
||||||
|
userData = finalizeUserData(userData, userDataId, template);
|
||||||
|
userData = userDataManager.validateUserData(userData, cmd.getHttpMethod());
|
||||||
|
|
||||||
|
sshKeyPairNames = cmd.getSSHKeyPairNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
|
Long callerId = caller.getId();
|
||||||
|
|
||||||
boolean isRootAdmin = _accountService.isRootAdmin(callerId);
|
boolean isRootAdmin = _accountService.isRootAdmin(callerId);
|
||||||
|
|
||||||
@ -6327,9 +6402,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
String displayName = cmd.getDisplayName();
|
String displayName = cmd.getDisplayName();
|
||||||
UserVm vm = null;
|
UserVm vm = null;
|
||||||
IpAddresses addrs = new IpAddresses(ipAddress, ip6Address, macAddress);
|
IpAddresses addrs = new IpAddresses(ipAddress, ip6Address, macAddress);
|
||||||
Long size = cmd.getSize();
|
boolean dynamicScalingEnabled = cmd.isDynamicScalingEnabled();
|
||||||
String group = cmd.getGroup();
|
String group = cmd.getGroup();
|
||||||
List<String> sshKeyPairNames = cmd.getSSHKeyPairNames();
|
|
||||||
Boolean displayVm = cmd.isDisplayVm();
|
Boolean displayVm = cmd.isDisplayVm();
|
||||||
String keyboard = cmd.getKeyboard();
|
String keyboard = cmd.getKeyboard();
|
||||||
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap();
|
Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap();
|
||||||
@ -6339,7 +6413,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
|
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
|
||||||
} else {
|
} else {
|
||||||
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd, zone, template, owner), owner, name, displayName, diskOfferingId,
|
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd, zone, template, owner), owner, name, displayName, diskOfferingId,
|
||||||
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
|
size , dataDiskInfoList, group , hypervisor, cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, ipToNetworkMap, addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
|
||||||
cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
||||||
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId, volume, snapshot);
|
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId, volume, snapshot);
|
||||||
}
|
}
|
||||||
@ -6347,7 +6421,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
if (_networkModel.checkSecurityGroupSupportForNetwork(owner, zone, networkIds,
|
if (_networkModel.checkSecurityGroupSupportForNetwork(owner, zone, networkIds,
|
||||||
cmd.getSecurityGroupIdList())) {
|
cmd.getSecurityGroupIdList())) {
|
||||||
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd, zone, template, owner), owner, name,
|
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd, zone, template, owner), owner, name,
|
||||||
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
|
displayName, diskOfferingId, size, dataDiskInfoList, group, hypervisor, cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, ipToNetworkMap, addrs, displayVm, keyboard,
|
||||||
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
||||||
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId, null, volume, snapshot);
|
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId, null, volume, snapshot);
|
||||||
|
|
||||||
@ -6355,8 +6429,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) {
|
if (cmd.getSecurityGroupIdList() != null && !cmd.getSecurityGroupIdList().isEmpty()) {
|
||||||
throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone");
|
throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone");
|
||||||
}
|
}
|
||||||
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, group,
|
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, dataDiskInfoList, group,
|
||||||
cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
|
hypervisor, cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, ipToNetworkMap, addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
|
||||||
cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId, volume, snapshot);
|
cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId, volume, snapshot);
|
||||||
if (cmd instanceof DeployVnfApplianceCmd) {
|
if (cmd instanceof DeployVnfApplianceCmd) {
|
||||||
vnfTemplateManager.createIsolatedNetworkRulesForVnfAppliance(zone, template, owner, vm, (DeployVnfApplianceCmd) cmd);
|
vnfTemplateManager.createIsolatedNetworkRulesForVnfAppliance(zone, template, owner, vm, (DeployVnfApplianceCmd) cmd);
|
||||||
@ -6365,7 +6439,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if this templateId has a child ISO
|
// check if this templateId has a child ISO
|
||||||
List<VMTemplateVO> child_templates = _templateDao.listByParentTemplatetId(templateId);
|
List<VMTemplateVO> child_templates = _templateDao.listByParentTemplatetId(template.getId());
|
||||||
for (VMTemplateVO tmpl: child_templates){
|
for (VMTemplateVO tmpl: child_templates){
|
||||||
if (tmpl.getFormat() == Storage.ImageFormat.ISO){
|
if (tmpl.getFormat() == Storage.ImageFormat.ISO){
|
||||||
logger.info("MDOV trying to attach disk {} to the VM {}", tmpl, vm);
|
logger.info("MDOV trying to attach disk {} to the VM {}", tmpl, vm);
|
||||||
@ -6385,10 +6459,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cmd.getCopyImageTags()) {
|
if (cmd.getCopyImageTags()) {
|
||||||
VMTemplateVO templateOrIso = _templateDao.findById(templateId);
|
VMTemplateVO templateOrIso = _templateDao.findById(template.getId());
|
||||||
if (templateOrIso != null) {
|
if (templateOrIso != null) {
|
||||||
final ResourceTag.ResourceObjectType templateType = (templateOrIso.getFormat() == ImageFormat.ISO) ? ResourceTag.ResourceObjectType.ISO : ResourceTag.ResourceObjectType.Template;
|
final ResourceTag.ResourceObjectType templateType = (templateOrIso.getFormat() == ImageFormat.ISO) ? ResourceTag.ResourceObjectType.ISO : ResourceTag.ResourceObjectType.Template;
|
||||||
final List<? extends ResourceTag> resourceTags = resourceTagDao.listBy(templateId, templateType);
|
final List<? extends ResourceTag> resourceTags = resourceTagDao.listBy(template.getId(), templateType);
|
||||||
for (ResourceTag resourceTag : resourceTags) {
|
for (ResourceTag resourceTag : resourceTags) {
|
||||||
final ResourceTagVO copyTag = new ResourceTagVO(resourceTag.getKey(), resourceTag.getValue(), resourceTag.getAccountId(), resourceTag.getDomainId(), vm.getId(), ResourceTag.ResourceObjectType.UserVm, resourceTag.getCustomer(), vm.getUuid());
|
final ResourceTagVO copyTag = new ResourceTagVO(resourceTag.getKey(), resourceTag.getValue(), resourceTag.getAccountId(), resourceTag.getDomainId(), vm.getId(), ResourceTag.ResourceObjectType.UserVm, resourceTag.getCustomer(), vm.getUuid());
|
||||||
resourceTagDao.persist(copyTag);
|
resourceTagDao.persist(copyTag);
|
||||||
@ -9331,7 +9405,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
null, null, userData, null, null, isDisplayVm, keyboard,
|
null, null, userData, null, null, isDisplayVm, keyboard,
|
||||||
accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKeys, networkNicMap,
|
accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKeys, networkNicMap,
|
||||||
id, instanceName, uuidName, hypervisorType, customParameters,
|
id, instanceName, uuidName, hypervisorType, customParameters,
|
||||||
null, null, null, powerState, dynamicScalingEnabled, null, serviceOffering.getDiskOfferingId(), null, null, null);
|
null, null, null, powerState, dynamicScalingEnabled, null, serviceOffering.getDiskOfferingId(), null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -9376,6 +9450,234 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateDetailsWithRootDiskAttributes(Map<String, String> details, VmDiskInfo rootVmDiskInfo) {
|
||||||
|
details.put(VmDetailConstants.ROOT_DISK_SIZE, rootVmDiskInfo.getSize().toString());
|
||||||
|
if (rootVmDiskInfo.getMinIops() != null) {
|
||||||
|
details.put(MIN_IOPS, rootVmDiskInfo.getMinIops().toString());
|
||||||
|
}
|
||||||
|
if (rootVmDiskInfo.getMaxIops() != null) {
|
||||||
|
details.put(MAX_IOPS, rootVmDiskInfo.getMaxIops().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkRootDiskSizeAgainstBackup(Long instanceVolumeSize,DiskOffering rootDiskOffering, Long backupVolumeSize) {
|
||||||
|
Long instanceRootDiskSize = rootDiskOffering.isCustomized() ? instanceVolumeSize : rootDiskOffering.getDiskSize() / GiB_TO_BYTES;
|
||||||
|
if (instanceRootDiskSize < backupVolumeSize) {
|
||||||
|
throw new InvalidParameterValueException(
|
||||||
|
String.format("Instance volume root disk size %d[GiB] cannot be less than the backed-up volume size %d[GiB].",
|
||||||
|
instanceVolumeSize, backupVolumeSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserVm allocateVMFromBackup(CreateVMFromBackupCmd cmd) throws InsufficientCapacityException, ResourceAllocationException, ResourceUnavailableException {
|
||||||
|
if (!backupManager.canCreateInstanceFromBackup(cmd.getBackupId())) {
|
||||||
|
throw new CloudRuntimeException("Create instance from backup is not supported for this provider.");
|
||||||
|
}
|
||||||
|
DataCenter zone = _dcDao.findById(cmd.getZoneId());
|
||||||
|
if (zone == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to find zone by id=" + cmd.getZoneId());
|
||||||
|
}
|
||||||
|
|
||||||
|
BackupVO backup = backupDao.findById(cmd.getBackupId());
|
||||||
|
if (backup == null) {
|
||||||
|
throw new InvalidParameterValueException("Backup " + cmd.getBackupId() + " does not exist");
|
||||||
|
}
|
||||||
|
if (backup.getZoneId() != cmd.getZoneId()) {
|
||||||
|
throw new InvalidParameterValueException("Instance should be created in the same zone as the backup");
|
||||||
|
}
|
||||||
|
backupManager.validateBackupForZone(backup.getZoneId());
|
||||||
|
backupDao.loadDetails(backup);
|
||||||
|
|
||||||
|
verifyDetails(cmd.getDetails());
|
||||||
|
|
||||||
|
UserVmVO backupVm = _vmDao.findByIdIncludingRemoved(backup.getVmId());
|
||||||
|
HypervisorType hypervisorType = backupVm.getHypervisorType();
|
||||||
|
|
||||||
|
Long serviceOfferingId = cmd.getServiceOfferingId();
|
||||||
|
ServiceOffering serviceOffering;
|
||||||
|
if (serviceOfferingId != null) {
|
||||||
|
serviceOffering = serviceOfferingDao.findById(serviceOfferingId);
|
||||||
|
if (serviceOffering == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to find service offering: " + serviceOffering.getId());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String serviceOfferingUuid = backup.getDetail(ApiConstants.SERVICE_OFFERING_ID);
|
||||||
|
if (serviceOfferingUuid == null) {
|
||||||
|
throw new CloudRuntimeException("Backup doesn't contain service offering uuid. Please specify a valid service offering id while creating the instance");
|
||||||
|
}
|
||||||
|
serviceOffering = serviceOfferingDao.findByUuid(serviceOfferingUuid);
|
||||||
|
if (serviceOffering == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to find service offering with the uuid stored in backup. Please specify a valid service offering id while creating instance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verifyServiceOffering(cmd, serviceOffering);
|
||||||
|
|
||||||
|
VirtualMachineTemplate template;
|
||||||
|
if (cmd.getTemplateId() != null) {
|
||||||
|
Long templateId = cmd.getTemplateId();
|
||||||
|
template = _templateDao.findById(templateId);
|
||||||
|
if (template == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to use template " + templateId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String templateUuid = backup.getDetail(ApiConstants.TEMPLATE_ID);
|
||||||
|
if (templateUuid == null) {
|
||||||
|
throw new CloudRuntimeException("Backup doesn't contain Template uuid. Please specify a valid Template/ISO while creating the instance");
|
||||||
|
}
|
||||||
|
template = _templateDao.findByUuid(templateUuid);
|
||||||
|
if (template == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to find template associated with the backup. Please specify a valid Template/ISO while creating instance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verifyTemplate(cmd, template, serviceOffering.getId());
|
||||||
|
|
||||||
|
Long size = cmd.getSize();
|
||||||
|
|
||||||
|
Long diskOfferingId = cmd.getDiskOfferingId();
|
||||||
|
Boolean isIso = template.getFormat().equals(ImageFormat.ISO);
|
||||||
|
if (diskOfferingId != null) {
|
||||||
|
if (!isIso) {
|
||||||
|
throw new InvalidParameterValueException(ApiConstants.DISK_OFFERING_ID + " parameter is supported for creating instance from backup only for ISO. For creating VMs with templates, please use the parameter " + ApiConstants.DATADISKS_DETAILS);
|
||||||
|
}
|
||||||
|
DiskOffering diskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||||
|
if (diskOffering == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to find disk offering " + diskOfferingId);
|
||||||
|
}
|
||||||
|
if (diskOffering.isComputeOnly()) {
|
||||||
|
throw new InvalidParameterValueException(String.format("The disk offering %s provided is directly mapped to a service offering, please provide an individual disk offering", diskOffering));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Long overrideDiskOfferingId = cmd.getOverrideDiskOfferingId();
|
||||||
|
|
||||||
|
VmDiskInfo rootVmDiskInfoFromBackup = backupManager.getRootDiskInfoFromBackup(backup);
|
||||||
|
|
||||||
|
if (isIso) {
|
||||||
|
if (diskOfferingId == null) {
|
||||||
|
diskOfferingId = rootVmDiskInfoFromBackup.getDiskOffering().getId();
|
||||||
|
updateDetailsWithRootDiskAttributes(cmd.getDetails(), rootVmDiskInfoFromBackup);
|
||||||
|
size = rootVmDiskInfoFromBackup.getSize();
|
||||||
|
} else {
|
||||||
|
DiskOffering rootDiskOffering = _diskOfferingDao.findById(diskOfferingId);
|
||||||
|
checkRootDiskSizeAgainstBackup(size, rootDiskOffering, rootVmDiskInfoFromBackup.getSize());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (overrideDiskOfferingId == null) {
|
||||||
|
overrideDiskOfferingId = serviceOffering.getDiskOfferingId();
|
||||||
|
updateDetailsWithRootDiskAttributes(cmd.getDetails(), rootVmDiskInfoFromBackup);
|
||||||
|
} else {
|
||||||
|
DiskOffering overrideDiskOffering = _diskOfferingDao.findById(overrideDiskOfferingId);
|
||||||
|
if (overrideDiskOffering.isComputeOnly()) {
|
||||||
|
updateDetailsWithRootDiskAttributes(cmd.getDetails(), rootVmDiskInfoFromBackup);
|
||||||
|
} else {
|
||||||
|
String diskSizeFromDetails = cmd.getDetails().get(VmDetailConstants.ROOT_DISK_SIZE);
|
||||||
|
Long rootDiskSize = diskSizeFromDetails == null ? null : Long.parseLong(diskSizeFromDetails);
|
||||||
|
checkRootDiskSizeAgainstBackup(rootDiskSize, overrideDiskOffering, rootVmDiskInfoFromBackup.getSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<VmDiskInfo> dataDiskInfoList = cmd.getDataDiskInfoList();
|
||||||
|
if (dataDiskInfoList != null) {
|
||||||
|
backupManager.checkVmDisksSizeAgainstBackup(dataDiskInfoList, backup);
|
||||||
|
} else {
|
||||||
|
dataDiskInfoList = backupManager.getDataDiskInfoListFromBackup(backup);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Long> networkIds = cmd.getNetworkIds();
|
||||||
|
Account owner = _accountService.getActiveAccountById(cmd.getEntityOwnerId());
|
||||||
|
LinkedHashMap<Integer, Long> userVmNetworkMap = getVmOvfNetworkMapping(zone, owner, template, cmd.getVmNetworkMap());
|
||||||
|
if (MapUtils.isNotEmpty(userVmNetworkMap)) {
|
||||||
|
networkIds = new ArrayList<>(userVmNetworkMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, IpAddresses> ipToNetworkMap = cmd.getIpToNetworkMap();
|
||||||
|
if (networkIds == null && ipToNetworkMap == null) {
|
||||||
|
networkIds = new ArrayList<Long>();
|
||||||
|
ipToNetworkMap = backupManager.getIpToNetworkMapFromBackup(backup, cmd.getPreserveIp(), networkIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserVm vm = createVirtualMachine(cmd, zone, owner, serviceOffering, template, hypervisorType, diskOfferingId, size, overrideDiskOfferingId, dataDiskInfoList, networkIds, ipToNetworkMap, null, null);
|
||||||
|
|
||||||
|
String vmSettingsFromBackup = backup.getDetail(ApiConstants.VM_SETTINGS);
|
||||||
|
if (vm != null && vmSettingsFromBackup != null) {
|
||||||
|
UserVmVO vmVO = _vmDao.findById(vm.getId());
|
||||||
|
Map<String, String> details = vmInstanceDetailsDao.listDetailsKeyPairs(vm.getId());
|
||||||
|
vmVO.setDetails(details);
|
||||||
|
|
||||||
|
Type type = new TypeToken<Map<String, String>>(){}.getType();
|
||||||
|
Map<String, String> vmDetailsFromBackup = new Gson().fromJson(vmSettingsFromBackup, type);
|
||||||
|
for (Entry<String, String> entry : vmDetailsFromBackup.entrySet()) {
|
||||||
|
if (!details.containsKey(entry.getKey())) {
|
||||||
|
vmVO.setDetail(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_vmDao.saveDetails(vmVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserVm restoreVMFromBackup(CreateVMFromBackupCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
|
||||||
|
long vmId = cmd.getEntityId();
|
||||||
|
Map<Long, DiskOffering> diskOfferingMap = cmd.getDataDiskTemplateToDiskOfferingMap();
|
||||||
|
Map<VirtualMachineProfile.Param, Object> additonalParams = new HashMap<>();
|
||||||
|
UserVm vm;
|
||||||
|
|
||||||
|
try {
|
||||||
|
vm = startVirtualMachine(vmId, null, null, null, diskOfferingMap, additonalParams, null);
|
||||||
|
|
||||||
|
boolean status = stopVirtualMachine(CallContext.current().getCallingUserId(), vm.getId()) ;
|
||||||
|
if (!status) {
|
||||||
|
UserVmVO vmVO = _vmDao.findById(vmId);
|
||||||
|
expunge(vmVO);
|
||||||
|
logger.debug("Successfully cleaned up Instance {} after create Instance from backup failed", vmId);
|
||||||
|
throw new CloudRuntimeException("Unable to stop the Instance before restore");
|
||||||
|
}
|
||||||
|
|
||||||
|
Long isoId = vm.getIsoId();
|
||||||
|
if (isoId != null) {
|
||||||
|
UserVmVO vmVO = _vmDao.findById(vmId);
|
||||||
|
vmVO.setIsoId(null);
|
||||||
|
_vmDao.update(vm.getId(), vmVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
backupManager.restoreBackupToVM(cmd.getBackupId(), vmId);
|
||||||
|
|
||||||
|
} catch (CloudRuntimeException e) {
|
||||||
|
UserVmVO vmVO = _vmDao.findById(vmId);
|
||||||
|
try {
|
||||||
|
expunge(vmVO);
|
||||||
|
logger.debug("Successfully cleaned up Instance {} after create Instance from backup failed", vmId);
|
||||||
|
} catch (Exception cleanupException) {
|
||||||
|
logger.debug("Failed to cleanup Instance {} after create Instance from backup failed", vmId, cleanupException);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Account owner = _accountService.getActiveAccountById(cmd.getEntityOwnerId());
|
||||||
|
UserVmVO userVm = _vmDao.findById(vmId);
|
||||||
|
|
||||||
|
List<String> sshKeyPairNames = cmd.getSSHKeyPairNames();
|
||||||
|
if (sshKeyPairNames != null && !sshKeyPairNames.isEmpty()) {
|
||||||
|
vm = resetVMSSHKeyInternal(userVm, owner, sshKeyPairNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.getStartVm()) {
|
||||||
|
Long podId = null;
|
||||||
|
Long clusterId = null;
|
||||||
|
if (cmd instanceof CreateVMFromBackupCmdByAdmin) {
|
||||||
|
CreateVMFromBackupCmdByAdmin adminCmd = (CreateVMFromBackupCmdByAdmin)cmd;
|
||||||
|
podId = adminCmd.getPodId();
|
||||||
|
clusterId = adminCmd.getClusterId();
|
||||||
|
}
|
||||||
|
vm = startVirtualMachine(vmId, podId, clusterId, cmd.getHostId(), diskOfferingMap, additonalParams, cmd.getDeploymentPlanner());
|
||||||
|
}
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Generate usage events related to unmanaging a VM
|
Generate usage events related to unmanaging a VM
|
||||||
*/
|
*/
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user