Skip to content

Commit 537c0a1

Browse files
authored
linstor: set/unset allow-two-primaries and protocol on rc level (#9560)
1 parent 7a9bb83 commit 537c0a1

File tree

3 files changed

+60
-23
lines changed

3 files changed

+60
-23
lines changed
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: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.io.BufferedReader;
2020
import java.io.IOException;
2121
import java.io.InputStreamReader;
22+
23+
import java.util.ArrayList;
2224
import java.util.Collections;
2325
import java.util.HashMap;
2426
import java.util.List;
@@ -37,6 +39,7 @@
3739

3840
import com.cloud.storage.Storage;
3941
import com.cloud.utils.exception.CloudRuntimeException;
42+
4043
import com.linbit.linstor.api.ApiClient;
4144
import com.linbit.linstor.api.ApiConsts;
4245
import com.linbit.linstor.api.ApiException;
@@ -47,8 +50,8 @@
4750
import com.linbit.linstor.api.model.Properties;
4851
import com.linbit.linstor.api.model.ProviderKind;
4952
import com.linbit.linstor.api.model.Resource;
53+
import com.linbit.linstor.api.model.ResourceConnectionModify;
5054
import com.linbit.linstor.api.model.ResourceDefinition;
51-
import com.linbit.linstor.api.model.ResourceDefinitionModify;
5255
import com.linbit.linstor.api.model.ResourceGroup;
5356
import com.linbit.linstor.api.model.ResourceGroupSpawn;
5457
import com.linbit.linstor.api.model.ResourceMakeAvailable;
@@ -262,15 +265,19 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
262265
* @throws ApiException if any problem connecting to the Linstor controller
263266
*/
264267
private void allow2PrimariesIfInUse(DevelopersApi api, String rscName) throws ApiException {
265-
if (LinstorUtil.isResourceInUse(api, rscName)) {
268+
String inUseNode = LinstorUtil.isResourceInUse(api, rscName);
269+
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
266270
// allow 2 primaries for live migration, should be removed by disconnect on the other end
267-
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
271+
ResourceConnectionModify rcm = new ResourceConnectionModify();
268272
Properties props = new Properties();
269273
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
270-
rdm.setOverrideProps(props);
271-
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
274+
props.put("DrbdOptions/Net/protocol", "C");
275+
rcm.setOverrideProps(props);
276+
ApiCallRcList answers = api.resourceConnectionModify(rscName, inUseNode, localNodeName, rcm);
272277
if (answers.hasError()) {
273-
s_logger.error("Unable to set 'allow-two-primaries' on " + rscName);
278+
s_logger.error(String.format(
279+
"Unable to set protocol C and 'allow-two-primaries' on %s/%s/%s",
280+
inUseNode, localNodeName, rscName));
274281
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
275282
}
276283
}
@@ -310,6 +317,23 @@ public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<S
310317
return true;
311318
}
312319

320+
private void removeTwoPrimariesRcProps(DevelopersApi api, String inUseNode, String rscName) throws ApiException {
321+
ResourceConnectionModify rcm = new ResourceConnectionModify();
322+
List<String> deleteProps = new ArrayList<>();
323+
deleteProps.add("DrbdOptions/Net/allow-two-primaries");
324+
deleteProps.add("DrbdOptions/Net/protocol");
325+
rcm.deleteProps(deleteProps);
326+
ApiCallRcList answers = api.resourceConnectionModify(rscName, localNodeName, inUseNode, rcm);
327+
if (answers.hasError()) {
328+
s_logger.error(
329+
String.format("Failed to remove 'protocol' and 'allow-two-primaries' on %s/%s/%s: %s",
330+
localNodeName,
331+
inUseNode,
332+
rscName, LinstorUtil.getBestErrorMessage(answers)));
333+
// do not fail here as removing allow-two-primaries property isn't fatal
334+
}
335+
}
336+
313337
private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
314338
{
315339
if (volumePath == null) {
@@ -339,27 +363,25 @@ private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
339363

340364

341365
if (optRsc.isPresent()) {
366+
Resource rsc = optRsc.get();
342367
try {
343-
Resource rsc = optRsc.get();
368+
String inUseNode = LinstorUtil.isResourceInUse(api, rsc.getName());
369+
if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
370+
removeTwoPrimariesRcProps(api, inUseNode, rsc.getName());
371+
}
372+
} catch (ApiException apiEx) {
373+
s_logger.error(apiEx.getBestMessage());
374+
// do not fail here as removing allow-two-primaries property or deleting diskless isn't fatal
375+
}
344376

377+
try {
345378
// if diskless resource remove it, in the worst case it will be transformed to a tiebreaker
346379
if (rsc.getFlags() != null &&
347380
rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS) &&
348381
!rsc.getFlags().contains(ApiConsts.FLAG_TIE_BREAKER)) {
349382
ApiCallRcList delAnswers = api.resourceDelete(rsc.getName(), localNodeName);
350383
logLinstorAnswers(delAnswers);
351384
}
352-
353-
// remove allow-two-primaries
354-
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
355-
rdm.deleteProps(Collections.singletonList("DrbdOptions/Net/allow-two-primaries"));
356-
ApiCallRcList answers = api.resourceDefinitionModify(rsc.getName(), rdm);
357-
if (answers.hasError()) {
358-
s_logger.error(
359-
String.format("Failed to remove 'allow-two-primaries' on %s: %s",
360-
rsc.getName(), LinstorUtil.getBestErrorMessage(answers)));
361-
// do not fail here as removing allow-two-primaries property isn't fatal
362-
}
363385
} catch (ApiException apiEx) {
364386
s_logger.error(apiEx.getBestMessage());
365387
// 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: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,20 @@ public static long getCapacityBytes(String linstorUrl, String rscGroupName) {
9797
*
9898
* @param api developer api object to use
9999
* @param rscName resource name to check in use state.
100-
* @return True if a resource found that is in use(primary) state, else false.
100+
* @return NodeName where the resource is inUse, if not in use `null`
101101
* @throws ApiException forwards api errors
102102
*/
103-
public static boolean isResourceInUse(DevelopersApi api, String rscName) throws ApiException {
103+
public static String isResourceInUse(DevelopersApi api, String rscName) throws ApiException {
104104
List<Resource> rscs = api.resourceList(rscName, null, null);
105105
if (rscs != null) {
106106
return rscs.stream()
107-
.anyMatch(rsc -> rsc.getState() != null && Boolean.TRUE.equals(rsc.getState().isInUse()));
108-
}
107+
.filter(rsc -> rsc.getState() != null && Boolean.TRUE.equals(rsc.getState().isInUse()))
108+
.map(Resource::getNodeName)
109+
.findFirst()
110+
.orElse(null);
111+
}
109112
s_logger.error("isResourceInUse: null returned from resourceList");
110-
return false;
113+
return null;
111114
}
112115

113116
/**

0 commit comments

Comments
 (0)