This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch 4.19
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.19 by this push:
new d54b105a037 Linstor: add support for ISO block devices and direct
download (#9792)
d54b105a037 is described below
commit d54b105a037e781c45d61718c2d809ddfa3e53cd
Author: Rene Peinthor <[email protected]>
AuthorDate: Thu Nov 28 17:47:47 2024 +0100
Linstor: add support for ISO block devices and direct download (#9792)
---
.../kvm/resource/LibvirtComputingResource.java | 31 +++++++----
.../kvm/resource/LibvirtDomainXMLParser.java | 24 +++++++--
.../hypervisor/kvm/resource/LibvirtVMDef.java | 24 ++++-----
.../kvm/storage/KVMStorageProcessor.java | 5 +-
.../kvm/storage/LibvirtStorageAdaptor.java | 6 +--
plugins/storage/volume/linstor/CHANGELOG.md | 6 +++
.../kvm/storage/LinstorStorageAdaptor.java | 60 ++++++++++++++++++----
7 files changed, 118 insertions(+), 38 deletions(-)
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 43923059d91..a4d7bd524ad 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
@@ -2983,6 +2983,17 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
return dataPath;
}
+ public static boolean useBLOCKDiskType(KVMPhysicalDisk physicalDisk) {
+ return physicalDisk != null &&
+ physicalDisk.getPool().getType() == StoragePoolType.Linstor &&
+ physicalDisk.getFormat() != null &&
+ physicalDisk.getFormat()== PhysicalDiskFormat.RAW;
+ }
+
+ public static DiskDef.DiskType getDiskType(KVMPhysicalDisk physicalDisk) {
+ return useBLOCKDiskType(physicalDisk) ? DiskDef.DiskType.BLOCK :
DiskDef.DiskType.FILE;
+ }
+
public void createVbd(final Connect conn, final VirtualMachineTO vmSpec,
final String vmName, final LibvirtVMDef vm) throws InternalErrorException,
LibvirtException, URISyntaxException {
final Map<String, String> details = vmSpec.getDetails();
final List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
@@ -3028,7 +3039,8 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
physicalDisk =
getPhysicalDiskFromNfsStore(dataStoreUrl, data);
} else if
(primaryDataStoreTO.getPoolType().equals(StoragePoolType.SharedMountPoint) ||
primaryDataStoreTO.getPoolType().equals(StoragePoolType.Filesystem) ||
-
primaryDataStoreTO.getPoolType().equals(StoragePoolType.StorPool)) {
+
primaryDataStoreTO.getPoolType().equals(StoragePoolType.StorPool) ||
+
primaryDataStoreTO.getPoolType().equals(StoragePoolType.Linstor)) {
physicalDisk =
getPhysicalDiskPrimaryStore(primaryDataStoreTO, data);
}
}
@@ -3078,8 +3090,8 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
final DiskDef disk = new DiskDef();
int devId = volume.getDiskSeq().intValue();
if (volume.getType() == Volume.Type.ISO) {
-
- disk.defISODisk(volPath, devId, isUefiEnabled);
+ final DiskDef.DiskType diskType = getDiskType(physicalDisk);
+ disk.defISODisk(volPath, devId, isUefiEnabled, diskType);
if (guestCpuArch != null && guestCpuArch.equals("aarch64")) {
disk.setBusType(DiskDef.DiskBus.SCSI);
@@ -3171,7 +3183,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
if (vmSpec.getType() != VirtualMachine.Type.User) {
final DiskDef iso = new DiskDef();
- iso.defISODisk(sysvmISOPath);
+ iso.defISODisk(sysvmISOPath, DiskDef.DiskType.FILE);
if (guestCpuArch != null && guestCpuArch.equals("aarch64")) {
iso.setBusType(DiskDef.DiskBus.SCSI);
}
@@ -3384,7 +3396,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
List<DiskDef> disks = getDisks(conn, vmName);
DiskDef configdrive = null;
for (DiskDef disk : disks) {
- if (disk.getDeviceType() == DiskDef.DeviceType.CDROM &&
disk.getDiskLabel() == CONFIG_DRIVE_ISO_DISK_LABEL) {
+ if (disk.getDeviceType() == DiskDef.DeviceType.CDROM &&
CONFIG_DRIVE_ISO_DISK_LABEL.equals(disk.getDiskLabel())) {
configdrive = disk;
}
}
@@ -3414,11 +3426,12 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
final String name = isoPath.substring(index + 1);
final KVMStoragePool secondaryPool =
storagePoolManager.getStoragePoolByURI(path);
final KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
+ final DiskDef.DiskType diskType = getDiskType(isoVol);
isoPath = isoVol.getPath();
- iso.defISODisk(isoPath, diskSeq);
+ iso.defISODisk(isoPath, diskSeq, diskType);
} else {
- iso.defISODisk(null, diskSeq);
+ iso.defISODisk(null, diskSeq, DiskDef.DiskType.FILE);
}
final String result = attachOrDetachDevice(conn, true, vmName,
iso.toString());
@@ -3426,7 +3439,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
final List<DiskDef> disks = getDisks(conn, vmName);
for (final DiskDef disk : disks) {
if (disk.getDeviceType() == DiskDef.DeviceType.CDROM
- && (diskSeq == null || disk.getDiskLabel() ==
iso.getDiskLabel())) {
+ && (diskSeq == null ||
disk.getDiskLabel().equals(iso.getDiskLabel()))) {
cleanupDisk(disk);
}
}
@@ -4002,7 +4015,7 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
return stopVMInternal(conn, vmName, true);
}
String ret = stopVMInternal(conn, vmName, false);
- if (ret == Script.ERR_TIMEOUT) {
+ if (Script.ERR_TIMEOUT.equals(ret)) {
ret = stopVMInternal(conn, vmName, true);
} else if (ret != null) {
/*
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
index a0dd270f999..4cd7fbf3b39 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
@@ -126,11 +126,10 @@ public class LibvirtDomainXMLParser {
}
def.defFileBasedDisk(diskFile, diskLabel,
DiskDef.DiskBus.valueOf(bus.toUpperCase()), fmt);
} else if (device.equalsIgnoreCase("cdrom")) {
- def.defISODisk(diskFile, i+1, diskLabel);
+ def.defISODisk(diskFile, i+1, diskLabel,
DiskDef.DiskType.FILE);
}
} else if (type.equalsIgnoreCase("block")) {
- def.defBlockBasedDisk(diskDev, diskLabel,
- DiskDef.DiskBus.valueOf(bus.toUpperCase()));
+ parseDiskBlock(def, device, diskDev, diskLabel, bus,
diskFile, i);
}
if (StringUtils.isNotBlank(diskCacheMode)) {
def.setCacheMode(DiskDef.DiskCacheMode.valueOf(diskCacheMode.toUpperCase()));
@@ -449,6 +448,25 @@ public class LibvirtDomainXMLParser {
return node.getAttribute(attr);
}
+ /**
+ * Parse the disk block part of the libvirt XML.
+ * @param def
+ * @param device
+ * @param diskDev
+ * @param diskLabel
+ * @param bus
+ * @param diskFile
+ * @param curDiskIndex
+ */
+ private void parseDiskBlock(DiskDef def, String device, String diskDev,
String diskLabel, String bus,
+ String diskFile, int curDiskIndex) {
+ if (device.equalsIgnoreCase("disk")) {
+ def.defBlockBasedDisk(diskDev, diskLabel,
DiskDef.DiskBus.valueOf(bus.toUpperCase()));
+ } else if (device.equalsIgnoreCase("cdrom")) {
+ def.defISODisk(diskFile, curDiskIndex+1, diskLabel,
DiskDef.DiskType.BLOCK);
+ }
+ }
+
public Integer getVncPort() {
return vncPort;
}
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index cfd72c28b5a..ec940942082 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -833,8 +833,8 @@ public class LibvirtVMDef {
}
}
- public void defISODisk(String volPath) {
- _diskType = DiskType.FILE;
+ public void defISODisk(String volPath, DiskType diskType) {
+ _diskType = diskType;
_deviceType = DeviceType.CDROM;
_sourcePath = volPath;
_diskLabel = getDevLabel(3, DiskBus.IDE, true);
@@ -843,8 +843,8 @@ public class LibvirtVMDef {
_bus = DiskBus.IDE;
}
- public void defISODisk(String volPath, boolean isUefiEnabled) {
- _diskType = DiskType.FILE;
+ public void defISODisk(String volPath, boolean isUefiEnabled, DiskType
diskType) {
+ _diskType = diskType;
_deviceType = DeviceType.CDROM;
_sourcePath = volPath;
_bus = isUefiEnabled ? DiskBus.SATA : DiskBus.IDE;
@@ -853,18 +853,18 @@ public class LibvirtVMDef {
_diskCacheMode = DiskCacheMode.NONE;
}
- public void defISODisk(String volPath, Integer devId) {
- defISODisk(volPath, devId, null);
+ public void defISODisk(String volPath, Integer devId, DiskType
diskType) {
+ defISODisk(volPath, devId, null, diskType);
}
- public void defISODisk(String volPath, Integer devId, String
diskLabel) {
+ public void defISODisk(String volPath, Integer devId, String
diskLabel, DiskType diskType) {
if (devId == null && StringUtils.isBlank(diskLabel)) {
s_logger.debug(String.format("No ID or label informed for
volume [%s].", volPath));
- defISODisk(volPath);
+ defISODisk(volPath, diskType);
return;
}
- _diskType = DiskType.FILE;
+ _diskType = diskType;
_deviceType = DeviceType.CDROM;
_sourcePath = volPath;
@@ -881,11 +881,11 @@ public class LibvirtVMDef {
_bus = DiskBus.IDE;
}
- public void defISODisk(String volPath, Integer devId,boolean isSecure)
{
+ public void defISODisk(String volPath, Integer devId, boolean
isSecure, DiskType diskType) {
if (!isSecure) {
- defISODisk(volPath, devId);
+ defISODisk(volPath, devId, diskType);
} else {
- _diskType = DiskType.FILE;
+ _diskType = diskType;
_deviceType = DeviceType.CDROM;
_sourcePath = volPath;
_diskLabel = getDevLabel(devId, DiskBus.SATA, true);
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
index 75443605c31..8cee8434b5e 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -1114,11 +1114,12 @@ public class KVMStorageProcessor implements
StorageProcessor {
storagePool = storagePoolMgr.getStoragePoolByURI(path);
}
final KVMPhysicalDisk isoVol = storagePool.getPhysicalDisk(name);
+ final DiskDef.DiskType isoDiskType =
LibvirtComputingResource.getDiskType(isoVol);
isoPath = isoVol.getPath();
- iso.defISODisk(isoPath, isUefiEnabled);
+ iso.defISODisk(isoPath, isUefiEnabled, isoDiskType);
} else {
- iso.defISODisk(null, isUefiEnabled);
+ iso.defISODisk(null, isUefiEnabled, DiskDef.DiskType.FILE);
}
final List<DiskDef> disks = resource.getDisks(conn, vmName);
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 57a492452e5..11375969b6e 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
@@ -172,7 +172,7 @@ public class LibvirtStorageAdaptor implements
StorageAdaptor {
* Checks if downloaded template is extractable
* @return true if it should be extracted, false if not
*/
- private boolean isTemplateExtractable(String templatePath) {
+ public static boolean isTemplateExtractable(String templatePath) {
String type = Script.runSimpleBashScript("file " + templatePath + " |
awk -F' ' '{print $2}'");
return type.equalsIgnoreCase("bzip2") || type.equalsIgnoreCase("gzip")
|| type.equalsIgnoreCase("zip");
}
@@ -182,7 +182,7 @@ public class LibvirtStorageAdaptor implements
StorageAdaptor {
* @param downloadedTemplateFile
* @param templateUuid
*/
- private String getExtractCommandForDownloadedFile(String
downloadedTemplateFile, String templateUuid) {
+ public static String getExtractCommandForDownloadedFile(String
downloadedTemplateFile, String templateUuid) {
if (downloadedTemplateFile.endsWith(".zip")) {
return "unzip -p " + downloadedTemplateFile + " | cat > " +
templateUuid;
} else if (downloadedTemplateFile.endsWith(".bz2")) {
@@ -197,7 +197,7 @@ public class LibvirtStorageAdaptor implements
StorageAdaptor {
/**
* Extract downloaded template into installPath, remove compressed file
*/
- private void extractDownloadedTemplate(String downloadedTemplateFile,
KVMStoragePool destPool, String destinationFile) {
+ public static void extractDownloadedTemplate(String
downloadedTemplateFile, KVMStoragePool destPool, String destinationFile) {
String extractCommand =
getExtractCommandForDownloadedFile(downloadedTemplateFile, destinationFile);
Script.runSimpleBashScript(extractCommand);
Script.runSimpleBashScript("rm -f " + downloadedTemplateFile);
diff --git a/plugins/storage/volume/linstor/CHANGELOG.md
b/plugins/storage/volume/linstor/CHANGELOG.md
index a0a53d20119..930e139870f 100644
--- a/plugins/storage/volume/linstor/CHANGELOG.md
+++ b/plugins/storage/volume/linstor/CHANGELOG.md
@@ -12,6 +12,12 @@ and this project adheres to [Semantic
Versioning](https://semver.org/spec/v2.0.0
- Disable discard="unmap" for ide devices and qemu < 7.0
https://bugzilla.redhat.com/show_bug.cgi?id=2029980
+## [2024-10-14]
+
+### Added
+
+- Support for ISO direct download to primary storage
+
## [2024-10-04]
### Added
diff --git
a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java
b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java
index bc2a3a42d97..1f71a54a4f3 100644
---
a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java
+++
b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java
@@ -23,11 +23,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.UUID;
import javax.annotation.Nonnull;
import com.cloud.storage.Storage;
import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
import org.apache.cloudstack.utils.qemu.QemuImg;
@@ -56,6 +58,8 @@ import com.linbit.linstor.api.model.StoragePool;
import com.linbit.linstor.api.model.Volume;
import com.linbit.linstor.api.model.VolumeDefinition;
+import java.io.File;
+
@StorageAdaptorInfo(storagePoolType=Storage.StoragePoolType.Linstor)
public class LinstorStorageAdaptor implements StorageAdaptor {
private static final Logger s_logger =
Logger.getLogger(LinstorStorageAdaptor.class);
@@ -563,13 +567,7 @@ public class LinstorStorageAdaptor implements
StorageAdaptor {
name, QemuImg.PhysicalDiskFormat.RAW, provisioningType,
disk.getVirtualSize(), null);
final DevelopersApi api = getLinstorAPI(destPools);
- final String rscName = LinstorUtil.RSC_PREFIX + name;
- try {
- LinstorUtil.applyAuxProps(api, rscName, disk.getDispName(),
disk.getVmName());
- } catch (ApiException apiExc) {
- s_logger.error(String.format("Error setting aux properties for
%s", rscName));
- logLinstorAnswers(apiExc.getApiCallRcList());
- }
+ applyAuxProps(api, name, disk.getDispName(), disk.getVmName());
s_logger.debug(String.format("Linstor.copyPhysicalDisk: dstPath: %s",
dstDisk.getPath()));
final QemuImgFile destFile = new QemuImgFile(dstDisk.getPath());
@@ -620,13 +618,57 @@ public class LinstorStorageAdaptor implements
StorageAdaptor {
return null;
}
+ private void fileExistsOrThrow(String templateFilePath) {
+ File sourceFile = new File(templateFilePath);
+ if (!sourceFile.exists()) {
+ throw new CloudRuntimeException("Direct download template file " +
sourceFile +
+ " does not exist on this host");
+ }
+ }
+
+ private String getFinalDirectDownloadPath(String templateFilePath,
KVMStoragePool destPool) {
+ String finalSourcePath = templateFilePath;
+ if (LibvirtStorageAdaptor.isTemplateExtractable(templateFilePath)) {
+ finalSourcePath = templateFilePath.substring(0,
templateFilePath.lastIndexOf('.'));
+ LibvirtStorageAdaptor.extractDownloadedTemplate(templateFilePath,
destPool, finalSourcePath);
+ }
+ return finalSourcePath;
+ }
+
+ private void applyAuxProps(DevelopersApi api, String csPath, String
csName, String csVMName) {
+ final String rscName = getLinstorRscName(csPath);
+ try {
+ LinstorUtil.applyAuxProps(api, rscName, csName, csVMName);
+ } catch (ApiException apiExc) {
+ s_logger.error(String.format("Error setting aux properties for
%s", rscName));
+ logLinstorAnswers(apiExc.getApiCallRcList());
+ }
+ }
+
@Override
public KVMPhysicalDisk createTemplateFromDirectDownloadFile(String
templateFilePath, String destTemplatePath,
KVMStoragePool
destPool, Storage.ImageFormat format,
int timeout)
{
- s_logger.debug("Linstor: createTemplateFromDirectDownloadFile");
- return null;
+ s_logger.debug(String.format("Linstor:
createTemplateFromDirectDownloadFile: %s/%s", templateFilePath, format));
+ fileExistsOrThrow(templateFilePath);
+ String name = UUID.randomUUID().toString();
+
+ String finalSourcePath = getFinalDirectDownloadPath(templateFilePath,
destPool);
+
+ File finalSourceFile = new File(finalSourcePath);
+ final KVMPhysicalDisk dstDisk = destPool.createPhysicalDisk(
+ name, QemuImg.PhysicalDiskFormat.RAW,
Storage.ProvisioningType.THIN, finalSourceFile.length(), null);
+
+ final DevelopersApi api = getLinstorAPI(destPool);
+ applyAuxProps(api, name, finalSourceFile.getName(), null);
+
+ Script.runSimpleBashScript(
+ String.format("dd if=\"%s\" of=\"%s\" bs=64k
conv=nocreat,sparse oflag=direct",
+ finalSourcePath, dstDisk.getPath()));
+
+ Script.runSimpleBashScript("rm " + finalSourcePath);
+ return dstDisk;
}
public long getCapacity(LinstorStoragePool pool) {