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")
+ }
+}