This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch 4.18
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.18 by this push:
     new 537c0a1e8d2 linstor: set/unset allow-two-primaries and protocol on rc 
level (#9560)
537c0a1e8d2 is described below

commit 537c0a1e8d2cbe12f3e510d6b51babd6486f4c3e
Author: Rene Peinthor <[email protected]>
AuthorDate: Tue Sep 3 13:01:07 2024 +0200

    linstor: set/unset allow-two-primaries and protocol on rc level (#9560)
---
 plugins/storage/volume/linstor/CHANGELOG.md        | 12 +++++
 .../kvm/storage/LinstorStorageAdaptor.java         | 58 +++++++++++++++-------
 .../storage/datastore/util/LinstorUtil.java        | 13 +++--
 3 files changed, 60 insertions(+), 23 deletions(-)

diff --git a/plugins/storage/volume/linstor/CHANGELOG.md 
b/plugins/storage/volume/linstor/CHANGELOG.md
new file mode 100644
index 00000000000..30f0225b45e
--- /dev/null
+++ b/plugins/storage/volume/linstor/CHANGELOG.md
@@ -0,0 +1,12 @@
+# Changelog
+
+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/),
+and this project adheres to [Semantic 
Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [2024-08-27]
+
+### Changed
+
+- Allow two primaries(+protocol c) is now set on resource-connection level 
instead of rd
diff --git 
a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java
 
b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java
index b17c768b96a..0ae65573d2b 100644
--- 
a/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java
+++ 
b/plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java
@@ -19,6 +19,8 @@ package com.cloud.hypervisor.kvm.storage;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -37,6 +39,7 @@ import org.libvirt.LibvirtException;
 
 import com.cloud.storage.Storage;
 import com.cloud.utils.exception.CloudRuntimeException;
+
 import com.linbit.linstor.api.ApiClient;
 import com.linbit.linstor.api.ApiConsts;
 import com.linbit.linstor.api.ApiException;
@@ -47,8 +50,8 @@ import com.linbit.linstor.api.model.ApiCallRcList;
 import com.linbit.linstor.api.model.Properties;
 import com.linbit.linstor.api.model.ProviderKind;
 import com.linbit.linstor.api.model.Resource;
+import com.linbit.linstor.api.model.ResourceConnectionModify;
 import com.linbit.linstor.api.model.ResourceDefinition;
-import com.linbit.linstor.api.model.ResourceDefinitionModify;
 import com.linbit.linstor.api.model.ResourceGroup;
 import com.linbit.linstor.api.model.ResourceGroupSpawn;
 import com.linbit.linstor.api.model.ResourceMakeAvailable;
@@ -262,15 +265,19 @@ public class LinstorStorageAdaptor implements 
StorageAdaptor {
      * @throws ApiException if any problem connecting to the Linstor controller
      */
     private void allow2PrimariesIfInUse(DevelopersApi api, String rscName) 
throws ApiException {
-        if (LinstorUtil.isResourceInUse(api, rscName)) {
+        String inUseNode = LinstorUtil.isResourceInUse(api, rscName);
+        if (inUseNode != null && !inUseNode.equalsIgnoreCase(localNodeName)) {
             // allow 2 primaries for live migration, should be removed by 
disconnect on the other end
-            ResourceDefinitionModify rdm = new ResourceDefinitionModify();
+            ResourceConnectionModify rcm = new ResourceConnectionModify();
             Properties props = new Properties();
             props.put("DrbdOptions/Net/allow-two-primaries", "yes");
-            rdm.setOverrideProps(props);
-            ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
+            props.put("DrbdOptions/Net/protocol", "C");
+            rcm.setOverrideProps(props);
+            ApiCallRcList answers = api.resourceConnectionModify(rscName, 
inUseNode, localNodeName, rcm);
             if (answers.hasError()) {
-                s_logger.error("Unable to set 'allow-two-primaries' on " + 
rscName);
+                s_logger.error(String.format(
+                        "Unable to set protocol C and 'allow-two-primaries' on 
%s/%s/%s",
+                        inUseNode, localNodeName, rscName));
                 // do not fail here as adding allow-two-primaries property is 
only a problem while live migrating
             }
         }
@@ -310,6 +317,23 @@ public class LinstorStorageAdaptor implements 
StorageAdaptor {
         return true;
     }
 
+    private void removeTwoPrimariesRcProps(DevelopersApi api, String 
inUseNode, String rscName) throws ApiException {
+        ResourceConnectionModify rcm = new ResourceConnectionModify();
+        List<String> deleteProps = new ArrayList<>();
+        deleteProps.add("DrbdOptions/Net/allow-two-primaries");
+        deleteProps.add("DrbdOptions/Net/protocol");
+        rcm.deleteProps(deleteProps);
+        ApiCallRcList answers = api.resourceConnectionModify(rscName, 
localNodeName, inUseNode, rcm);
+        if (answers.hasError()) {
+            s_logger.error(
+                    String.format("Failed to remove 'protocol' and 
'allow-two-primaries' on %s/%s/%s: %s",
+                            localNodeName,
+                            inUseNode,
+                            rscName, 
LinstorUtil.getBestErrorMessage(answers)));
+            // do not fail here as removing allow-two-primaries property isn't 
fatal
+        }
+    }
+
     private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool 
pool)
     {
         if (volumePath == null) {
@@ -339,9 +363,18 @@ public class LinstorStorageAdaptor implements 
StorageAdaptor {
 
 
         if (optRsc.isPresent()) {
+            Resource rsc = optRsc.get();
             try {
-                Resource rsc = optRsc.get();
+                String inUseNode = LinstorUtil.isResourceInUse(api, 
rsc.getName());
+                if (inUseNode != null && 
!inUseNode.equalsIgnoreCase(localNodeName)) {
+                    removeTwoPrimariesRcProps(api, inUseNode, rsc.getName());
+                }
+            } catch (ApiException apiEx) {
+                s_logger.error(apiEx.getBestMessage());
+                // do not fail here as removing allow-two-primaries property 
or deleting diskless isn't fatal
+            }
 
+            try {
                 // if diskless resource remove it, in the worst case it will 
be transformed to a tiebreaker
                 if (rsc.getFlags() != null &&
                         rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS) 
&&
@@ -349,17 +382,6 @@ public class LinstorStorageAdaptor implements 
StorageAdaptor {
                     ApiCallRcList delAnswers = 
api.resourceDelete(rsc.getName(), localNodeName);
                     logLinstorAnswers(delAnswers);
                 }
-
-                // remove allow-two-primaries
-                ResourceDefinitionModify rdm = new ResourceDefinitionModify();
-                
rdm.deleteProps(Collections.singletonList("DrbdOptions/Net/allow-two-primaries"));
-                ApiCallRcList answers = 
api.resourceDefinitionModify(rsc.getName(), rdm);
-                if (answers.hasError()) {
-                    s_logger.error(
-                            String.format("Failed to remove 
'allow-two-primaries' on %s: %s",
-                                    rsc.getName(), 
LinstorUtil.getBestErrorMessage(answers)));
-                    // do not fail here as removing allow-two-primaries 
property isn't fatal
-                }
             } catch (ApiException apiEx) {
                 s_logger.error(apiEx.getBestMessage());
                 // do not fail here as removing allow-two-primaries property 
or deleting diskless isn't fatal
diff --git 
a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java
 
b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java
index 9f4dbae7835..db2b5d1ea0b 100644
--- 
a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java
+++ 
b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java
@@ -97,17 +97,20 @@ public class LinstorUtil {
      *
      * @param api developer api object to use
      * @param rscName resource name to check in use state.
-     * @return True if a resource found that is in use(primary) state, else 
false.
+     * @return NodeName where the resource is inUse, if not in use `null`
      * @throws ApiException forwards api errors
      */
-    public static boolean isResourceInUse(DevelopersApi api, String rscName) 
throws ApiException {
+    public static String isResourceInUse(DevelopersApi api, String rscName) 
throws ApiException {
         List<Resource> rscs = api.resourceList(rscName, null, null);
         if (rscs != null) {
             return rscs.stream()
-                    .anyMatch(rsc -> rsc.getState() != null && 
Boolean.TRUE.equals(rsc.getState().isInUse()));
-        }
+                    .filter(rsc -> rsc.getState() != null && 
Boolean.TRUE.equals(rsc.getState().isInUse()))
+                    .map(Resource::getNodeName)
+                    .findFirst()
+                    .orElse(null);
+       }
         s_logger.error("isResourceInUse: null returned from resourceList");
-        return false;
+        return null;
     }
 
     /**

Reply via email to