diff --git a/api/src/main/java/com/cloud/hypervisor/Hypervisor.java b/api/src/main/java/com/cloud/hypervisor/Hypervisor.java index e1108b34a83..27ffef1c370 100644 --- a/api/src/main/java/com/cloud/hypervisor/Hypervisor.java +++ b/api/src/main/java/com/cloud/hypervisor/Hypervisor.java @@ -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 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 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 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 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); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java index a7826dedcd0..1f968b869b9 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java @@ -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)); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 219feeef5a9..04b64dd80a3 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -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 VmDestroyForcestop = new ConfigKey("Advanced", Boolean.class, "vm.destroy.forcestop", "false", "On destroy, force-stop takes this value ", true); - public static final List VM_STORAGE_MIGRATION_SUPPORTING_HYPERVISORS = new ArrayList<>(Arrays.asList( - HypervisorType.KVM, - HypervisorType.VMware, - HypervisorType.XenServer, - HypervisorType.Simulator - )); - - protected static final List ROOT_DISK_SIZE_OVERRIDE_SUPPORTING_HYPERVISORS = Arrays.asList( - HypervisorType.KVM, - HypervisorType.XenServer, - HypervisorType.VMware, - HypervisorType.Simulator, - HypervisorType.Custom - ); - - private static final List 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 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 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) { diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java index 8316c57d67d..d49dcd0f00c 100644 --- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java +++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java @@ -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 {