Linstor: Fix migrate primary storage (#9528)

This commit is contained in:
Rene Peinthor 2024-09-09 10:01:41 +02:00 committed by GitHub
parent ebaf064d92
commit 3f5a77ef58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 76 additions and 35 deletions

View File

@ -18,6 +18,7 @@ package com.cloud.hypervisor.kvm.storage;
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
import org.apache.cloudstack.utils.qemu.QemuObject; import org.apache.cloudstack.utils.qemu.QemuObject;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
@ -25,8 +26,10 @@ import java.util.List;
public class KVMPhysicalDisk { public class KVMPhysicalDisk {
private String path; private String path;
private String name; private final String name;
private KVMStoragePool pool; private final KVMStoragePool pool;
private String dispName;
private String vmName;
private boolean useAsTemplate; private boolean useAsTemplate;
public static String RBDStringBuilder(String monHost, int monPort, String authUserName, String authSecret, String image) { public static String RBDStringBuilder(String monHost, int monPort, String authUserName, String authSecret, String image) {
@ -81,7 +84,9 @@ public class KVMPhysicalDisk {
@Override @Override
public String toString() { public String toString() {
return "KVMPhysicalDisk [path=" + path + ", name=" + name + ", pool=" + pool + ", format=" + format + ", size=" + size + ", virtualSize=" + virtualSize + "]"; return String.format("KVMPhysicalDisk %s",
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(
this, "path", "name", "pool", "format", "size", "virtualSize", "dispName", "vmName"));
} }
public void setFormat(PhysicalDiskFormat format) { public void setFormat(PhysicalDiskFormat format) {
@ -135,4 +140,20 @@ public class KVMPhysicalDisk {
public void setUseAsTemplate() { this.useAsTemplate = true; } public void setUseAsTemplate() { this.useAsTemplate = true; }
public boolean useAsTemplate() { return this.useAsTemplate; } public boolean useAsTemplate() { return this.useAsTemplate; }
public String getDispName() {
return dispName;
}
public void setDispName(String dispName) {
this.dispName = dispName;
}
public String getVmName() {
return vmName;
}
public void setVmName(String vmName) {
this.vmName = vmName;
}
} }

View File

@ -432,6 +432,7 @@ public class KVMStorageProcessor implements StorageProcessor {
if (!storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path, details)) { if (!storagePoolMgr.connectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), path, details)) {
s_logger.warn("Failed to connect new volume at path: " + path + ", in storage pool id: " + primaryStore.getUuid()); s_logger.warn("Failed to connect new volume at path: " + path + ", in storage pool id: " + primaryStore.getUuid());
} }
BaseVol.setDispName(template.getName());
vol = storagePoolMgr.copyPhysicalDisk(BaseVol, path != null ? path : volume.getUuid(), primaryPool, cmd.getWaitInMillSeconds(), null, volume.getPassphrase(), volume.getProvisioningType()); vol = storagePoolMgr.copyPhysicalDisk(BaseVol, path != null ? path : volume.getUuid(), primaryPool, cmd.getWaitInMillSeconds(), null, volume.getPassphrase(), volume.getProvisioningType());
@ -524,6 +525,8 @@ public class KVMStorageProcessor implements StorageProcessor {
final KVMPhysicalDisk volume = secondaryStoragePool.getPhysicalDisk(srcVolumeName); final KVMPhysicalDisk volume = secondaryStoragePool.getPhysicalDisk(srcVolumeName);
volume.setFormat(PhysicalDiskFormat.valueOf(srcFormat.toString())); volume.setFormat(PhysicalDiskFormat.valueOf(srcFormat.toString()));
volume.setDispName(srcVol.getName());
volume.setVmName(srcVol.getVmName());
final KVMPhysicalDisk newDisk = storagePoolMgr.copyPhysicalDisk(volume, path != null ? path : volumeName, primaryPool, cmd.getWaitInMillSeconds()); final KVMPhysicalDisk newDisk = storagePoolMgr.copyPhysicalDisk(volume, path != null ? path : volumeName, primaryPool, cmd.getWaitInMillSeconds());
@ -2486,6 +2489,8 @@ public class KVMStorageProcessor implements StorageProcessor {
} }
volume.setFormat(PhysicalDiskFormat.valueOf(srcFormat.toString())); volume.setFormat(PhysicalDiskFormat.valueOf(srcFormat.toString()));
volume.setDispName(srcVol.getName());
volume.setVmName(srcVol.getVmName());
String destVolumeName = null; String destVolumeName = null;
if (destPrimaryStore.isManaged()) { if (destPrimaryStore.isManaged()) {

View File

@ -1402,7 +1402,10 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
*/ */
KVMStoragePool srcPool = disk.getPool(); KVMStoragePool srcPool = disk.getPool();
PhysicalDiskFormat sourceFormat = disk.getFormat(); /* Linstor images are always stored as RAW, but Linstor uses qcow2 in DB,
to support snapshots(backuped) as qcow2 files. */
PhysicalDiskFormat sourceFormat = srcPool.getType() != StoragePoolType.Linstor ?
disk.getFormat() : PhysicalDiskFormat.RAW;
String sourcePath = disk.getPath(); String sourcePath = disk.getPath();
KVMPhysicalDisk newDisk; KVMPhysicalDisk newDisk;

View File

@ -516,6 +516,15 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
final KVMPhysicalDisk dstDisk = destPools.createPhysicalDisk( final KVMPhysicalDisk dstDisk = destPools.createPhysicalDisk(
name, QemuImg.PhysicalDiskFormat.RAW, provisioningType, disk.getVirtualSize(), null); 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());
}
s_logger.debug(String.format("Linstor.copyPhysicalDisk: dstPath: %s", dstDisk.getPath())); s_logger.debug(String.format("Linstor.copyPhysicalDisk: dstPath: %s", dstDisk.getPath()));
final QemuImgFile destFile = new QemuImgFile(dstDisk.getPath()); final QemuImgFile destFile = new QemuImgFile(dstDisk.getPath());
destFile.setFormat(dstDisk.getFormat()); destFile.setFormat(dstDisk.getFormat());

View File

@ -26,7 +26,6 @@ import com.linbit.linstor.api.model.ResourceDefinition;
import com.linbit.linstor.api.model.ResourceDefinitionCloneRequest; import com.linbit.linstor.api.model.ResourceDefinitionCloneRequest;
import com.linbit.linstor.api.model.ResourceDefinitionCloneStarted; import com.linbit.linstor.api.model.ResourceDefinitionCloneStarted;
import com.linbit.linstor.api.model.ResourceDefinitionCreate; import com.linbit.linstor.api.model.ResourceDefinitionCreate;
import com.linbit.linstor.api.model.ResourceDefinitionModify;
import com.linbit.linstor.api.model.ResourceGroupSpawn; import com.linbit.linstor.api.model.ResourceGroupSpawn;
import com.linbit.linstor.api.model.ResourceMakeAvailable; import com.linbit.linstor.api.model.ResourceMakeAvailable;
import com.linbit.linstor.api.model.Snapshot; import com.linbit.linstor.api.model.Snapshot;
@ -62,8 +61,8 @@ import com.cloud.resource.ResourceState;
import com.cloud.storage.DataStoreRole; import com.cloud.storage.DataStoreRole;
import com.cloud.storage.ResizeVolumePayload; import com.cloud.storage.ResizeVolumePayload;
import com.cloud.storage.SnapshotVO; import com.cloud.storage.SnapshotVO;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Storage; import com.cloud.storage.Storage;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageManager; import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateStoragePoolVO;
@ -389,27 +388,6 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
} }
} }
private void applyAuxProps(DevelopersApi api, String rscName, String dispName, String vmName)
throws ApiException
{
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
Properties props = new Properties();
if (dispName != null)
{
props.put("Aux/cs-name", dispName);
}
if (vmName != null)
{
props.put("Aux/cs-vm-name", vmName);
}
if (!props.isEmpty())
{
rdm.setOverrideProps(props);
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
checkLinstorAnswersThrow(answers);
}
}
private String getRscGrp(StoragePoolVO storagePoolVO) { private String getRscGrp(StoragePoolVO storagePoolVO) {
return storagePoolVO.getUserInfo() != null && !storagePoolVO.getUserInfo().isEmpty() ? return storagePoolVO.getUserInfo() != null && !storagePoolVO.getUserInfo().isEmpty() ?
storagePoolVO.getUserInfo() : "DfltRscGrp"; storagePoolVO.getUserInfo() : "DfltRscGrp";
@ -427,7 +405,8 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
ApiCallRcList answers = api.resourceGroupSpawn(rscGrp, rscGrpSpawn); ApiCallRcList answers = api.resourceGroupSpawn(rscGrp, rscGrpSpawn);
checkLinstorAnswersThrow(answers); checkLinstorAnswersThrow(answers);
applyAuxProps(api, rscName, volName, vmName); answers = LinstorUtil.applyAuxProps(api, rscName, volName, vmName);
checkLinstorAnswersThrow(answers);
return LinstorUtil.getDevicePath(api, rscName); return LinstorUtil.getDevicePath(api, rscName);
} catch (ApiException apiEx) } catch (ApiException apiEx)
@ -499,7 +478,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
resizeResource(linstorApi, rscName, volumeInfo.getSize()); resizeResource(linstorApi, rscName, volumeInfo.getSize());
} }
applyAuxProps(linstorApi, rscName, volumeInfo.getName(), volumeInfo.getAttachedVmName()); LinstorUtil.applyAuxProps(linstorApi, rscName, volumeInfo.getName(), volumeInfo.getAttachedVmName());
applyQoSSettings(storagePoolVO, linstorApi, rscName, volumeInfo.getMaxIops()); applyQoSSettings(storagePoolVO, linstorApi, rscName, volumeInfo.getMaxIops());
return LinstorUtil.getDevicePath(linstorApi, rscName); return LinstorUtil.getDevicePath(linstorApi, rscName);
@ -551,7 +530,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
answers = linstorApi.resourceSnapshotRestore(cloneRes, snapName, snapshotRestore); answers = linstorApi.resourceSnapshotRestore(cloneRes, snapName, snapshotRestore);
checkLinstorAnswersThrow(answers); checkLinstorAnswersThrow(answers);
applyAuxProps(linstorApi, rscName, volumeVO.getName(), null); LinstorUtil.applyAuxProps(linstorApi, rscName, volumeVO.getName(), null);
applyQoSSettings(storagePoolVO, linstorApi, rscName, volumeVO.getMaxIops()); applyQoSSettings(storagePoolVO, linstorApi, rscName, volumeVO.getMaxIops());
return LinstorUtil.getDevicePath(linstorApi, rscName); return LinstorUtil.getDevicePath(linstorApi, rscName);
@ -833,7 +812,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
VolumeInfo volume = sinfo.getBaseVolume(); VolumeInfo volume = sinfo.getBaseVolume();
deleteSnapshot( deleteSnapshot(
srcData.getDataStore(), srcData.getDataStore(),
LinstorUtil.RSC_PREFIX + volume.getUuid(), LinstorUtil.RSC_PREFIX + volume.getPath(),
LinstorUtil.RSC_PREFIX + sinfo.getUuid()); LinstorUtil.RSC_PREFIX + sinfo.getUuid());
} }
res = new CopyCommandResult(null, answer); res = new CopyCommandResult(null, answer);
@ -969,7 +948,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
VolumeInfo srcVolInfo = (VolumeInfo) srcData; VolumeInfo srcVolInfo = (VolumeInfo) srcData;
final StoragePoolVO pool = _storagePoolDao.findById(srcVolInfo.getDataStore().getId()); final StoragePoolVO pool = _storagePoolDao.findById(srcVolInfo.getDataStore().getId());
final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress()); final DevelopersApi api = LinstorUtil.getLinstorAPI(pool.getHostAddress());
final String rscName = LinstorUtil.RSC_PREFIX + srcVolInfo.getUuid(); final String rscName = LinstorUtil.RSC_PREFIX + srcVolInfo.getPath();
VolumeObjectTO to = (VolumeObjectTO) srcVolInfo.getTO(); VolumeObjectTO to = (VolumeObjectTO) srcVolInfo.getTO();
// patch source format // patch source format
@ -1082,7 +1061,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
options.put("volumeSize", snapshotObject.getBaseVolume().getSize() + ""); options.put("volumeSize", snapshotObject.getBaseVolume().getSize() + "");
try { try {
final String rscName = LinstorUtil.RSC_PREFIX + snapshotObject.getBaseVolume().getUuid(); final String rscName = LinstorUtil.RSC_PREFIX + snapshotObject.getBaseVolume().getPath();
String snapshotName = setCorrectSnapshotPath(api, rscName, snapshotObject); String snapshotName = setCorrectSnapshotPath(api, rscName, snapshotObject);
CopyCommand cmd = new LinstorBackupSnapshotCommand( CopyCommand cmd = new LinstorBackupSnapshotCommand(

View File

@ -22,8 +22,10 @@ import com.linbit.linstor.api.DevelopersApi;
import com.linbit.linstor.api.model.ApiCallRc; import com.linbit.linstor.api.model.ApiCallRc;
import com.linbit.linstor.api.model.ApiCallRcList; import com.linbit.linstor.api.model.ApiCallRcList;
import com.linbit.linstor.api.model.Node; import com.linbit.linstor.api.model.Node;
import com.linbit.linstor.api.model.Properties;
import com.linbit.linstor.api.model.ProviderKind; import com.linbit.linstor.api.model.ProviderKind;
import com.linbit.linstor.api.model.Resource; import com.linbit.linstor.api.model.Resource;
import com.linbit.linstor.api.model.ResourceDefinitionModify;
import com.linbit.linstor.api.model.ResourceGroup; import com.linbit.linstor.api.model.ResourceGroup;
import com.linbit.linstor.api.model.ResourceWithVolumes; import com.linbit.linstor.api.model.ResourceWithVolumes;
import com.linbit.linstor.api.model.StoragePool; import com.linbit.linstor.api.model.StoragePool;
@ -239,4 +241,26 @@ public class LinstorUtil {
s_logger.error(errMsg); s_logger.error(errMsg);
throw new CloudRuntimeException("Linstor: " + errMsg); throw new CloudRuntimeException("Linstor: " + errMsg);
} }
public static ApiCallRcList applyAuxProps(DevelopersApi api, String rscName, String dispName, String vmName)
throws ApiException
{
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
Properties props = new Properties();
if (dispName != null)
{
props.put("Aux/cs-name", dispName);
}
if (vmName != null)
{
props.put("Aux/cs-vm-name", vmName);
}
ApiCallRcList answers = new ApiCallRcList();
if (!props.isEmpty())
{
rdm.setOverrideProps(props);
answers = api.resourceDefinitionModify(rscName, rdm);
}
return answers;
}
} }

View File

@ -239,7 +239,7 @@ public class LinstorVMSnapshotStrategy extends DefaultVMSnapshotStrategy {
final String snapshotName = vmSnapshotVO.getName(); final String snapshotName = vmSnapshotVO.getName();
final List<String> failedToDelete = new ArrayList<>(); final List<String> failedToDelete = new ArrayList<>();
for (VolumeObjectTO volumeObjectTO : volumeTOs) { for (VolumeObjectTO volumeObjectTO : volumeTOs) {
final String rscName = LinstorUtil.RSC_PREFIX + volumeObjectTO.getUuid(); final String rscName = LinstorUtil.RSC_PREFIX + volumeObjectTO.getPath();
String err = linstorDeleteSnapshot(api, rscName, snapshotName); String err = linstorDeleteSnapshot(api, rscName, snapshotName);
if (err != null) if (err != null)
@ -292,7 +292,7 @@ public class LinstorVMSnapshotStrategy extends DefaultVMSnapshotStrategy {
final String snapshotName = vmSnapshotVO.getName(); final String snapshotName = vmSnapshotVO.getName();
for (VolumeObjectTO volumeObjectTO : volumeTOs) { for (VolumeObjectTO volumeObjectTO : volumeTOs) {
final String rscName = LinstorUtil.RSC_PREFIX + volumeObjectTO.getUuid(); final String rscName = LinstorUtil.RSC_PREFIX + volumeObjectTO.getPath();
String err = linstorRevertSnapshot(api, rscName, snapshotName); String err = linstorRevertSnapshot(api, rscName, snapshotName);
if (err != null) { if (err != null) {
throw new CloudRuntimeException(String.format( throw new CloudRuntimeException(String.format(