This is an automated email from the ASF dual-hosted git repository. sureshanaparti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push: new 5ea1ada59a4 Allow full clone volumes with thin provisioning in KVM (#11177) 5ea1ada59a4 is described below commit 5ea1ada59a43bccc699f09efb3a7a89df1562017 Author: João Jandre <48719461+joaojan...@users.noreply.github.com> AuthorDate: Thu Jul 31 07:42:17 2025 -0300 Allow full clone volumes with thin provisioning in KVM (#11177) It adds a configuration called create.full.clone to the agent.properties file. When set to true, all QCOW2 volumes created will be full-clone. If false (default), the current behavior remains, where only FAT and SPARSE volumes are full-clone and THIN volumes are linked-clone. --- agent/conf/agent.properties | 3 +++ .../java/com/cloud/agent/properties/AgentProperties.java | 8 ++++++++ .../hypervisor/kvm/storage/LibvirtStorageAdaptor.java | 16 +++++++++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index e70acee229d..cd31b0db56d 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -447,3 +447,6 @@ iscsi.session.cleanup.enabled=false # Timeout (in seconds) to wait for the incremental snapshot to complete. # incremental.snapshot.timeout=10800 + +# If set to true, creates VMs as full clones of their templates on KVM hypervisor. Creates as linked clones otherwise. +# create.full.clone=false 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 47255762a05..847d1bb2396 100644 --- a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java +++ b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java @@ -863,6 +863,14 @@ public class AgentProperties{ * */ public static final Property<Integer> REVERT_SNAPSHOT_TIMEOUT = new Property<>("revert.snapshot.timeout", 10800); + /** + * If set to true, creates VMs as full clones of their templates on KVM hypervisor. Creates as linked clones otherwise. <br> + * Data type: Boolean. <br> + * Default value: <code>false</code> + */ + public static final Property<Boolean> CREATE_FULL_CLONE = new Property<>("create.full.clone", false); + + public static class Property <T>{ private String name; private T defaultValue; diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index 7c66a91876f..bf851831cd0 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -32,6 +32,8 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; +import com.cloud.agent.properties.AgentProperties; +import com.cloud.agent.properties.AgentPropertiesFileHandler; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.utils.cryptsetup.KeyFile; import org.apache.cloudstack.utils.qemu.QemuImageOptions; @@ -1315,14 +1317,22 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { passphraseObjects.add(QemuObject.prepareSecretForQemuImg(format, QemuObject.EncryptFormat.LUKS, keyFile.toString(), "sec0", options)); disk.setQemuEncryptFormat(QemuObject.EncryptFormat.LUKS); } + + QemuImgFile srcFile = new QemuImgFile(template.getPath(), template.getFormat()); + Boolean createFullClone = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.CREATE_FULL_CLONE); switch(provisioningType){ case THIN: - QemuImgFile backingFile = new QemuImgFile(template.getPath(), template.getFormat()); - qemu.create(destFile, backingFile, options, passphraseObjects); + logger.info("Creating volume [{}] {} backing file [{}] as the property [{}] is [{}].", destFile.getFileName(), createFullClone ? "without" : "with", + template.getPath(), AgentProperties.CREATE_FULL_CLONE.getName(), createFullClone); + if (createFullClone) { + qemu.convert(srcFile, destFile, options, passphraseObjects, null, false); + } else { + qemu.create(destFile, srcFile, options, passphraseObjects); + } break; case SPARSE: case FAT: - QemuImgFile srcFile = new QemuImgFile(template.getPath(), template.getFormat()); + srcFile = new QemuImgFile(template.getPath(), template.getFormat()); qemu.convert(srcFile, destFile, options, passphraseObjects, null, false); break; }