Skip to content

Commit 5fedf32

Browse files
committed
linstor: Provide /dev/drbd/by-res/ resource paths to CloudStack (apache#12300)
1 parent c4e2edb commit 5fedf32

File tree

3 files changed

+38
-21
lines changed

3 files changed

+38
-21
lines changed

plugins/storage/volume/linstor/CHANGELOG.md

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,24 @@ All notable changes to Linstor CloudStack plugin will be documented in this file
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [2025-10-03]
8+
## [2025-12-18]
99

1010
### Changed
11+
- Provide /dev/drbd/by-res/ resource paths to CloudStack for usage.
12+
13+
## [2025-10-03]
1114

15+
### Changed
1216
- Revert qcow2 snapshot now use sparse/discard options to convert on thin devices.
1317

1418
## [2025-08-05]
1519

1620
### Fixed
17-
1821
- getVolumeStats wasn't correctly working if multiple Linstor clusters/primary storages are used.
1922

2023
## [2025-07-01]
2124

2225
### Fixed
23-
2426
- Regression in 4.19.3 and 4.21.0 with templates from snapshots
2527

2628
## [2025-05-07]
@@ -31,25 +33,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3133
## [2025-03-13]
3234

3335
### Fixed
34-
3536
- Implemented missing delete datastore, to correctly cleanup on datastore removal
3637

3738
## [2025-02-21]
3839

3940
### Fixed
40-
4141
- Always try to delete cs-...-rst resource before doing a snapshot backup
4242

4343
## [2025-01-27]
4444

4545
### Fixed
46-
4746
- Use of multiple primary storages on the same linstor controller
4847

4948
## [2025-01-20]
5049

5150
### Fixed
52-
5351
- Volume snapshots on zfs used the wrong dataset path to hide/unhide snapdev
5452

5553
## [2024-12-19]
@@ -60,13 +58,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6058
## [2024-12-13]
6159

6260
### Fixed
63-
6461
- Linstor heartbeat check now also ask linstor-controller if there is no connection between nodes
6562

6663
## [2024-12-11]
6764

6865
### Fixed
69-
7066
- Only set allow-two-primaries if a live migration is performed
7167

7268
## [2024-10-28]
@@ -79,17 +75,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7975
## [2024-10-14]
8076

8177
### Added
82-
8378
- Support for ISO direct download to primary storage
8479

8580
## [2024-10-04]
8681

8782
### Added
88-
8983
- Enable qemu discard="unmap" for Linstor block disks
9084

9185
## [2024-08-27]
9286

9387
### Changed
94-
9588
- Allow two primaries(+protocol c) is now set on resource-connection level instead of rd

plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
229229
makeResourceAvailable(api, foundRscName, false);
230230

231231
if (!resources.isEmpty() && !resources.get(0).getVolumes().isEmpty()) {
232-
final String devPath = resources.get(0).getVolumes().get(0).getDevicePath();
232+
final String devPath = LinstorUtil.getDevicePathFromResource(resources.get(0));
233233
s_logger.info("Linstor: Created drbd device: " + devPath);
234234
final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk(devPath, name, pool);
235235
kvmDisk.setFormat(QemuImg.PhysicalDiskFormat.RAW);
@@ -453,8 +453,9 @@ public boolean disconnectPhysicalDisk(Map<String, String> volumeToDisconnect)
453453
private Optional<ResourceWithVolumes> getResourceByPathOrName(
454454
final List<ResourceWithVolumes> resources, String path) {
455455
return resources.stream()
456-
.filter(rsc -> getLinstorRscName(path).equalsIgnoreCase(rsc.getName()) || rsc.getVolumes().stream()
457-
.anyMatch(v -> path.equals(v.getDevicePath())))
456+
.filter(rsc -> getLinstorRscName(path).equalsIgnoreCase(rsc.getName()) ||
457+
path.equals(LinstorUtil.formatDrbdByResDevicePath(rsc.getName())) ||
458+
rsc.getVolumes().stream().anyMatch(v -> path.equals(v.getDevicePath())))
458459
.findFirst();
459460
}
460461

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,16 @@ public static boolean areResourcesDiskless(DevelopersApi api, String rscName, Co
263263
return false;
264264
}
265265

266+
/**
267+
* Format the device path for DRBD resources.
268+
* @param rscName
269+
* @return
270+
*/
271+
public static String formatDrbdByResDevicePath(String rscName)
272+
{
273+
return String.format("/dev/drbd/by-res/%s/0", rscName);
274+
}
275+
266276
/**
267277
* Try to get the device path for the given resource name.
268278
* This could be made a bit more direct after java-linstor api is fixed for layer data subtypes.
@@ -282,12 +292,7 @@ public static String getDevicePath(DevelopersApi api, String rscName) throws Api
282292
null);
283293
for (ResourceWithVolumes rsc : resources) {
284294
if (!rsc.getVolumes().isEmpty()) {
285-
// CloudStack resource always only have 1 volume
286-
String devicePath = rsc.getVolumes().get(0).getDevicePath();
287-
if (devicePath != null && !devicePath.isEmpty()) {
288-
s_logger.debug(String.format("getDevicePath: %s -> %s", rscName, devicePath));
289-
return devicePath;
290-
}
295+
return LinstorUtil.getDevicePathFromResource(rsc);
291296
}
292297
}
293298

@@ -296,6 +301,24 @@ public static String getDevicePath(DevelopersApi api, String rscName) throws Api
296301
throw new CloudRuntimeException("Linstor: " + errMsg);
297302
}
298303

304+
/**
305+
* Check if the resource has DRBD or not and deliver the correct device path.
306+
* @param rsc
307+
* @return
308+
*/
309+
public static String getDevicePathFromResource(ResourceWithVolumes rsc) {
310+
if (!rsc.getVolumes().isEmpty()) {
311+
// CloudStack resource always only have 1 volume
312+
if (rsc.getLayerObject().getDrbd() != null) {
313+
return formatDrbdByResDevicePath(rsc.getName());
314+
} else {
315+
return rsc.getVolumes().get(0).getDevicePath();
316+
}
317+
}
318+
throw new CloudRuntimeException(
319+
String.format("getDevicePath: Resource %s/%s doesn't have volumes", rsc.getNodeName(), rsc.getName()));
320+
}
321+
299322
public static ApiCallRcList applyAuxProps(DevelopersApi api, String rscName, String dispName, String vmName)
300323
throws ApiException
301324
{

0 commit comments

Comments
 (0)