Add support for functionality in hypervisor class (#9736)

* Add support for functionality in hypervisor class

* Address comments

* address comments
This commit is contained in:
Vishesh 2024-12-03 12:20:59 +05:30 committed by GitHub
parent f3a474bb9e
commit 52e7b41a54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 58 additions and 31 deletions

View File

@ -20,37 +20,57 @@ import com.cloud.storage.Storage.ImageFormat;
import org.apache.commons.lang3.StringUtils;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.EnumSet;
import java.util.stream.Collectors;
import static com.cloud.hypervisor.Hypervisor.HypervisorType.Functionality.DirectDownloadTemplate;
import static com.cloud.hypervisor.Hypervisor.HypervisorType.Functionality.RootDiskSizeOverride;
import static com.cloud.hypervisor.Hypervisor.HypervisorType.Functionality.VmStorageMigration;
public class Hypervisor {
public static class HypervisorType {
public enum Functionality {
DirectDownloadTemplate,
RootDiskSizeOverride,
VmStorageMigration
}
private static final Map<String, HypervisorType> hypervisorTypeMap = new LinkedHashMap<>();
public static final HypervisorType None = new HypervisorType("None"); //for storage hosts
public static final HypervisorType XenServer = new HypervisorType("XenServer", ImageFormat.VHD);
public static final HypervisorType KVM = new HypervisorType("KVM", ImageFormat.QCOW2);
public static final HypervisorType VMware = new HypervisorType("VMware", ImageFormat.OVA);
public static final HypervisorType XenServer = new HypervisorType("XenServer", ImageFormat.VHD, EnumSet.of(RootDiskSizeOverride, VmStorageMigration));
public static final HypervisorType KVM = new HypervisorType("KVM", ImageFormat.QCOW2, EnumSet.of(DirectDownloadTemplate, RootDiskSizeOverride, VmStorageMigration));
public static final HypervisorType VMware = new HypervisorType("VMware", ImageFormat.OVA, EnumSet.of(RootDiskSizeOverride, VmStorageMigration));
public static final HypervisorType Hyperv = new HypervisorType("Hyperv");
public static final HypervisorType VirtualBox = new HypervisorType("VirtualBox");
public static final HypervisorType Parralels = new HypervisorType("Parralels");
public static final HypervisorType BareMetal = new HypervisorType("BareMetal");
public static final HypervisorType Simulator = new HypervisorType("Simulator");
public static final HypervisorType Simulator = new HypervisorType("Simulator", null, EnumSet.of(RootDiskSizeOverride, VmStorageMigration));
public static final HypervisorType Ovm = new HypervisorType("Ovm", ImageFormat.RAW);
public static final HypervisorType Ovm3 = new HypervisorType("Ovm3", ImageFormat.RAW);
public static final HypervisorType LXC = new HypervisorType("LXC");
public static final HypervisorType Custom = new HypervisorType("Custom");
public static final HypervisorType Custom = new HypervisorType("Custom", null, EnumSet.of(RootDiskSizeOverride));
public static final HypervisorType Any = new HypervisorType("Any"); /*If you don't care about the hypervisor type*/
private final String name;
private final ImageFormat imageFormat;
private final Set<Functionality> supportedFunctionalities;
public HypervisorType(String name) {
this(name, null);
this(name, null, EnumSet.noneOf(Functionality.class));
}
public HypervisorType(String name, ImageFormat imageFormat) {
this(name, imageFormat, EnumSet.noneOf(Functionality.class));
}
public HypervisorType(String name, ImageFormat imageFormat, Set<Functionality> supportedFunctionalities) {
this.name = name;
this.imageFormat = imageFormat;
this.supportedFunctionalities = supportedFunctionalities;
if (name.equals("Parralels")){ // typo in the original code
hypervisorTypeMap.put("parallels", this);
} else {
@ -81,6 +101,12 @@ public class Hypervisor {
return hypervisorType;
}
public static List<HypervisorType> getListOfHypervisorsSupportingFunctionality(Functionality functionality) {
return hypervisorTypeMap.values().stream()
.filter(hypervisor -> hypervisor.supportedFunctionalities.contains(functionality))
.collect(Collectors.toList());
}
/**
* Returns the display name of a hypervisor type in case the custom hypervisor is used,
* using the 'hypervisor.custom.display.name' setting. Otherwise, returns hypervisor name
@ -102,6 +128,15 @@ public class Hypervisor {
return name;
}
/**
* Make this method to be part of the properties of the hypervisor type itself.
*
* @return true if the hypervisor plugin support the specified functionality
*/
public boolean isFunctionalitySupported(Functionality functionality) {
return supportedFunctionalities.contains(functionality);
}
@Override
public int hashCode() {
return Objects.hash(name);

View File

@ -362,7 +362,9 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
"Parameter zoneids cannot combine all zones (-1) option with other zones");
String customHypervisor = HypervisorGuru.HypervisorCustomDisplayName.value();
if (isDirectDownload() && !(getHypervisor().equalsIgnoreCase(Hypervisor.HypervisorType.KVM.toString())
if (isDirectDownload() &&
!(Hypervisor.HypervisorType.getType(getHypervisor())
.isFunctionalitySupported(Hypervisor.HypervisorType.Functionality.DirectDownloadTemplate)
|| getHypervisor().equalsIgnoreCase(customHypervisor))) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Parameter directdownload " +
"is only allowed for KVM or %s templates", customHypervisor));

View File

@ -16,6 +16,7 @@
// under the License.
package com.cloud.vm;
import static com.cloud.hypervisor.Hypervisor.HypervisorType.Functionality;
import static com.cloud.storage.Volume.IOPS_LIMIT;
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
import static org.apache.cloudstack.api.ApiConstants.MAX_IOPS;
@ -679,23 +680,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
private static final ConfigKey<Boolean> VmDestroyForcestop = new ConfigKey<Boolean>("Advanced", Boolean.class, "vm.destroy.forcestop", "false",
"On destroy, force-stop takes this value ", true);
public static final List<HypervisorType> VM_STORAGE_MIGRATION_SUPPORTING_HYPERVISORS = new ArrayList<>(Arrays.asList(
HypervisorType.KVM,
HypervisorType.VMware,
HypervisorType.XenServer,
HypervisorType.Simulator
));
protected static final List<HypervisorType> ROOT_DISK_SIZE_OVERRIDE_SUPPORTING_HYPERVISORS = Arrays.asList(
HypervisorType.KVM,
HypervisorType.XenServer,
HypervisorType.VMware,
HypervisorType.Simulator,
HypervisorType.Custom
);
private static final List<HypervisorType> HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS = Arrays.asList(HypervisorType.KVM, HypervisorType.VMware);
@Override
public UserVmVO getVirtualMachine(long vmId) {
return _vmDao.findById(vmId);
@ -4563,7 +4547,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
* @throws InvalidParameterValueException if the hypervisor does not support rootdisksize override
*/
protected void verifyIfHypervisorSupportsRootdiskSizeOverride(HypervisorType hypervisorType) {
if (!ROOT_DISK_SIZE_OVERRIDE_SUPPORTING_HYPERVISORS.contains(hypervisorType)) {
if (!hypervisorType.isFunctionalitySupported(Functionality.RootDiskSizeOverride)) {
throw new InvalidParameterValueException("Hypervisor " + hypervisorType + " does not support rootdisksize override");
}
}
@ -6606,9 +6590,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
HypervisorType hypervisorType = vm.getHypervisorType();
if (vm.getType() != VirtualMachine.Type.User && !HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS.contains(hypervisorType)) {
throw new InvalidParameterValueException(String.format("Unable to migrate storage of non-user VMs for hypervisor [%s]. Operation only supported for the following"
+ " hypervisors: [%s].", hypervisorType, HYPERVISORS_THAT_CAN_DO_STORAGE_MIGRATION_ON_NON_USER_VMS));
List<HypervisorType> supportedHypervisorsForNonUserVMStorageMigration = HypervisorType.getListOfHypervisorsSupportingFunctionality(Functionality.VmStorageMigration)
.stream().filter(hypervisor -> !hypervisor.equals(HypervisorType.XenServer)).collect(Collectors.toList());
if (vm.getType() != VirtualMachine.Type.User && !supportedHypervisorsForNonUserVMStorageMigration.contains(hypervisorType)) {
throw new InvalidParameterValueException(String.format(
"Unable to migrate storage of non-user VMs for hypervisor [%s]. Operation only supported for the following hypervisors: [%s].",
hypervisorType, supportedHypervisorsForNonUserVMStorageMigration));
}
List<VolumeVO> vols = _volsDao.findByInstance(vm.getId());
@ -7318,8 +7305,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
}
if (!VM_STORAGE_MIGRATION_SUPPORTING_HYPERVISORS.contains(vm.getHypervisorType())) {
throw new InvalidParameterValueException(String.format("Unsupported hypervisor: %s for VM migration, we support XenServer/VMware/KVM only", vm.getHypervisorType()));
if (!vm.getHypervisorType().isFunctionalitySupported(Functionality.VmStorageMigration)) {
throw new InvalidParameterValueException(
String.format("Unsupported hypervisor: %s for VM migration, we support [%s] only",
vm.getHypervisorType(),
HypervisorType.getListOfHypervisorsSupportingFunctionality(Functionality.VmStorageMigration)));
}
if (_vmSnapshotDao.findByVm(vmId).size() > 0) {

View File

@ -635,7 +635,7 @@ public class UserVmManagerImplTest {
int expectedExceptionCounter = hypervisorTypeArray.length - 5;
for(int i = 0; i < hypervisorTypeArray.length; i++) {
if (UserVmManagerImpl.ROOT_DISK_SIZE_OVERRIDE_SUPPORTING_HYPERVISORS.contains(hypervisorTypeArray[i])) {
if (hypervisorTypeArray[i].isFunctionalitySupported(Hypervisor.HypervisorType.Functionality.RootDiskSizeOverride)) {
userVmManagerImpl.verifyIfHypervisorSupportsRootdiskSizeOverride(hypervisorTypeArray[i]);
} else {
try {