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

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


The following commit(s) were added to refs/heads/4.20 by this push:
     new 8dcfc7c7678 Linstor fix host picking (#12047)
8dcfc7c7678 is described below

commit 8dcfc7c7678dadfe8f0d3974888871b53f2d48c7
Author: Rene Peinthor <[email protected]>
AuthorDate: Mon Jan 12 11:29:31 2026 +0100

    Linstor fix host picking (#12047)
---
 .../driver/LinstorPrimaryDataStoreDriverImpl.java  | 101 +++++++++++----------
 1 file changed, 55 insertions(+), 46 deletions(-)

diff --git 
a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java
 
b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java
index 306e9259936..c2bce6e5a04 100644
--- 
a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java
+++ 
b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/driver/LinstorPrimaryDataStoreDriverImpl.java
@@ -63,6 +63,8 @@ import com.cloud.api.storage.LinstorBackupSnapshotCommand;
 import com.cloud.api.storage.LinstorRevertBackupSnapshotCommand;
 import com.cloud.configuration.Config;
 import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.Status;
 import com.cloud.host.dao.HostDao;
 import com.cloud.resource.ResourceState;
 import com.cloud.storage.DataStoreRole;
@@ -921,9 +923,10 @@ public class LinstorPrimaryDataStoreDriverImpl implements 
PrimaryDataStoreDriver
             _backupsnapshotwait,
             VirtualMachineManager.ExecuteInSequence.value());
 
-        Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, 
rscName);
+        final StoragePool pool = (StoragePool) volumeInfo.getDataStore();
+        Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, pool, 
rscName);
         if (optEP.isEmpty()) {
-            optEP = getLinstorEP(linstorApi, rscName);
+            optEP = getLinstorEP(linstorApi, pool, rscName);
         }
 
         if (optEP.isPresent()) {
@@ -1063,13 +1066,29 @@ public class LinstorPrimaryDataStoreDriverImpl 
implements PrimaryDataStoreDriver
             Answer answer = copyVolume(srcData, dstData);
             res = new CopyCommandResult(null, answer);
         } else {
-            Answer answer = new Answer(null, false, "noimpl");
-            res = new CopyCommandResult(null, answer);
-            res.setResult("Not implemented yet");
+            throw new CloudRuntimeException("Not implemented for Linstor 
primary storage.");
         }
         callback.complete(res);
     }
 
+    private Host getEnabledClusterHost(StoragePool storagePool, List<String> 
linstorNodeNames) {
+        List<HostVO> csHosts;
+        if (storagePool.getClusterId() != null) {
+            csHosts = _hostDao.findByClusterId(storagePool.getClusterId());
+        } else {
+            csHosts = 
_hostDao.findByDataCenterId(storagePool.getDataCenterId());
+        }
+        Collections.shuffle(csHosts); // so we do not always pick the same 
host for operations
+        for (HostVO host : csHosts) {
+            if (host.getResourceState() == ResourceState.Enabled &&
+                    host.getStatus() == Status.Up &&
+                    linstorNodeNames.contains(host.getName())) {
+                return host;
+            }
+        }
+        return null;
+    }
+
     /**
      * Tries to get a Linstor cloudstack end point, that is at least diskless.
      *
@@ -1078,47 +1097,37 @@ public class LinstorPrimaryDataStoreDriverImpl 
implements PrimaryDataStoreDriver
      * @return Optional RemoteHostEndPoint if one could get found.
      * @throws ApiException
      */
