Skip to content

Commit de14141

Browse files
shwstpprslavkapweizhouapachenvazquez
authored
el8 fixes backport (apache#155)
* Extract the IO_URING configuration into the agent.properties (apache#6253) When using advanced virtualization the IO Driver is not supported. The admin will decide if want to enable/disable this configuration from agent.properties file. The default value is true * kvm: truncate vnc password to 8 chars (apache#6244) This PR truncates the vnc password of kvm vms to 8 chars to support latest versions of libvirt. * merge fix Signed-off-by: Abhishek Kumar <[email protected]> * [KVM] Enable IOURING only when it is available on the host (apache#6399) * [KVM] Disable IOURING by default on agents * Refactor * Remove agent property for iouring * Restore property * Refactor suse check and enable on ubuntu by default * Refactor irrespective of guest OS * Improvement * Logs and new path * Refactor condition to enable iouring * Improve condition * Refactor property check * Improvement * Doc comment * Extend comment * Move method * Add log * [KVM] Fix VM migration error due to VNC password on libvirt limiting versions (apache#6404) * [KVM] Fix VM migration error due to VNC password on libvirt limiting versions * Fix passwd value * Simplify implementation Co-authored-by: slavkap <[email protected]> Co-authored-by: Wei Zhou <[email protected]> Co-authored-by: Nicolas Vazquez <[email protected]>
1 parent c39cf4c commit de14141

File tree

6 files changed

+98
-17
lines changed

6 files changed

+98
-17
lines changed

agent/conf/agent.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,6 @@ iscsi.session.cleanup.enabled=false
288288

289289
# Manually set the host CPU MHz, in cases where CPU scaling support detected value is wrong
290290
# host.cpu.manual.speed.mhz=0
291+
292+
# Enable/disable IO driver for Qemu (in case it is not set CloudStack can also detect if its supported by qemu)
293+
# enable.io.uring=true

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
313313

314314
public final static String HOST_CACHE_PATH_PARAMETER = "host.cache.location";
315315
public final static String CONFIG_DIR = "config";
316+
private boolean enableIoUring;
317+
private final static String ENABLE_IO_URING_PROPERTY = "enable.io.uring";
316318

317319
public static final String BASH_SCRIPT_PATH = "/bin/bash";
318320

@@ -1138,6 +1140,12 @@ public boolean configure(final String name, final Map<String, Object> params) th
11381140
s_logger.trace("Ignoring libvirt error.", e);
11391141
}
11401142

1143+
// Enable/disable IO driver for Qemu (in case it is not set CloudStack can also detect if its supported by qemu)
1144+
// Do not remove - switching it to AgentProperties.Property may require accepting null values for the properties default value
1145+
String enableIoUringConfig = (String) params.get(ENABLE_IO_URING_PROPERTY);
1146+
enableIoUring = isIoUringEnabled(enableIoUringConfig);
1147+
s_logger.info("IO uring driver for Qemu: " + (enableIoUring ? "enabled" : "disabled"));
1148+
11411149
final String cpuArchOverride = (String)params.get("guest.cpu.arch");
11421150
if (!Strings.isNullOrEmpty(cpuArchOverride)) {
11431151
_guestCpuArch = cpuArchOverride;
@@ -2972,18 +2980,68 @@ private KVMPhysicalDisk getPhysicalDiskPrimaryStore(PrimaryDataStoreTO primaryDa
29722980
return storagePool.getPhysicalDisk(data.getPath());
29732981
}
29742982

2983+
/**
2984+
* Check if IO_URING is supported by qemu
2985+
*/
2986+
protected boolean isIoUringSupportedByQemu() {
2987+
s_logger.debug("Checking if iouring is supported");
2988+
String command = getIoUringCheckCommand();
2989+
if (org.apache.commons.lang3.StringUtils.isBlank(command)) {
2990+
s_logger.debug("Could not check iouring support, disabling it");
2991+
return false;
2992+
}
2993+
int exitValue = executeBashScriptAndRetrieveExitValue(command);
2994+
return exitValue == 0;
2995+
}
2996+
2997+
protected String getIoUringCheckCommand() {
2998+
String[] qemuPaths = { "/usr/bin/qemu-system-x86_64", "/usr/libexec/qemu-kvm", "/usr/bin/qemu-kvm" };
2999+
for (String qemuPath : qemuPaths) {
3000+
File file = new File(qemuPath);
3001+
if (file.exists()) {
3002+
String cmd = String.format("ldd %s | grep -Eqe '[[:space:]]liburing\\.so'", qemuPath);
3003+
s_logger.debug("Using the check command: " + cmd);
3004+
return cmd;
3005+
}
3006+
}
3007+
return null;
3008+
}
3009+
29753010
/**
29763011
* Set Disk IO Driver, if supported by the Libvirt/Qemu version.
29773012
* IO Driver works for:
29783013
* (i) Qemu >= 5.0;
29793014
* (ii) Libvirt >= 6.3.0
29803015
*/
29813016
protected void setDiskIoDriver(DiskDef disk) {
2982-
if (getHypervisorLibvirtVersion() >= HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IO_URING && getHypervisorQemuVersion() >= HYPERVISOR_QEMU_VERSION_SUPPORTS_IO_URING) {
3017+
if (enableIoUring) {
29833018
disk.setIoDriver(DiskDef.IoDriver.IOURING);
29843019
}
29853020
}
29863021

3022+
/**
3023+
* IO_URING supported if the property 'enable.io.uring' is set to true OR it is supported by qemu
3024+
*/
3025+
private boolean isIoUringEnabled(String enableIoUringConfig) {
3026+
boolean meetRequirements = getHypervisorLibvirtVersion() >= HYPERVISOR_LIBVIRT_VERSION_SUPPORTS_IO_URING
3027+
&& getHypervisorQemuVersion() >= HYPERVISOR_QEMU_VERSION_SUPPORTS_IO_URING;
3028+
if (!meetRequirements) {
3029+
return false;
3030+
}
3031+
return enableIoUringConfig != null ?
3032+
Boolean.parseBoolean(enableIoUringConfig):
3033+
(isBaseOsUbuntu() || isIoUringSupportedByQemu());
3034+
}
3035+
3036+
private boolean isBaseOsUbuntu() {
3037+
Map<String, String> versionString = getVersionStrings();
3038+
String hostKey = "Host.OS";
3039+
if (MapUtils.isEmpty(versionString) || !versionString.containsKey(hostKey) || versionString.get(hostKey) == null) {
3040+
return false;
3041+
}
3042+
return versionString.get(hostKey).equalsIgnoreCase("ubuntu");
3043+
}
3044+
29873045
private KVMPhysicalDisk getPhysicalDiskFromNfsStore(String dataStoreUrl, DataTO data) {
29883046
final String volPath = dataStoreUrl + File.separator + data.getPath();
29893047
final int index = volPath.lastIndexOf("/");
@@ -3847,10 +3905,20 @@ public List<DiskDef> getDisks(final Connect conn, final String vmName) {
38473905
}
38483906

38493907
private String executeBashScript(final String script) {
3908+
return createScript(script).execute();
3909+
}
3910+
3911+
private Script createScript(final String script) {
38503912
final Script command = new Script("/bin/bash", _timeout, s_logger);
38513913
command.add("-c");
38523914
command.add(script);
3853-
return command.execute();
3915+
return command;
3916+
}
3917+
3918+
private int executeBashScriptAndRetrieveExitValue(final String script) {
3919+
Script command = createScript(script);
3920+
command.execute();
3921+
return command.getExitValue();
38543922
}
38553923

38563924
public List<VmNetworkStatsEntry> getVmNetworkStat(Connect conn, String vmName) throws LibvirtException {

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import java.util.Map;
2424

2525
import org.apache.commons.lang.StringEscapeUtils;
26-
import org.apache.commons.lang.StringUtils;
26+
import org.apache.commons.lang3.StringUtils;
2727
import org.apache.log4j.Logger;
2828

2929
public class LibvirtVMDef {
@@ -1764,7 +1764,7 @@ public String toString() {
17641764
graphicBuilder.append(" listen=''");
17651765
}
17661766
if (_passwd != null) {
1767-
graphicBuilder.append(" passwd='" + _passwd + "'");
1767+
graphicBuilder.append(" passwd='" + StringUtils.truncate(_passwd, 8) + "'");
17681768
} else if (_keyMap != null) {
17691769
graphicBuilder.append(" _keymap='" + _keyMap + "'");
17701770
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,11 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
149149

150150
final String target = command.getDestinationIp();
151151
xmlDesc = dm.getXMLDesc(xmlFlag);
152-
xmlDesc = replaceIpForVNCInDescFile(xmlDesc, target);
152+
153+
// Limit the VNC password in case the length is greater than 8 characters
154+
// Since libvirt version 8 VNC passwords are limited to 8 characters
155+
String vncPassword = org.apache.commons.lang3.StringUtils.truncate(to.getVncPassword(), 8);
156+
xmlDesc = replaceIpForVNCInDescFileAndNormalizePassword(xmlDesc, target, vncPassword);
153157

154158
String oldIsoVolumePath = getOldVolumePath(disks, vmName);
155159
String newIsoVolumePath = getNewVolumePathIfDatastoreHasChanged(libvirtComputingResource, conn, to);
@@ -450,16 +454,20 @@ protected MigrateDiskInfo searchDiskDefOnMigrateDiskInfoList(List<MigrateDiskInf
450454
* </graphics>
451455
* @param xmlDesc the qemu xml description
452456
* @param target the ip address to migrate to
457+
* @param vncPassword if set, the VNC password truncated to 8 characters
453458
* @return the new xmlDesc
454459
*/
455-
String replaceIpForVNCInDescFile(String xmlDesc, final String target) {
460+
String replaceIpForVNCInDescFileAndNormalizePassword(String xmlDesc, final String target, String vncPassword) {
456461
final int begin = xmlDesc.indexOf(GRAPHICS_ELEM_START);
457462
if (begin >= 0) {
458463
final int end = xmlDesc.lastIndexOf(GRAPHICS_ELEM_END) + GRAPHICS_ELEM_END.length();
459464
if (end > begin) {
460465
String graphElem = xmlDesc.substring(begin, end);
461466
graphElem = graphElem.replaceAll("listen='[a-zA-Z0-9\\.]*'", "listen='" + target + "'");
462467
graphElem = graphElem.replaceAll("address='[a-zA-Z0-9\\.]*'", "address='" + target + "'");
468+
if (org.apache.commons.lang3.StringUtils.isNotBlank(vncPassword)) {
469+
graphElem = graphElem.replaceAll("passwd='([^\\s]+)'", "passwd='" + vncPassword + "'");
470+
}
463471
xmlDesc = xmlDesc.replaceAll(GRAPHICS_ELEM_START + CONTENTS_WILDCARD + GRAPHICS_ELEM_END, graphElem);
464472
}
465473
}

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import org.apache.cloudstack.utils.linux.MemStat;
6161
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
6262
import org.apache.commons.lang.SystemUtils;
63+
import org.apache.commons.lang3.StringUtils;
6364
import org.joda.time.Duration;
6465
import org.junit.Assert;
6566
import org.junit.Before;
@@ -773,7 +774,7 @@ private void verifyGraphicsDevices(VirtualMachineTO to, Document domainDoc, Stri
773774
assertXpath(domainDoc, prefix + "/graphics/@type", "vnc");
774775
assertXpath(domainDoc, prefix + "/graphics/@listen", to.getVncAddr());
775776
assertXpath(domainDoc, prefix + "/graphics/@autoport", "yes");
776-
assertXpath(domainDoc, prefix + "/graphics/@passwd", to.getVncPassword());
777+
assertXpath(domainDoc, prefix + "/graphics/@passwd", StringUtils.truncate(to.getVncPassword(), 8));
777778
}
778779

779780
private void verifySerialDevices(Document domainDoc, String prefix) {

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -571,53 +571,55 @@ public void setup() throws Exception {
571571
@Test
572572
public void testReplaceIpForVNCInDescFile() {
573573
final String targetIp = "192.168.22.21";
574-
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFile(fullfile, targetIp);
574+
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(fullfile, targetIp, null);
575575
assertTrue("transformation does not live up to expectation:\n" + result, targetfile.equals(result));
576576
}
577577

578578
@Test
579-
public void testReplaceIpForVNCInDesc() {
579+
public void testReplaceIpAndPasswordForVNCInDesc() {
580580
final String xmlDesc =
581581
"<domain type='kvm' id='3'>" +
582582
" <devices>" +
583-
" <graphics type='vnc' port='5900' autoport='yes' listen='10.10.10.1'>" +
583+
" <graphics type='vnc' port='5900' autoport='yes' listen='10.10.10.1' passwd='123456789012345'>" +
584584
" <listen type='address' address='10.10.10.1'/>" +
585585
" </graphics>" +
586586
" </devices>" +
587587
"</domain>";
588588
final String expectedXmlDesc =
589589
"<domain type='kvm' id='3'>" +
590590
" <devices>" +
591-
" <graphics type='vnc' port='5900' autoport='yes' listen='10.10.10.10'>" +
591+
" <graphics type='vnc' port='5900' autoport='yes' listen='10.10.10.10' passwd='12345678'>" +
592592
" <listen type='address' address='10.10.10.10'/>" +
593593
" </graphics>" +
594594
" </devices>" +
595595
"</domain>";
596596
final String targetIp = "10.10.10.10";
597-
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFile(xmlDesc, targetIp);
597+
final String password = "12345678";
598+
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(xmlDesc, targetIp, password);
598599
assertTrue("transformation does not live up to expectation:\n" + result, expectedXmlDesc.equals(result));
599600
}
600601

601602
@Test
602-
public void testReplaceFqdnForVNCInDesc() {
603+
public void testReplaceFqdnAndPasswordForVNCInDesc() {
603604
final String xmlDesc =
604605
"<domain type='kvm' id='3'>" +
605606
" <devices>" +
606-
" <graphics type='vnc' port='5900' autoport='yes' listen='localhost.local'>" +
607+
" <graphics type='vnc' port='5900' autoport='yes' listen='localhost.local' passwd='123456789012345'>" +
607608
" <listen type='address' address='localhost.local'/>" +
608609
" </graphics>" +
609610
" </devices>" +
610611
"</domain>";
611612
final String expectedXmlDesc =
612613
"<domain type='kvm' id='3'>" +
613614
" <devices>" +
614-
" <graphics type='vnc' port='5900' autoport='yes' listen='localhost.localdomain'>" +
615+
" <graphics type='vnc' port='5900' autoport='yes' listen='localhost.localdomain' passwd='12345678'>" +
615616
" <listen type='address' address='localhost.localdomain'/>" +
616617
" </graphics>" +
617618
" </devices>" +
618619
"</domain>";
619620
final String targetIp = "localhost.localdomain";
620-
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFile(xmlDesc, targetIp);
621+
final String password = "12345678";
622+
final String result = libvirtMigrateCmdWrapper.replaceIpForVNCInDescFileAndNormalizePassword(xmlDesc, targetIp, password);
621623
assertTrue("transformation does not live up to expectation:\n" + result, expectedXmlDesc.equals(result));
622624
}
623625

@@ -789,5 +791,4 @@ public void testReplaceDPDKPorts() throws ParserConfigurationException, IOExcept
789791
Assert.assertTrue(replaced.contains("csdpdk-7"));
790792
Assert.assertFalse(replaced.contains("csdpdk-1"));
791793
}
792-
793794
}

0 commit comments

Comments
 (0)