mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 01:32:18 +02:00
Merge branch '4.19' into 4.20
This commit is contained in:
commit
aca8235960
@ -5,6 +5,12 @@ All notable changes to Linstor CloudStack plugin will be documented in this file
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2025-10-03]
|
||||
|
||||
### Changed
|
||||
|
||||
- Revert qcow2 snapshot now use sparse/discard options to convert on thin devices.
|
||||
|
||||
## [2025-08-05]
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -26,24 +26,39 @@ import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
|
||||
import com.cloud.resource.CommandWrapper;
|
||||
import com.cloud.resource.ResourceWrapper;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.utils.script.Script;
|
||||
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
|
||||
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
|
||||
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
|
||||
import org.apache.cloudstack.storage.to.VolumeObjectTO;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImg;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImgException;
|
||||
import org.apache.cloudstack.utils.qemu.QemuImgFile;
|
||||
import org.joda.time.Duration;
|
||||
import org.libvirt.LibvirtException;
|
||||
|
||||
@ResourceWrapper(handles = LinstorRevertBackupSnapshotCommand.class)
|
||||
public final class LinstorRevertBackupSnapshotCommandWrapper
|
||||
extends CommandWrapper<LinstorRevertBackupSnapshotCommand, CopyCmdAnswer, LibvirtComputingResource>
|
||||
{
|
||||
private void convertQCow2ToRAW(final String srcPath, final String dstPath, int waitMilliSeconds)
|
||||
|
||||
private void convertQCow2ToRAW(
|
||||
KVMStoragePool pool, final String srcPath, final String dstUuid, int waitMilliSeconds)
|
||||
throws LibvirtException, QemuImgException
|
||||
{
|
||||
final String dstPath = pool.getPhysicalDisk(dstUuid).getPath();
|
||||
final QemuImgFile srcQemuFile = new QemuImgFile(
|
||||
srcPath, QemuImg.PhysicalDiskFormat.QCOW2);
|
||||
final QemuImg qemu = new QemuImg(waitMilliSeconds);
|
||||
boolean zeroedDevice = LinstorUtil.resourceSupportZeroBlocks(pool, LinstorUtil.RSC_PREFIX + dstUuid);
|
||||
if (zeroedDevice)
|
||||
{
|
||||
// blockdiscard the device to ensure the device is filled with zeroes
|
||||
Script blkDiscardScript = new Script("blkdiscard", Duration.millis(waitMilliSeconds));
|
||||
blkDiscardScript.add("-f");
|
||||
blkDiscardScript.add(dstPath);
|
||||
blkDiscardScript.execute();
|
||||
}
|
||||
final QemuImg qemu = new QemuImg(waitMilliSeconds, zeroedDevice, true);
|
||||
final QemuImgFile dstFile = new QemuImgFile(dstPath, QemuImg.PhysicalDiskFormat.RAW);
|
||||
qemu.convert(srcQemuFile, dstFile);
|
||||
}
|
||||
@ -70,8 +85,9 @@ public final class LinstorRevertBackupSnapshotCommandWrapper
|
||||
srcDataStore.getUrl() + File.separator + srcFile.getParent());
|
||||
|
||||
convertQCow2ToRAW(
|
||||
linstorPool,
|
||||
secondaryPool.getLocalPath() + File.separator + srcFile.getName(),
|
||||
linstorPool.getPhysicalDisk(dst.getPath()).getPath(),
|
||||
dst.getPath(),
|
||||
cmd.getWaitInMillSeconds());
|
||||
|
||||
final VolumeObjectTO dstVolume = new VolumeObjectTO();
|
||||
|
||||
@ -30,7 +30,6 @@ 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;
|
||||
@ -57,7 +56,6 @@ import com.linbit.linstor.api.model.ResourceGroupSpawn;
|
||||
import com.linbit.linstor.api.model.ResourceMakeAvailable;
|
||||
import com.linbit.linstor.api.model.ResourceWithVolumes;
|
||||
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;
|
||||
@ -573,40 +571,6 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
||||
return copyPhysicalDisk(disk, name, destPool, timeout, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all diskful resource are on a zeroed block device.
|
||||
* @param destPool Linstor pool to use
|
||||
* @param resName Linstor resource name
|
||||
* @return true if all resources are on a provider with zeroed blocks.
|
||||
*/
|
||||
private boolean resourceSupportZeroBlocks(KVMStoragePool destPool, String resName) {
|
||||
final DevelopersApi api = getLinstorAPI(destPool);
|
||||
|
||||
try {
|
||||
List<ResourceWithVolumes> resWithVols = api.viewResources(
|
||||
Collections.emptyList(),
|
||||
Collections.singletonList(resName),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
null,
|
||||
null);
|
||||
|
||||
if (resWithVols != null) {
|
||||
return resWithVols.stream()
|
||||
.allMatch(res -> {
|
||||
Volume vol0 = res.getVolumes().get(0);
|
||||
return vol0 != null && (vol0.getProviderKind() == ProviderKind.LVM_THIN ||
|
||||
vol0.getProviderKind() == ProviderKind.ZFS ||
|
||||
vol0.getProviderKind() == ProviderKind.ZFS_THIN ||
|
||||
vol0.getProviderKind() == ProviderKind.DISKLESS);
|
||||
} );
|
||||
}
|
||||
} catch (ApiException apiExc) {
|
||||
logger.error(apiExc.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given disk is the SystemVM template, by checking its properties file in the same directory.
|
||||
* The initial systemvm template resource isn't created on the management server, but
|
||||
@ -677,7 +641,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
||||
destFile.setFormat(dstDisk.getFormat());
|
||||
destFile.setSize(disk.getVirtualSize());
|
||||
|
||||
boolean zeroedDevice = resourceSupportZeroBlocks(destPools, getLinstorRscName(name));
|
||||
boolean zeroedDevice = LinstorUtil.resourceSupportZeroBlocks(destPools, getLinstorRscName(name));
|
||||
try {
|
||||
final QemuImg qemu = new QemuImg(timeout, zeroedDevice, true);
|
||||
qemu.convert(srcFile, destFile);
|
||||
|
||||
@ -42,6 +42,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -431,4 +432,37 @@ public class LinstorUtil {
|
||||
public static boolean isRscDiskless(ResourceWithVolumes rsc) {
|
||||
return rsc.getFlags() != null && rsc.getFlags().contains(ApiConsts.FLAG_DISKLESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all diskful resource are on a zeroed block device.
|
||||
* @param pool Linstor pool to use
|
||||
* @param resName Linstor resource name
|
||||
* @return true if all resources are on a provider with zeroed blocks.
|
||||
*/
|
||||
public static boolean resourceSupportZeroBlocks(KVMStoragePool pool, String resName) {
|
||||
final DevelopersApi api = getLinstorAPI(pool.getSourceHost());
|
||||
try {
|
||||
List<ResourceWithVolumes> resWithVols = api.viewResources(
|
||||
Collections.emptyList(),
|
||||
Collections.singletonList(resName),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
null,
|
||||
null);
|
||||
|
||||
if (resWithVols != null) {
|
||||
return resWithVols.stream()
|
||||
.allMatch(res -> {
|
||||
Volume vol0 = res.getVolumes().get(0);
|
||||
return vol0 != null && (vol0.getProviderKind() == ProviderKind.LVM_THIN ||
|
||||
vol0.getProviderKind() == ProviderKind.ZFS ||
|
||||
vol0.getProviderKind() == ProviderKind.ZFS_THIN ||
|
||||
vol0.getProviderKind() == ProviderKind.DISKLESS);
|
||||
} );
|
||||
}
|
||||
} catch (ApiException apiExc) {
|
||||
LOGGER.error(apiExc.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user