-    private Optional<RemoteHostEndPoint> getLinstorEP(DevelopersApi api, 
String rscName) throws ApiException {
+    private Optional<RemoteHostEndPoint> getLinstorEP(DevelopersApi api, 
StoragePool storagePool, String rscName)
+            throws ApiException {
         List<String> linstorNodeNames = LinstorUtil.getLinstorNodeNames(api);
-        Collections.shuffle(linstorNodeNames);  // do not always pick the 
first linstor node
-
-        Host host = null;
-        for (String nodeName : linstorNodeNames) {
-            host = _hostDao.findByName(nodeName);
-            if (host != null && host.getResourceState() == 
ResourceState.Enabled) {
-                logger.info(String.format("Linstor: Make resource %s available 
on node %s ...", rscName, nodeName));
-                ApiCallRcList answers = 
api.resourceMakeAvailableOnNode(rscName, nodeName, new ResourceMakeAvailable());
-                if (!answers.hasError()) {
-                    break; // found working host
-                } else {
-                    logger.error(
-                        String.format("Linstor: Unable to make resource %s on 
node %s available: %s",
-                            rscName,
-                            nodeName,
-                            LinstorUtil.getBestErrorMessage(answers)));
-                }
+        Host host = getEnabledClusterHost(storagePool, linstorNodeNames);
+        if (host != null) {
+            logger.info("Linstor: Make resource {} available on node {} ...", 
rscName, host.getName());
+            ApiCallRcList answers = api.resourceMakeAvailableOnNode(
+                    rscName, host.getName(), new ResourceMakeAvailable());
+            if (answers.hasError()) {
+                logger.error("Linstor: Unable to make resource {} on node {} 
available: {}",
+                        rscName, host.getName(), 
LinstorUtil.getBestErrorMessage(answers));
+                return Optional.empty();
+            } else {
+                return 
Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
             }
         }
 
-        if (host == null)
-        {
-            logger.error("Linstor: Couldn't create a resource on any 
cloudstack host.");
-            return Optional.empty();
-        }
-        else
-        {
-            return 
Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
-        }
+        logger.error("Linstor: Couldn't create a resource on any cloudstack 
host.");
+        return Optional.empty();
     }
 
-    private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, 
String rscName) throws ApiException {
+    private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, 
StoragePool storagePool, String rscName)
+            throws ApiException {
         List<com.linbit.linstor.api.model.StoragePool> linSPs = 
LinstorUtil.getDiskfulStoragePools(api, rscName);
         if (linSPs != null) {
-            for (com.linbit.linstor.api.model.StoragePool sp : linSPs) {
-                Host host = _hostDao.findByName(sp.getNodeName());
-                if (host != null && host.getResourceState() == 
ResourceState.Enabled) {
-                    return 
Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
-                }
+            List<String> linstorNodeNames = linSPs.stream()
+                    .map(com.linbit.linstor.api.model.StoragePool::getNodeName)
+                    .collect(Collectors.toList());
+            Host host = getEnabledClusterHost(storagePool, linstorNodeNames);
+            if (host != null) {
+                return 
Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
             }
         }
         logger.error("Linstor: No diskfull host found.");
@@ -1199,12 +1208,12 @@ public class LinstorPrimaryDataStoreDriverImpl 
implements PrimaryDataStoreDriver
                     VirtualMachineManager.ExecuteInSequence.value());
 
             try {
-                Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, 
rscName);
+                Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, 
rscName);
                 if (optEP.isPresent()) {
                     answer = optEP.get().sendMessage(cmd);
                 } else {
-                    answer = new Answer(cmd, false, "Unable to get matching 
Linstor endpoint.");
                     deleteResourceDefinition(pool, rscName);
+                    throw new CloudRuntimeException("Unable to get matching 
Linstor endpoint.");
                 }
             } catch (ApiException exc) {
                 logger.error("copy template failed: ", exc);
@@ -1241,12 +1250,12 @@ public class LinstorPrimaryDataStoreDriverImpl 
implements PrimaryDataStoreDriver
         Answer answer;
 
         try {
-            Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
+            Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, 
rscName);
             if (optEP.isPresent()) {
                 answer = optEP.get().sendMessage(cmd);
             }
             else {
-                answer = new Answer(cmd, false, "Unable to get matching 
Linstor endpoint.");
+                throw new CloudRuntimeException("Unable to get matching 
Linstor endpoint.");
             }
         } catch (ApiException exc) {
             logger.error("copy volume failed: ", exc);
@@ -1279,14 +1288,14 @@ public class LinstorPrimaryDataStoreDriverImpl 
implements PrimaryDataStoreDriver
         try {
             String devName = restoreResourceFromSnapshot(api, pool, rscName, 
snapshotName, restoreName);
 
-            Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, 
restoreName);
+            Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, pool, 
restoreName);
             if (optEPAny.isPresent()) {
                 // patch the src device path to the temporary linstor resource
                 snapshotObject.setPath(devName);
                 origCmd.setSrcTO(snapshotObject.getTO());
                 answer = optEPAny.get().sendMessage(origCmd);
-            } else{
-                answer = new Answer(origCmd, false, "Unable to get matching 
Linstor endpoint.");
+            } else {
+                throw new CloudRuntimeException("Unable to get matching 
Linstor endpoint.");
             }
         } finally {
             // delete the temporary resource, noop if already gone
@@ -1348,7 +1357,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements 
PrimaryDataStoreDriver
                 VirtualMachineManager.ExecuteInSequence.value());
             cmd.setOptions(options);
 
-            Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
+            Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, pool, 
rscName);
             Answer answer;
             if (optEP.isPresent()) {
                 answer = optEP.get().sendMessage(cmd);

Reply via email to