Skip to content

Commit

Permalink
linstor/kvm: add support for ISO block devices and direct download
Browse files Browse the repository at this point in the history
If Linstor storage pool is used, use the BLOCK qemu driver for the
Linstor block device.
  • Loading branch information
rp- committed Oct 21, 2024
1 parent ba39217 commit 8aeaa5c
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2982,6 +2982,17 @@ public String getVolumePath(final Connect conn, final DiskTO volume, boolean dis
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());
Expand Down Expand Up @@ -3027,7 +3038,8 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
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);
}
}
Expand Down Expand Up @@ -3077,8 +3089,8 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {
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);
Expand Down Expand Up @@ -3170,7 +3182,7 @@ public int compare(final DiskTO arg0, final DiskTO arg1) {

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);
}
Expand Down Expand Up @@ -3403,11 +3415,12 @@ public synchronized String attachOrDetachISO(final Connect conn, final String vm
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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,15 @@ public boolean parseDomainXML(String domXML) {
}
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()));
if (device.equalsIgnoreCase("disk")) {
def.defBlockBasedDisk(diskDev, diskLabel,
DiskDef.DiskBus.valueOf(bus.toUpperCase()));
} else if (device.equalsIgnoreCase("cdrom")) {
def.defISODisk(diskFile, i+1, diskLabel, DiskDef.DiskType.BLOCK);
}
}
if (StringUtils.isNotBlank(diskCacheMode)) {
def.setCacheMode(DiskDef.DiskCacheMode.valueOf(diskCacheMode.toUpperCase()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -833,8 +833,8 @@ public void defFileBasedDisk(String filePath, int devId, DiskFmtType diskFmtType
}
}

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);
Expand All @@ -843,8 +843,8 @@ public void defISODisk(String volPath) {
_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;
Expand All @@ -853,18 +853,18 @@ public void defISODisk(String volPath, boolean isUefiEnabled) {
_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;

Expand All @@ -881,11 +881,11 @@ public void defISODisk(String volPath, Integer devId, String diskLabel) {
_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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1112,11 +1112,12 @@ protected synchronized void attachOrDetachISO(final Connect conn, final String v
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public KVMPhysicalDisk createDiskFromTemplateBacking(KVMPhysicalDisk template, S
* 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");
}
Expand All @@ -181,7 +181,7 @@ private boolean isTemplateExtractable(String templatePath) {
* @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")) {
Expand All @@ -196,7 +196,7 @@ private String getExtractCommandForDownloadedFile(String downloadedTemplateFile,
/**
* 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@
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;
import org.apache.cloudstack.utils.qemu.QemuImgException;
Expand All @@ -53,6 +56,8 @@
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);
Expand Down Expand Up @@ -578,8 +583,41 @@ public KVMPhysicalDisk createTemplateFromDirectDownloadFile(String templateFileP
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));
{
File sourceFile = new File(templateFilePath);
if (!sourceFile.exists()) {
throw new CloudRuntimeException("Direct download template file " + sourceFile +
" does not exist on this host");
}
}
String name = UUID.randomUUID().toString();

String finalSourcePath = templateFilePath;
if (LibvirtStorageAdaptor.isTemplateExtractable(templateFilePath)) {
finalSourcePath = templateFilePath.substring(0, templateFilePath.lastIndexOf('.'));
LibvirtStorageAdaptor.extractDownloadedTemplate(templateFilePath, destPool, finalSourcePath);
}

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);
final String rscName = getLinstorRscName(name);
try {
LinstorUtil.applyAuxProps(api, rscName, finalSourceFile.getName(), null);
} catch (ApiException apiExc) {
s_logger.error(String.format("Error setting aux properties for %s", rscName));
logLinstorAnswers(apiExc.getApiCallRcList());
}

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) {
Expand Down

0 comments on commit 8aeaa5c

Please sign in to comment.