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

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


The following commit(s) were added to refs/heads/main by this push:
     new 6786d45951a fix(linstor): surface ambiguous template fallbacks and 
legacy orphan cleanup (#13078)
6786d45951a is described below

commit 6786d45951a5faf26ce3caa7fffecb880bbfd5e0
Author: James Peru Mmbono <[email protected]>
AuthorDate: Wed May 27 15:09:32 2026 +0300

    fix(linstor): surface ambiguous template fallbacks and legacy orphan 
cleanup (#13078)
    
    Co-authored-by: jmsperu <[email protected]>
---
 .../kvm/storage/LinstorStorageAdaptor.java          | 14 ++++++++++++--
 .../storage/datastore/util/LinstorUtil.java         | 21 ++++++++++++++++++++-
 2 files changed, 32 insertions(+), 3 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 31a41cd9407..32858108d6a 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
@@ -508,9 +508,19 @@ public class LinstorStorageAdaptor implements 
StorageAdaptor {
             // if there is only one template-for property left for templates, 
the template isn't needed anymore
             // or if it isn't a template anyway, it will not have this Aux 
property
             // _cs-template-for- properties work like a ref-count.
-            if (rd.getProps().keySet().stream()
+            long remainingTemplateRefs = rd.getProps().keySet().stream()
                     .filter(key -> key.startsWith("Aux/" + 
LinstorUtil.CS_TEMPLATE_FOR_PREFIX))
-                    .count() == expectedProps) {
+                    .count();
+            if (remainingTemplateRefs == expectedProps) {
+                // Surface the legacy case where a resource has zero 
`_cs-template-for-` aux
+                // properties even though we never decremented one — that's a 
template predating
+                // the ref-count convention, or a stale orphan. Logging before 
deletion lets
+                // operators audit how many such orphans existed at upgrade 
time.
+                if (expectedProps == 0) {
+                    logger.info("Linstor: deleting resource {} which has no 
_cs-template-for- aux properties " +
+                                    "(legacy template predating the ref-count 
convention, or a stale orphan). " +
+                                    "Resource group context: {}", 
rd.getName(), rscGrpName);
+                }
                 ApiCallRcList answers = 
api.resourceDefinitionDelete(rd.getName());
                 checkLinstorAnswersThrow(answers);
                 deleted = true;
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 239331077e1..502bf6d0ca2 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
@@ -543,7 +543,26 @@ public class LinstorUtil {
                 .filter(rscDfn -> 
rscDfn.getProps().containsKey(LinstorUtil.getTemplateForAuxPropKey(rscGrpName)))
                 .findFirst();
 
-        return rd.orElseGet(() -> rdsStartingWith.get(0));
+        if (rd.isPresent()) {
+            return rd.get();
+        }
+        // Fallback: no resource has the exact "_cs-template-for-<rscGrpName>" 
property.
+        // This happens when (a) the matched resource is a legacy template 
created before that
+        // convention was introduced, or (b) the template was cached by a 
different resource
+        // group and the operator hopes to share it. Log so the ambiguity is 
visible — silent
+        // first-match fallback has previously routed clones to the wrong 
template when
+        // multiple resource groups coexisted on the same controller.
+        ResourceDefinition fallback = rdsStartingWith.get(0);
+        LOGGER.warn("LINSTOR findResourceDefinition: no resource for '{}' has 
the expected " +
+                        "Aux property '{}' for resource group '{}'; falling 
back to first match '{}' " +
+                        "(present aux properties: {}). If this is wrong, set 
the property explicitly " +
+                        "or remove the unrelated resource definition.",
+                rscName, getTemplateForAuxPropKey(rscGrpName), rscGrpName,
+                fallback.getName(),
+                fallback.getProps().keySet().stream()
+                        .filter(k -> k.startsWith("Aux/" + 
CS_TEMPLATE_FOR_PREFIX))
+                        .collect(Collectors.toList()));
+        return fallback;
     }
 
     public static boolean isRscDiskless(ResourceWithVolumes rsc) {

Reply via email to