From 02f9daaf7e7e4b5cf3778fc5978921da3b271eb1 Mon Sep 17 00:00:00 2001 From: Ramgopal Nagaboina Date: Mon, 7 Sep 2026 15:42:42 -0400 Subject: [PATCH] fix: store the cidr set in the managed egress firewall dummy rule For a managed egress firewall, Read collects unknown rules into a dummy rule, but stored the uuid string in cidr_list, which is a schema.TypeSet and must hold a *schema.Set. It builds one (cidrs) right above for this, so use it. With the string, reading a managed egress firewall panics with interface conversion: interface {} is string, not *schema.Set. --- .../resource_cloudstack_egress_firewall.go | 2 +- ...ce_cloudstack_egress_firewall_unit_test.go | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 cloudstack/resource_cloudstack_egress_firewall_unit_test.go diff --git a/cloudstack/resource_cloudstack_egress_firewall.go b/cloudstack/resource_cloudstack_egress_firewall.go index beec0bd0..f5f7843b 100644 --- a/cloudstack/resource_cloudstack_egress_firewall.go +++ b/cloudstack/resource_cloudstack_egress_firewall.go @@ -421,7 +421,7 @@ func resourceCloudStackEgressFirewallRead(d *schema.ResourceData, meta interface // Make a dummy rule to hold the unknown UUID rule := map[string]interface{}{ - "cidr_list": uuid, + "cidr_list": cidrs, "protocol": uuid, "uuids": map[string]interface{}{uuid: uuid}, } diff --git a/cloudstack/resource_cloudstack_egress_firewall_unit_test.go b/cloudstack/resource_cloudstack_egress_firewall_unit_test.go new file mode 100644 index 00000000..05c03580 --- /dev/null +++ b/cloudstack/resource_cloudstack_egress_firewall_unit_test.go @@ -0,0 +1,64 @@ +// +// 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 ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/apache/cloudstack-go/v2/cloudstack" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// For a managed egress firewall, Read collects unknown rules into a dummy rule. +// cidr_list is a schema.TypeSet, so its value must be a *schema.Set. The dummy +// rule stored the uuid string there instead, which corrupts the rule set and +// later panics when createEgressFirewallRule asserts cidr_list as *schema.Set. +func TestEgressFirewallReadManagedDummyRuleCidrListIsSet(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"listegressfirewallrulesresponse":{"count":1,"firewallrule":[{"id":"rule-1","protocol":"tcp","cidrlist":"10.0.0.0/8","startport":80,"endport":80}]}}`)) + })) + defer server.Close() + + cs := cloudstack.NewClient(server.URL, "key", "secret", false) + + d := schema.TestResourceDataRaw(t, resourceCloudStackEgressFirewall().Schema, map[string]interface{}{ + "managed": true, + }) + d.SetId("net-1") + + if err := resourceCloudStackEgressFirewallRead(d, cs); err != nil { + t.Fatalf("read of a managed egress firewall should not error, got: %s", err) + } + + rules := d.Get("rule").(*schema.Set) + if rules.Len() != 1 { + t.Fatalf("expected one managed dummy rule, got %d", rules.Len()) + } + + for _, raw := range rules.List() { + rule := raw.(map[string]interface{}) + if _, ok := rule["cidr_list"].(*schema.Set); !ok { + t.Fatalf("dummy rule cidr_list must be a *schema.Set, got %T", rule["cidr_list"]) + } + } +}