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

sureshanaparti pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/cloudstack-terraform-provider.git


The following commit(s) were added to refs/heads/main by this push:
     new 3ded431  fix: AND multiple filters in the pod and cluster data sources 
(#338)
3ded431 is described below

commit 3ded431e5cd0472b45337e6fb80402361e46b3a4
Author: Ramgopal Nagaboina <[email protected]>
AuthorDate: Thu Sep 3 10:22:27 2026 -0400

    fix: AND multiple filters in the pod and cluster data sources (#338)
    
    applyPodFilters and applyClusterFilters returned true as soon as any single
    filter matched, so a data source with two or more filter blocks selected a
    resource that matched only one of them (for example a pod matching the name
    filter but not the allocation_state filter). Every other data source in the
    provider (instance, volume, template, and others) requires all filters to
    match. Return false as soon as a filter does not match, and true only after
    all filters have matched. Adds unit tests for both.
    
    Signed-off-by: Ramgopal Nagaboina <[email protected]>
---
 cloudstack/data_source_cloudstack_cluster.go       |  6 +-
 cloudstack/data_source_cloudstack_pod.go           |  6 +-
 ...urce_cloudstack_pod_cluster_filter_unit_test.go | 85 ++++++++++++++++++++++
 3 files changed, 91 insertions(+), 6 deletions(-)

diff --git a/cloudstack/data_source_cloudstack_cluster.go 
b/cloudstack/data_source_cloudstack_cluster.go
index 35bdfe6..67568eb 100644
--- a/cloudstack/data_source_cloudstack_cluster.go
+++ b/cloudstack/data_source_cloudstack_cluster.go
@@ -348,10 +348,10 @@ func applyClusterFilters(cluster *cloudstack.Cluster, 
filters *schema.Set) (bool
                        return false
                }).String()
 
-               if r.MatchString(clusterField) {
-                       return true, nil
+               if !r.MatchString(clusterField) {
+                       return false, nil
                }
        }
 
-       return false, nil
+       return true, nil
 }
diff --git a/cloudstack/data_source_cloudstack_pod.go 
b/cloudstack/data_source_cloudstack_pod.go
index 77a8ca7..86bfa8d 100644
--- a/cloudstack/data_source_cloudstack_pod.go
+++ b/cloudstack/data_source_cloudstack_pod.go
@@ -272,10 +272,10 @@ func applyPodFilters(pod *cloudstack.Pod, filters 
*schema.Set) (bool, error) {
                        return false
                }).String()
 
-               if r.MatchString(podField) {
-                       return true, nil
+               if !r.MatchString(podField) {
+                       return false, nil
                }
        }
 
-       return false, nil
+       return true, nil
 }
diff --git a/cloudstack/data_source_cloudstack_pod_cluster_filter_unit_test.go 
b/cloudstack/data_source_cloudstack_pod_cluster_filter_unit_test.go
new file mode 100644
index 0000000..35ca776
--- /dev/null
+++ b/cloudstack/data_source_cloudstack_pod_cluster_filter_unit_test.go
@@ -0,0 +1,85 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package cloudstack
+
+import (
+       "testing"
+
+       "github.com/apache/cloudstack-go/v2/cloudstack"
+       "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+// filterSetForTest builds a *schema.Set of {name,value} filter blocks with a
+// content-based hash so distinct filters are not collapsed together.
+func filterSetForTest(pairs ...[2]string) *schema.Set {
+       hash := func(i interface{}) int {
+               m := i.(map[string]interface{})
+               return schema.HashString(m["name"].(string) + "|" + 
m["value"].(string))
+       }
+       items := make([]interface{}, 0, len(pairs))
+       for _, p := range pairs {
+               items = append(items, map[string]interface{}{"name": p[0], 
"value": p[1]})
+       }
+       return schema.NewSet(hash, items)
+}
+
+func TestApplyPodFiltersAreAndedNotOred(t *testing.T) {
+       pod := &cloudstack.Pod{Name: "pod-a", Allocationstate: "Enabled"}
+
+       // name matches but allocation_state does not: with AND semantics this 
must NOT match.
+       filters := filterSetForTest([2]string{"name", "pod-a"}, 
[2]string{"allocation_state", "Disabled"})
+       match, err := applyPodFilters(pod, filters)
+       if err != nil {
+               t.Fatalf("unexpected error: %s", err)
+       }
+       if match {
+               t.Errorf("pod matched only one of two filters but was selected; 
filters must be ANDed, not ORed")
+       }
+
+       // all filters match: must be selected.
+       filters = filterSetForTest([2]string{"name", "pod-a"}, 
[2]string{"allocation_state", "Enabled"})
+       match, err = applyPodFilters(pod, filters)
+       if err != nil {
+               t.Fatalf("unexpected error: %s", err)
+       }
+       if !match {
+               t.Errorf("pod matched all filters but was not selected")
+       }
+}
+
+func TestApplyClusterFiltersAreAndedNotOred(t *testing.T) {
+       cluster := &cloudstack.Cluster{Name: "cluster-a", Allocationstate: 
"Enabled"}
+
+       filters := filterSetForTest([2]string{"name", "cluster-a"}, 
[2]string{"allocation_state", "Disabled"})
+       match, err := applyClusterFilters(cluster, filters)
+       if err != nil {
+               t.Fatalf("unexpected error: %s", err)
+       }
+       if match {
+               t.Errorf("cluster matched only one of two filters but was 
selected; filters must be ANDed, not ORed")
+       }
+
+       filters = filterSetForTest([2]string{"name", "cluster-a"}, 
[2]string{"allocation_state", "Enabled"})
+       match, err = applyClusterFilters(cluster, filters)
+       if err != nil {
+               t.Fatalf("unexpected error: %s", err)
+       }
+       if !match {
+               t.Errorf("cluster matched all filters but was not selected")
+       }
+}

Reply via email to