Skip to content

Commit 855f4ea

Browse files
rp-dhslove
authored andcommitted
linstor: set/unset allow-two-primaries and protocol on rc level (apache#9560)
1 parent a7608ef commit 855f4ea

3 files changed

Lines changed: 60 additions & 24 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Changelog
2+
3+
All notable changes to Linstor CloudStack plugin will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [2024-08-27]
9+
10+
### Changed
11+
12+
- 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: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package com.cloud.hypervisor.kvm.storage;
1818

19+
import java.util.ArrayList;
1920
import java.util.Collections;
2021
import java.util.HashMap;
2122
import java.util.List;
@@ -26,6 +27,7 @@
2627

2728
import com.cloud.storage.Storage;
2829
import com.cloud.utils.exception.CloudRuntimeException;
30+
2931
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
3032
import org.apache.cloudstack.utils.qemu.QemuImg;
3133
import org.apache.cloudstack.utils.qemu.QemuImgException;
@@ -44,8 +46,8 @@
4446
import com.linbit.linstor.api.model.Properties;
4547
import com.linbit.linstor.api.model.ProviderKind;
4648
import com.linbit.linstor.api.model.Resource;
49+
import com.linbit.linstor.api.model.ResourceConnectionModify;
4750
import com.linbit.linstor.api.model.ResourceDefinition;
48-
import com.linbit.linstor.api.model.ResourceDefinitionModify;
4951
import com.linbit.linstor.api.model.ResourceGroupSpawn;
5052
import com.linbit.linstor.api.model.ResourceMakeAvailable;
5153
import com.linbit.linstor.api.model.ResourceWithVolumes;
@@ -242,15 +244,19 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
242244
* @throws ApiException if any problem connecting to the Linstor controller
243245
*/
244246
private void allow2PrimariesIfInUse(DevelopersApi api, String rscName) throws ApiException {
245-
if (LinstorUtil.isResourceInUse(api, rscName)) {
247+
String inUseNode = LinstorUtil.isResourceInUse(api, rscName);
248+
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
246249
// allow 2 primaries for live migration, should be removed by disconnect on the other end
247-
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
250+
ResourceConnectionModify rcm = new ResourceConnectionModify();
248251
Properties props = new Properties();
249252
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
250-
rdm.setOverrideProps(props);
251-
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
253+
props.put("DrbdOptions/Net/protocol", "C");
254+
rcm.setOverrideProps(props);
255+
ApiCallRcList answers = api.resourceConnectionModify(rscName, inUseNode, localNodeName, rcm);
252256
if (answers.hasError()) {
253-
logger.error("Unable to set 'allow-two-primaries' on {} ", rscName);
257+
logger.error(String.format(
258+
"Unable to set protocol C and 'allow-two-primaries' on %s/%s/%s",
259+
inUseNode, localNodeName, rscName));
254260
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
255261
}
256262
}
@@ -290,6 +296,23 @@ public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<S
290296
return true;
291297
}
292298

299+
private void removeTwoPrimariesRcProps(DevelopersApi api, String inUseNode, String rscName) throws ApiException {
300+
ResourceConnectionModify rcm = new ResourceConnectionModify();
301+
List<String> deleteProps = new ArrayList<>();
302+
deleteProps.add("DrbdOptions/Net/allow-two-primaries");
303+
deleteProps.add("DrbdOptions/Net/protocol");
304+
rcm.deleteProps(deleteProps);
305+
ApiCallRcList answers = api.resourceConnectionModify(rscName, localNodeName, inUseNode, rcm);
306+
if (answers.hasError()) {
307+
s_logger.error(
308+
String.format("Failed to remove 'protocol' and 'allow-two-primaries' on %s/%s/%s: %s",
309+
localNodeName,
310+
inUseNode,
311+
rscName, LinstorUtil.getBestErrorMessage(answers)));
312+
// do not fail here as removing allow-two-primaries property isn't fatal
313+
}
314+
}
315+
293316
private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
294317
{
295318
if (volumePath == null) {
@@ -319,27 +342,25 @@ private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
319342

320343

321344
if (optRsc.isPresent()) {
345+
Resource rsc = optRsc.get();
322346
try {
323-
Resource rsc = optRsc.get();
347+
String inUseNode = LinstorUtil.isResourceInUse(api, rsc.getName());
348+
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
349+
removeTwoPrimariesRcProps(api, inUseNode, rsc.getName());
350+
}
351+
} catch (ApiException apiEx) {
352+
s_logger.error(apiEx.getBestMessage());
353+
// do not fail here as removing allow-two-primaries property or deleting diskless isn't fatal
354+
}
324355

356+
try {
325357
// if diskless resource remove it, in the worst case it will be transformed to a tiebreaker
326358
if (rsc.getFlags() != null &&
327359
rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS) &&
328360
!rsc.getFlags().contains(ApiConsts.FLAG_TIE_BREAKER)) {
329361
ApiCallRcList delAnswers = api.resourceDelete(rsc.getName(), localNodeName);
330362
logLinstorAnswers(delAnswers);
331363
}
332-
333-
// remove allow-two-primaries
334-
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
335-
rdm.deleteProps(Collections.singletonList("DrbdOptions/Net/allow-two-primaries"));
336-
ApiCallRcList answers = api.resourceDefinitionModify(rsc.getName(), rdm);
337-
if (answers.hasError()) {
338-
logger.error(
339-
String.format("Failed to remove 'allow-two-primaries' on %s: %s",
340-
rsc.getName(), LinstorUtil.getBestErrorMessage(answers)));
341-
// do not fail here as removing allow-two-primaries property isn't fatal
342-
}
343364
} catch (ApiException apiEx) {
344365
logger.error(apiEx.getBestMessage());
345366
// do not fail here as removing allow-two-primaries property or deleting diskless isn't fatal

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,17 +192,20 @@ public static long getCapacityBytes(String linstorUrl, String rscGroupName) {
192192
*
193193
* @param api developer api object to use
194194
* @param rscName resource name to check in use state.
195-
* @return True if a resource found that is in use(primary) state, else false.
195+
* @return NodeName where the resource is inUse, if not in use `null`
196196
* @throws ApiException forwards api errors
197197
*/
198-
public static boolean isResourceInUse(DevelopersApi api, String rscName) throws ApiException {
198+
public static String isResourceInUse(DevelopersApi api, String rscName) throws ApiException {
199199
List<Resource> rscs = api.resourceList(rscName, null, null);
200200
if (rscs != null) {
201201
return rscs.stream()
202-
.anyMatch(rsc -> rsc.getState() != null && Boolean.TRUE.equals(rsc.getState().isInUse()));
203-
}
204-
LOGGER.error("isResourceInUse: null returned from resourceList");
205-
return false;
202+
.filter(rsc -> rsc.getState() != null && Boolean.TRUE.equals(rsc.getState().isInUse()))
203+
.map(Resource::getNodeName)
204+
.findFirst()
205+
.orElse(null);
206+
}
207+
s_logger.error("isResourceInUse: null returned from resourceList");
208+
return null;
206209
}
207210

208211
/**

0 commit comments

Comments
 (0)