From 405aac38bc949db8467cc789a0ecfc9b4c55cd15 Mon Sep 17 00:00:00 2001 From: Rene Peinthor Date: Mon, 22 Apr 2024 10:04:05 +0200 Subject: [PATCH] linstor: Only set allow-two-primaries if resource is already in use (#8802) For live migrate we need the allow-two-primaries option, but we don't know exactly if we are called for a migration operation. Now also check if at least any of the resources is in use somewhere and only then set the option. --- .../kvm/storage/LinstorStorageAdaptor.java | 33 +++++++++++++------ .../storage/datastore/util/LinstorUtil.java | 19 +++++++++++ 2 files changed, 42 insertions(+), 10 deletions(-) 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 9ad8332d0e1..66278f827f7 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 @@ -260,6 +260,28 @@ public class LinstorStorageAdaptor implements StorageAdaptor { } } + /** + * Checks if the given resource is in use by drbd on any host and + * if so set the drbd option allow-two-primaries + * @param api linstor api object + * @param rscName resource name to set allow-two-primaries if in use + * @throws ApiException if any problem connecting to the Linstor controller + */ + private void allow2PrimariesIfInUse(DevelopersApi api, String rscName) throws ApiException { + if (LinstorUtil.isResourceInUse(api, rscName)) { + // allow 2 primaries for live migration, should be removed by disconnect on the other end + ResourceDefinitionModify rdm = new ResourceDefinitionModify(); + Properties props = new Properties(); + props.put("DrbdOptions/Net/allow-two-primaries", "yes"); + rdm.setOverrideProps(props); + ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm); + if (answers.hasError()) { + s_logger.error("Unable to set 'allow-two-primaries' on " + rscName); + // do not fail here as adding allow-two-primaries property is only a problem while live migrating + } + } + } + @Override public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map details) { @@ -286,16 +308,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor { try { - // allow 2 primaries for live migration, should be removed by disconnect on the other end - ResourceDefinitionModify rdm = new ResourceDefinitionModify(); - Properties props = new Properties(); - props.put("DrbdOptions/Net/allow-two-primaries", "yes"); - rdm.setOverrideProps(props); - ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm); - if (answers.hasError()) { - s_logger.error("Unable to set 'allow-two-primaries' on " + rscName); - // do not fail here as adding allow-two-primaries property is only a problem while live migrating - } + allow2PrimariesIfInUse(api, rscName); } catch (ApiException apiEx) { s_logger.error(apiEx); // do not fail here as adding allow-two-primaries property is only a problem while live migrating 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 cc85c9834eb..c8544fd3e3e 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 @@ -23,6 +23,7 @@ import com.linbit.linstor.api.DevelopersApi; import com.linbit.linstor.api.model.ApiCallRc; import com.linbit.linstor.api.model.ApiCallRcList; import com.linbit.linstor.api.model.ProviderKind; +import com.linbit.linstor.api.model.Resource; import com.linbit.linstor.api.model.ResourceGroup; import com.linbit.linstor.api.model.StoragePool; @@ -90,4 +91,22 @@ public class LinstorUtil { throw new CloudRuntimeException(apiEx); } } + + /** + * Check if any resource of the given name is InUse on any host. + * + * @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. + * @throws ApiException forwards api errors + */ + public static boolean isResourceInUse(DevelopersApi api, String rscName) throws ApiException { + List rscs = api.resourceList(rscName, null, null); + if (rscs != null) { + return rscs.stream() + .anyMatch(rsc -> rsc.getState() != null && Boolean.TRUE.equals(rsc.getState().isInUse())); + } + s_logger.error("isResourceInUse: null returned from resourceList"); + return false; + } }