Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ website/vendor
!command/test-fixtures/**/.terraform/
.terraform.lock.hcl
provider.tf
.worktrees/
.env
134 changes: 71 additions & 63 deletions cloudstack/resource_cloudstack_egress_firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
}
}
}
}
Expand Down
13 changes: 8 additions & 5 deletions website/docs/r/egress_firewall.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
}
}
```
Expand All @@ -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.
Expand Down