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 edf76e1 Feature: Add dest_cidr_list support to egress firewall (#298)
edf76e1 is described below
commit edf76e19d9bd09f8a3515e5e60a9122101dae70e
Author: Elias Flötzinger <[email protected]>
AuthorDate: Mon Aug 17 13:12:32 2026 +0200
Feature: Add dest_cidr_list support to egress firewall (#298)
* chore: add .worktrees to .gitignore
* feat: add dest_cidr_list support to cloudstack_egress_firewall
Adds the destcidrlist parameter to egress firewall rules, allowing
users to restrict the destination of egress traffic. The field is
optional and maps to the CloudStack API's destcidrlist parameter.
Fixes #296
* refactor: simplify egress firewall read with cidrSetFromList helper
Restructure resourceCloudStackEgressFirewallRead to use a switch on the
protocol and extract the repeated CIDR set-building into a single
cidrSetFromList helper.
The helper returns an empty set for an empty list, restoring the guard
against empty Destcidrlist consistently across all branches.
Verified with the egress firewall acceptance tests against the
cloudstack simulator.
* docs: add dest_cidr_list example and 'all' protocol to egress firewall
---
.gitignore | 2 +
cloudstack/resource_cloudstack_egress_firewall.go | 134 ++++++++++++----------
website/docs/r/egress_firewall.html.markdown | 13 ++-
3 files changed, 81 insertions(+), 68 deletions(-)
diff --git a/.gitignore b/.gitignore
index b6b0f36..2c88f78 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,5 @@ website/vendor
!command/test-fixtures/**/.terraform/
.terraform.lock.hcl
provider.tf
+.worktrees/
+.env
diff --git a/cloudstack/resource_cloudstack_egress_firewall.go
b/cloudstack/resource_cloudstack_egress_firewall.go
index e2a83e4..beec0bd 100644
--- a/cloudstack/resource_cloudstack_egress_firewall.go
+++ b/cloudstack/resource_cloudstack_egress_firewall.go
@@ -70,6 +70,13 @@ func resourceCloudStackEgressFirewall() *schema.Resource {
Set:
schema.HashString,
},
+ "dest_cidr_list": {
+ Type:
schema.TypeSet,
+ Optional: true,
+ Elem:
&schema.Schema{Type: schema.TypeString},
+ Set:
schema.HashString,
+ },
+
"protocol": {
Type:
schema.TypeString,
Required: true,
@@ -194,6 +201,15 @@ func createEgressFirewallRule(d *schema.ResourceData, meta
interface{}, rule map
p.SetCidrlist(cidrList)
}
+ // Set the destination CIDR list
+ if rs, ok := rule["dest_cidr_list"].(*schema.Set); ok && rs.Len() > 0 {
+ var destCidrList []string
+ for _, cidr := range
rule["dest_cidr_list"].(*schema.Set).List() {
+ destCidrList = append(destCidrList, cidr.(string))
+ }
+ p.SetDestcidrlist(destCidrList)
+ }
+
// If the protocol is ICMP set the needed ICMP parameters
if rule["protocol"].(string) == "icmp" {
p.SetIcmptype(rule["icmp_type"].(int))
@@ -264,6 +280,19 @@ func createEgressFirewallRule(d *schema.ResourceData, meta
interface{}, rule map
return nil
}
+// cidrSetFromList builds a schema.Set of CIDRs from a comma-separated list,
+// returning an empty set when the list is empty.
+func cidrSetFromList(list string) *schema.Set {
+ set := &schema.Set{F: schema.HashString}
+ if list == "" {
+ return set
+ }
+ for _, cidr := range strings.Split(list, ",") {
+ set.Add(cidr)
+ }
+ return set
+}
+
func resourceCloudStackEgressFirewallRead(d *schema.ResourceData, meta
interface{}) error {
cs := meta.(*cloudstack.CloudStackClient)
@@ -297,7 +326,10 @@ func resourceCloudStackEgressFirewallRead(d
*schema.ResourceData, meta interface
rule := rule.(map[string]interface{})
uuids := rule["uuids"].(map[string]interface{})
- if rule["protocol"].(string) == "icmp" {
+ protocol := strings.ToLower(rule["protocol"].(string))
+
+ switch protocol {
+ case "icmp":
id, ok := uuids["icmp"]
if !ok {
continue
@@ -313,64 +345,14 @@ func resourceCloudStackEgressFirewallRead(d
*schema.ResourceData, meta interface
// Delete the known rule so only unknown rules
remain in the ruleMap
delete(ruleMap, id.(string))
- // Create a set with all CIDR's
- cidrs := &schema.Set{F: schema.HashString}
- for _, cidr := range strings.Split(r.Cidrlist,
",") {
- cidrs.Add(cidr)
- }
-
// Update the values
rule["protocol"] = r.Protocol
rule["icmp_type"] = r.Icmptype
rule["icmp_code"] = r.Icmpcode
- rule["cidr_list"] = cidrs
+ rule["cidr_list"] = cidrSetFromList(r.Cidrlist)
+ rule["dest_cidr_list"] =
cidrSetFromList(r.Destcidrlist)
rules.Add(rule)
- }
-
- // If protocol is not ICMP, loop through all ports
- if rule["protocol"].(string) != "icmp" &&
strings.ToLower(rule["protocol"].(string)) != "all" {
- if ps := rule["ports"].(*schema.Set); ps.Len()
> 0 {
-
- // Create an empty schema.Set to hold
all ports
- ports := &schema.Set{F:
schema.HashString}
-
- // Loop through all ports and retrieve
their info
- for _, port := range ps.List() {
- id, ok := uuids[port.(string)]
- if !ok {
- continue
- }
-
- // Get the rule
- r, ok := ruleMap[id.(string)]
- if !ok {
- delete(uuids,
port.(string))
- continue
- }
-
- // Delete the known rule so
only unknown rules remain in the ruleMap
- delete(ruleMap, id.(string))
-
- // Create a set with all CIDR's
- cidrs := &schema.Set{F:
schema.HashString}
- for _, cidr := range
strings.Split(r.Cidrlist, ",") {
- cidrs.Add(cidr)
- }
-
- // Update the values
- rule["protocol"] = r.Protocol
- rule["cidr_list"] = cidrs
- ports.Add(port)
- }
-
- // If there is at least one port found,
add this rule to the rules set
- if ports.Len() > 0 {
- rule["ports"] = ports
- rules.Add(rule)
- }
- }
- }
- if strings.ToLower(rule["protocol"].(string)) == "all" {
+ case "all":
id, ok := uuids["all"]
if !ok {
continue
@@ -386,18 +368,44 @@ func resourceCloudStackEgressFirewallRead(d
*schema.ResourceData, meta interface
// Delete the known rule so only unknown rules
remain in the ruleMap
delete(ruleMap, id.(string))
- // Create a set with all CIDR's
- if _, ok := rule["cidr_list"]; ok {
- cidrs := &schema.Set{F:
schema.HashString}
- for _, cidr := range
strings.Split(r.Cidrlist, ",") {
- cidrs.Add(cidr)
- }
- rule["cidr_list"] = cidrs
- }
-
// Update the values
rule["protocol"] = r.Protocol
+ rule["cidr_list"] = cidrSetFromList(r.Cidrlist)
+ rule["dest_cidr_list"] =
cidrSetFromList(r.Destcidrlist)
rules.Add(rule)
+ default:
+ // Create an empty schema.Set to hold all ports
+ ports := &schema.Set{F: schema.HashString}
+
+ // Loop through all ports and retrieve their
info
+ for _, port := range
rule["ports"].(*schema.Set).List() {
+ id, ok := uuids[port.(string)]
+ if !ok {
+ continue
+ }
+
+ // Get the rule
+ r, ok := ruleMap[id.(string)]
+ if !ok {
+ delete(uuids, port.(string))
+ continue
+ }
+
+ // Delete the known rule so only
unknown rules remain in the ruleMap
+ delete(ruleMap, id.(string))
+
+ // Update the values
+ rule["protocol"] = r.Protocol
+ rule["cidr_list"] =
cidrSetFromList(r.Cidrlist)
+ rule["dest_cidr_list"] =
cidrSetFromList(r.Destcidrlist)
+ ports.Add(port)
+ }
+
+ // If there is at least one port found, add
this rule to the rules set
+ if ports.Len() > 0 {
+ rule["ports"] = ports
+ rules.Add(rule)
+ }
}
}
}
diff --git a/website/docs/r/egress_firewall.html.markdown
b/website/docs/r/egress_firewall.html.markdown
index 10badd1..dde7406 100644
--- a/website/docs/r/egress_firewall.html.markdown
+++ b/website/docs/r/egress_firewall.html.markdown
@@ -17,9 +17,10 @@ resource "cloudstack_egress_firewall" "default" {
network_id = "6eb22f91-7454-4107-89f4-36afcdf33021"
rule {
- cidr_list = ["10.0.0.0/8"]
- protocol = "tcp"
- ports = ["80", "1000-2000"]
+ cidr_list = ["10.0.0.0/8"]
+ dest_cidr_list = ["192.168.0.0/16"]
+ protocol = "tcp"
+ ports = ["80", "1000-2000"]
}
}
```
@@ -43,10 +44,12 @@ The following arguments are supported:
The `rule` block supports:
-* `cidr_list` - (Required) A CIDR list to allow access to the given ports.
+* `cidr_list` - (Optional) A CIDR list to allow access to the given ports.
+
+* `dest_cidr_list` - (Optional) A CIDR list to restrict the destination of
egress traffic.
* `protocol` - (Required) The name of the protocol to allow. Valid options are:
- `tcp`, `udp` and `icmp`.
+ `tcp`, `udp`, `icmp` and `all`.
* `icmp_type` - (Optional) The ICMP type to allow. This can only be specified
if
the protocol is ICMP.