linstor: Provide /dev/drbd/by-res/ resource paths to CloudStack (#12300)

This commit is contained in:
Rene Peinthor 2025-12-31 10:55:54 +01:00 committed by GitHub
parent 5cb279b6f1
commit 10dcbd76f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 21 deletions

View File

@ -5,22 +5,24 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2025-12-18]
### Changed
- Provide /dev/drbd/by-res/ resource paths to CloudStack for usage.
## [2025-10-03] ## [2025-10-03]
### Changed ### Changed
- Revert qcow2 snapshot now use sparse/discard options to convert on thin devices. - Revert qcow2 snapshot now use sparse/discard options to convert on thin devices.
## [2025-08-05] ## [2025-08-05]
### Fixed ### Fixed
- getVolumeStats wasn't correctly working if multiple Linstor clusters/primary storages are used. - getVolumeStats wasn't correctly working if multiple Linstor clusters/primary storages are used.
## [2025-07-01] ## [2025-07-01]
### Fixed ### Fixed
- Regression in 4.19.3 and 4.21.0 with templates from snapshots - Regression in 4.19.3 and 4.21.0 with templates from snapshots
## [2025-05-07] ## [2025-05-07]
@ -31,25 +33,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2025-03-13] ## [2025-03-13]
### Fixed ### Fixed
- Implemented missing delete datastore, to correctly cleanup on datastore removal - Implemented missing delete datastore, to correctly cleanup on datastore removal
## [2025-02-21] ## [2025-02-21]
### Fixed ### Fixed
- Always try to delete cs-...-rst resource before doing a snapshot backup - Always try to delete cs-...-rst resource before doing a snapshot backup
## [2025-01-27] ## [2025-01-27]
### Fixed ### Fixed
- Use of multiple primary storages on the same linstor controller - Use of multiple primary storages on the same linstor controller
## [2025-01-20] ## [2025-01-20]
### Fixed ### Fixed
- Volume snapshots on zfs used the wrong dataset path to hide/unhide snapdev - Volume snapshots on zfs used the wrong dataset path to hide/unhide snapdev
## [2024-12-19] ## [2024-12-19]
@ -60,13 +58,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2024-12-13] ## [2024-12-13]
### Fixed ### Fixed
- Linstor heartbeat check now also ask linstor-controller if there is no connection between nodes - Linstor heartbeat check now also ask linstor-controller if there is no connection between nodes
## [2024-12-11] ## [2024-12-11]
### Fixed ### Fixed
- Only set allow-two-primaries if a live migration is performed - Only set allow-two-primaries if a live migration is performed
## [2024-10-28] ## [2024-10-28]
@ -79,17 +75,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2024-10-14] ## [2024-10-14]
### Added ### Added
- Support for ISO direct download to primary storage - Support for ISO direct download to primary storage
## [2024-10-04] ## [2024-10-04]
### Added ### Added
- Enable qemu discard="unmap" for Linstor block disks - Enable qemu discard="unmap" for Linstor block disks
## [2024-08-27] ## [2024-08-27]
### Changed ### Changed
- Allow two primaries(+protocol c) is now set on resource-connection level instead of rd - Allow two primaries(+protocol c) is now set on resource-connection level instead of rd

View File

@ -232,7 +232,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
makeResourceAvailable(api, foundRscName, false); makeResourceAvailable(api, foundRscName, false);
if (!resources.isEmpty() && !resources.get(0).getVolumes().isEmpty()) { if (!resources.isEmpty() && !resources.get(0).getVolumes().isEmpty()) {
final String devPath = resources.get(0).getVolumes().get(0).getDevicePath(); final String devPath = LinstorUtil.getDevicePathFromResource(resources.get(0));
logger.info("Linstor: Created drbd device: " + devPath); logger.info("Linstor: Created drbd device: " + devPath);
final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk(devPath, name, pool); final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk(devPath, name, pool);
kvmDisk.setFormat(QemuImg.PhysicalDiskFormat.RAW); kvmDisk.setFormat(QemuImg.PhysicalDiskFormat.RAW);
@ -455,8 +455,9 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
private Optional<ResourceWithVolumes> getResourceByPathOrName( private Optional<ResourceWithVolumes> getResourceByPathOrName(
final List<ResourceWithVolumes> resources, String path) { final List<ResourceWithVolumes> resources, String path) {
return resources.stream() return resources.stream()
.filter(rsc -> getLinstorRscName(path).equalsIgnoreCase(rsc.getName()) || rsc.getVolumes().stream() .filter(rsc -> getLinstorRscName(path).equalsIgnoreCase(rsc.getName()) ||
.anyMatch(v -> path.equals(v.getDevicePath()))) path.equals(LinstorUtil.formatDrbdByResDevicePath(rsc.getName())) ||
rsc.getVolumes().stream().anyMatch(v -> path.equals(v.getDevicePath())))
.findFirst(); .findFirst();
} }

View File

@ -264,6 +264,16 @@ public class LinstorUtil {
return false; return false;
} }
/**
* Format the device path for DRBD resources.
* @param rscName
* @return
*/
public static String formatDrbdByResDevicePath(String rscName)
{
return String.format("/dev/drbd/by-res/%s/0", rscName);
}
/** /**
* Try to get the device path for the given resource name. * Try to get the device path for the given resource name.
* This could be made a bit more direct after java-linstor api is fixed for layer data subtypes. * This could be made a bit more direct after java-linstor api is fixed for layer data subtypes.
@ -283,12 +293,7 @@ public class LinstorUtil {
null); null);
for (ResourceWithVolumes rsc : resources) { for (ResourceWithVolumes rsc : resources) {
if (!rsc.getVolumes().isEmpty()) { if (!rsc.getVolumes().isEmpty()) {
// CloudStack resource always only have 1 volume return LinstorUtil.getDevicePathFromResource(rsc);
String devicePath = rsc.getVolumes().get(0).getDevicePath();
if (devicePath != null && !devicePath.isEmpty()) {
LOGGER.debug("getDevicePath: {} -> {}", rscName, devicePath);
return devicePath;
}
} }
} }
@ -297,6 +302,24 @@ public class LinstorUtil {
throw new CloudRuntimeException("Linstor: " + errMsg); throw new CloudRuntimeException("Linstor: " + errMsg);
} }
/**
* Check if the resource has DRBD or not and deliver the correct device path.
* @param rsc
* @return
*/
public static String getDevicePathFromResource(ResourceWithVolumes rsc) {
if (!rsc.getVolumes().isEmpty()) {
// CloudStack resource always only have 1 volume
if (rsc.getLayerObject().getDrbd() != null) {
return formatDrbdByResDevicePath(rsc.getName());
} else {
return rsc.getVolumes().get(0).getDevicePath();
}
}
throw new CloudRuntimeException(
String.format("getDevicePath: Resource %s/%s doesn't have volumes", rsc.getNodeName(), rsc.getName()));
}
public static ApiCallRcList applyAuxProps(DevelopersApi api, String rscName, String dispName, String vmName) public static ApiCallRcList applyAuxProps(DevelopersApi api, String rscName, String dispName, String vmName)
throws ApiException throws ApiException
{ {