From 0ebe79cfea1fcbaff03cce2a8411ccf1710fab1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Jandre?= <48719461+JoaoJandre@users.noreply.github.com> Date: Tue, 20 May 2025 08:20:32 -0300 Subject: [PATCH 1/2] check version before using --bitmaps --- .../apache/cloudstack/utils/qemu/QemuImg.java | 5 +++- .../formatinspector/Qcow2Inspector.java | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/qemu/QemuImg.java b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/qemu/QemuImg.java index 751a16a15541..608ad3c69cba 100644 --- a/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/qemu/QemuImg.java +++ b/plugins/hypervisors/kvm/src/main/java/org/apache/cloudstack/utils/qemu/QemuImg.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.regex.Pattern; +import org.apache.cloudstack.storage.formatinspector.Qcow2Inspector; import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang3.StringUtils; import org.libvirt.LibvirtException; @@ -53,6 +54,8 @@ public class QemuImg { public static final long QEMU_2_10 = 2010000; public static final long QEMU_5_10 = 5010000; + public static final int MIN_BITMAP_VERSION = 3; + /* The qemu-img binary. We expect this to be in $PATH */ public String _qemuImgPath = "qemu-img"; private String cloudQemuImgPath = "cloud-qemu-img"; @@ -466,7 +469,7 @@ public void convert(final QemuImgFile srcFile, final QemuImgFile destFile, script.add(srcFile.getFileName()); } - if (this.version >= QEMU_5_10 && keepBitmaps) { + if (this.version >= QEMU_5_10 && keepBitmaps && Qcow2Inspector.validateQcow2Version(srcFile.getFileName(), MIN_BITMAP_VERSION)) { script.add("--bitmaps"); } diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java index 9d80064d292e..b636a3255dcd 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java @@ -25,6 +25,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.math.BigInteger; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -108,6 +109,32 @@ public static Map unravelQcow2Header(InputStream qcow2InputStrea return result; } + + /** + * Validates if the file has a minimum version. + * @param filePath Path of the file to be validated. + * @param minVersion the minimum version that it should contain. + * @throws RuntimeException If a IOException is thrown. + * @return true if file version is >= minVersion, false otherwise. + */ + public static boolean validateQcow2Version(String filePath, int minVersion) { + try (InputStream inputStream = new FileInputStream(filePath)) { + for (Qcow2HeaderField qcow2Header : Qcow2HeaderField.values()) { + if (qcow2Header != Qcow2HeaderField.VERSION) { + skipHeader(inputStream, qcow2Header, filePath); + continue; + } + + byte[] headerValue = readHeader(inputStream, qcow2Header, filePath); + int version = new BigInteger(headerValue).intValue(); + return version >= minVersion; + } + } catch (IOException ex) { + throw new RuntimeException(String.format("Unable to validate file [%s] due to: ", filePath), ex); + } + return false; + } + /** * Skips the field's length in the InputStream. * @param qcow2InputStream InputStream of the QCOW2 being unraveled. From ca34e88354de080113bbfb4c380ef8cf606ee28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Jandre?= <48719461+JoaoJandre@users.noreply.github.com> Date: Tue, 20 May 2025 11:59:42 -0300 Subject: [PATCH 2/2] use cloudruntimeexception --- .../cloudstack/storage/formatinspector/Qcow2Inspector.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java index b636a3255dcd..bc06d7490787 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/formatinspector/Qcow2Inspector.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.storage.formatinspector; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.commons.lang3.ArrayUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -130,7 +131,7 @@ public static boolean validateQcow2Version(String filePath, int minVersion) { return version >= minVersion; } } catch (IOException ex) { - throw new RuntimeException(String.format("Unable to validate file [%s] due to: ", filePath), ex); + throw new CloudRuntimeException(String.format("Unable to validate file [%s] due to: ", filePath), ex); } return false; }