diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index e70acee229df..988e812d9c6d 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -213,8 +213,9 @@ hypervisor.type=kvm # If null (default), defaults to the VM's OS architecture #guest.cpu.arch= -# This param will require CPU features on the CPU section. -# The features listed in this property must be separated by a blank space (e.g.: vmx vme) +# Specifies required CPU features for end-user and system VMs. +# These features must be present on the host CPU for VM deployment. +# Multiple features should be separated by whitespace (e.g.: vmx vme). #guest.cpu.features= # Disables memory ballooning on VM guests for overcommit. diff --git a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java index 695376216732..7392b54828e5 100644 --- a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java +++ b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java @@ -390,8 +390,9 @@ public class AgentProperties{ public static final Property GUEST_CPU_ARCH = new Property<>("guest.cpu.arch", null, String.class); /** - * This param will require CPU features on the CPU section.
- * The features listed in this property must be separated by a blank space (see example below).
+ * Specifies required CPU features for end-user and system VMs.
+ * These features must be present on the host CPU for VM deployment.
+ * Multiple features should be separated by whitespace (see example below).
* Possible values: vmx vme
* Data type: String.
* Default value: null diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index a632fd5adfd2..90b1738b4e5c 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -1283,15 +1283,7 @@ public boolean configure(final String name, final Map params) th params.put("guest.cpu.model", guestCpuModel); } - final String cpuFeatures = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.GUEST_CPU_FEATURES); - if (cpuFeatures != null) { - this.cpuFeatures = new ArrayList(); - for (final String feature: cpuFeatures.split(" ")) { - if (!feature.isEmpty()) { - this.cpuFeatures.add(feature); - } - } - } + this.cpuFeatures = parseCpuFeatures(AgentPropertiesFileHandler.getPropertyValue(AgentProperties.GUEST_CPU_FEATURES)); final String[] info = NetUtils.getNetworkParams(privateNic); @@ -1397,6 +1389,22 @@ public boolean configure(final String name, final Map params) th return true; } + /** + * Parses a string containing whitespace-separated CPU feature names and converts it into a list. + * + * @param features A string containing whitespace-separated CPU feature names to be parsed. + * @return A list of CPU feature strings. Returns an empty list if {@code features} is null. + */ + protected List parseCpuFeatures(String features) { + if (features == null) { + return new ArrayList<>(); + } + + return Arrays.stream(features.split(" ")) + .filter(feature -> !feature.isEmpty()) + .collect(Collectors.toList()); + } + /** * Gets the ID list of the VMs to set memory balloon stats period. * @param conn the Libvirt connection. @@ -2984,9 +2992,7 @@ private CpuModeDef createCpuModeDef(VirtualMachineTO vmTO, int vcpus) { String cpuModel = MapUtils.isNotEmpty(details) && details.get(VmDetailConstants.GUEST_CPU_MODEL) != null ? details.get(VmDetailConstants.GUEST_CPU_MODEL) : guestCpuModel; cmd.setMode(cpuMode); cmd.setModel(cpuModel); - if (VirtualMachine.Type.User.equals(vmTO.getType())) { - cmd.setFeatures(cpuFeatures); - } + cmd.setFeatures(cpuFeatures); int vCpusInDef = vmTO.getVcpuMaxLimit() == null ? vcpus : vmTO.getVcpuMaxLimit(); setCpuTopology(cmd, vCpusInDef, vmTO.getDetails()); return cmd; diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java index 35c5a3bea930..0831c6d1259c 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java @@ -6620,4 +6620,20 @@ public void recreateCheckpointsOnVmTestVolumesHaveCheckpoints() { Mockito.verify(libvirtComputingResourceSpy, Mockito.times(1)).recreateCheckpointsOfDisk(Mockito.any(), Mockito.any(), Mockito.any()); Assert.assertTrue(result); } + + @Test + public void parseCpuFeaturesTestReturnEmptyListWhenFeaturesIsNull() { + List cpuFeatures = libvirtComputingResourceSpy.parseCpuFeatures(null); + Assert.assertEquals(0, cpuFeatures.size()); + } + + @Test + public void parseCpuFeaturesTestReturnListOfCpuFeaturesAndIgnoreMultipleWhitespacesAlongsideEachOther() { + List cpuFeatures = libvirtComputingResourceSpy.parseCpuFeatures(" -mca mce -mmx hle "); + Assert.assertEquals(4, cpuFeatures.size()); + Assert.assertEquals("-mca", cpuFeatures.get(0)); + Assert.assertEquals("mce", cpuFeatures.get(1)); + Assert.assertEquals("-mmx", cpuFeatures.get(2)); + Assert.assertEquals("hle", cpuFeatures.get(3)); + } }