Refactored the firewall resource in order to better handle the various possible changes in configuration
This commit is contained in:
parent
c92e6612a1
commit
31b12a007f
|
@ -1,16 +1,14 @@
|
||||||
package digitalocean
|
package digitalocean
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/digitalocean/godo"
|
"github.com/digitalocean/godo"
|
||||||
"github.com/hashicorp/terraform/helper/hashcode"
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/helper/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resourceDigitalOceanFirewall() *schema.Resource {
|
func resourceDigitalOceanFirewall() *schema.Resource {
|
||||||
|
@ -19,12 +17,113 @@ func resourceDigitalOceanFirewall() *schema.Resource {
|
||||||
Read: resourceDigitalOceanFirewallRead,
|
Read: resourceDigitalOceanFirewallRead,
|
||||||
Update: resourceDigitalOceanFirewallUpdate,
|
Update: resourceDigitalOceanFirewallUpdate,
|
||||||
Delete: resourceDigitalOceanFirewallDelete,
|
Delete: resourceDigitalOceanFirewallDelete,
|
||||||
Exists: resourceDigitalOceanFirewallExists,
|
|
||||||
Importer: &schema.ResourceImporter{
|
Importer: &schema.ResourceImporter{
|
||||||
State: schema.ImportStatePassthrough,
|
State: schema.ImportStatePassthrough,
|
||||||
},
|
},
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.NoZeroValues,
|
||||||
|
},
|
||||||
|
|
||||||
|
"droplet_ids": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeInt},
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"inbound_rule": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"protocol": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{
|
||||||
|
"tcp",
|
||||||
|
"udp",
|
||||||
|
"icmp",
|
||||||
|
}, false),
|
||||||
|
},
|
||||||
|
"port_range": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validation.NoZeroValues,
|
||||||
|
},
|
||||||
|
"source_addresses": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
ValidateFunc: validation.NoZeroValues,
|
||||||
|
},
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"source_droplet_ids": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeInt},
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"source_load_balancer_uids": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
ValidateFunc: validation.NoZeroValues,
|
||||||
|
},
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"source_tags": tagsSchema(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"outbound_rule": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"protocol": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ValidateFunc: validation.StringInSlice([]string{
|
||||||
|
"tcp",
|
||||||
|
"udp",
|
||||||
|
"icmp",
|
||||||
|
}, false),
|
||||||
|
},
|
||||||
|
"port_range": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ValidateFunc: validation.NoZeroValues,
|
||||||
|
},
|
||||||
|
"destination_addresses": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
ValidateFunc: validation.NoZeroValues,
|
||||||
|
},
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"destination_droplet_ids": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeInt},
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"destination_load_balancer_uids": {
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
ValidateFunc: validation.NoZeroValues,
|
||||||
|
},
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"destination_tags": tagsSchema(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
"status": {
|
"status": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
|
@ -56,105 +155,40 @@ func resourceDigitalOceanFirewall() *schema.Resource {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"name": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
"droplet_ids": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
"inbound_rule": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Optional: true,
|
|
||||||
Elem: &schema.Resource{
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"protocol": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"port_range": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
DiffSuppressFunc: func(k, oldV, newV string, d *schema.ResourceData) bool {
|
|
||||||
if oldV == "0" && newV == "all" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return (oldV == newV)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"source_addresses": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"source_tags": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"source_droplet_ids": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeInt},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"source_load_balancer_uids": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"outbound_rule": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Optional: true,
|
|
||||||
Elem: &schema.Resource{
|
|
||||||
Schema: map[string]*schema.Schema{
|
|
||||||
"protocol": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"port_range": {
|
|
||||||
Type: schema.TypeString,
|
|
||||||
Optional: true,
|
|
||||||
DiffSuppressFunc: func(k, oldV, newV string, d *schema.ResourceData) bool {
|
|
||||||
if oldV == "0" && newV == "all" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return (oldV == newV)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"destination_addresses": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"destination_tags": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"destination_droplet_ids": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeInt},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
"destination_load_balancer_uids": {
|
|
||||||
Type: schema.TypeList,
|
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
|
||||||
Optional: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"tags": tagsSchema(),
|
"tags": tagsSchema(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
CustomizeDiff: func(diff *schema.ResourceDiff, v interface{}) error {
|
||||||
|
|
||||||
|
inboundRules, hasInbound := diff.GetOk("inbound_rule")
|
||||||
|
outboundRules, hasOutbound := diff.GetOk("outbound_rule")
|
||||||
|
|
||||||
|
if !hasInbound && !hasOutbound {
|
||||||
|
return fmt.Errorf("At least one rule must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range inboundRules.(*schema.Set).List() {
|
||||||
|
inbound := v.(map[string]interface{})
|
||||||
|
protocol := inbound["protocol"]
|
||||||
|
|
||||||
|
port := inbound["port_range"]
|
||||||
|
if protocol != "icmp" && port == "" {
|
||||||
|
return fmt.Errorf("`port_range` of inbound rules is required if protocol is `tcp` or `udp`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range outboundRules.(*schema.Set).List() {
|
||||||
|
inbound := v.(map[string]interface{})
|
||||||
|
protocol := inbound["protocol"]
|
||||||
|
|
||||||
|
port := inbound["port_range"]
|
||||||
|
if protocol != "icmp" && port == "" {
|
||||||
|
return fmt.Errorf("`port_range` of outbound rules is required if protocol is `tcp` or `udp`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,18 +235,21 @@ func resourceDigitalOceanFirewallRead(d *schema.ResourceData, meta interface{})
|
||||||
d.Set("create_at", firewall.Created)
|
d.Set("create_at", firewall.Created)
|
||||||
d.Set("pending_changes", firewallPendingChanges(d, firewall))
|
d.Set("pending_changes", firewallPendingChanges(d, firewall))
|
||||||
d.Set("name", firewall.Name)
|
d.Set("name", firewall.Name)
|
||||||
d.Set("droplet_ids", firewall.DropletIDs)
|
|
||||||
|
|
||||||
if err := d.Set("inbound_rule", flattenFirewallInboundRules(d, firewall.InboundRules)); err != nil {
|
if err := d.Set("droplet_ids", flattenFirewallDropletIds(firewall.DropletIDs)); err != nil {
|
||||||
|
return fmt.Errorf("[DEBUG] Error setting `droplet_ids`: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := d.Set("inbound_rule", flattenFirewallInboundRules(firewall.InboundRules)); err != nil {
|
||||||
return fmt.Errorf("[DEBUG] Error setting Firewall inbound_rule error: %#v", err)
|
return fmt.Errorf("[DEBUG] Error setting Firewall inbound_rule error: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.Set("outbound_rule", flattenFirewallOutboundRules(d, firewall.OutboundRules)); err != nil {
|
if err := d.Set("outbound_rule", flattenFirewallOutboundRules(firewall.OutboundRules)); err != nil {
|
||||||
return fmt.Errorf("[DEBUG] Error setting Firewall outbound_rule error: %#v", err)
|
return fmt.Errorf("[DEBUG] Error setting Firewall outbound_rule error: %#v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.Set("tags", flattenTags(firewall.Tags)); err != nil {
|
if err := d.Set("tags", flattenTags(firewall.Tags)); err != nil {
|
||||||
return fmt.Errorf("Error setting `tags`: %+v", err)
|
return fmt.Errorf("[DEBUG] Error setting `tags`: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -256,27 +293,6 @@ func resourceDigitalOceanFirewallDelete(d *schema.ResourceData, meta interface{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceDigitalOceanFirewallExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
|
||||||
client := meta.(*godo.Client)
|
|
||||||
|
|
||||||
log.Printf("[INFO] Exists firewall: %s", d.Id())
|
|
||||||
|
|
||||||
// Retrieve the firewall properties for updating the state
|
|
||||||
_, resp, err := client.Firewalls.Get(context.Background(), d.Id())
|
|
||||||
if err != nil {
|
|
||||||
// check if the firewall no longer exists.
|
|
||||||
if resp != nil && resp.StatusCode == 404 {
|
|
||||||
log.Printf("[WARN] DigitalOcean Firewall (%s) not found", d.Id())
|
|
||||||
d.SetId("")
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, fmt.Errorf("Error retrieving firewall: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func firewallRequest(d *schema.ResourceData, client *godo.Client) (*godo.FirewallRequest, error) {
|
func firewallRequest(d *schema.ResourceData, client *godo.Client) (*godo.FirewallRequest, error) {
|
||||||
// Build up our firewall request
|
// Build up our firewall request
|
||||||
opts := &godo.FirewallRequest{
|
opts := &godo.FirewallRequest{
|
||||||
|
@ -284,22 +300,18 @@ func firewallRequest(d *schema.ResourceData, client *godo.Client) (*godo.Firewal
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := d.GetOk("droplet_ids"); ok {
|
if v, ok := d.GetOk("droplet_ids"); ok {
|
||||||
var droplets []int
|
opts.DropletIDs = expandFirewallDropletIds(v.(*schema.Set).List())
|
||||||
for _, id := range v.([]interface{}) {
|
|
||||||
i, err := strconv.Atoi(id.(string))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
droplets = append(droplets, i)
|
|
||||||
}
|
|
||||||
opts.DropletIDs = droplets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get inbound_rules
|
// Get inbound_rules
|
||||||
opts.InboundRules = expandFirewallInboundRules(d)
|
if v, ok := d.GetOk("inbound_rule"); ok {
|
||||||
|
opts.InboundRules = expandFirewallInboundRules(v.(*schema.Set).List())
|
||||||
|
}
|
||||||
|
|
||||||
// Get outbound_rules
|
// Get outbound_rules
|
||||||
opts.OutboundRules = expandFirewallOutboundRules(d)
|
if v, ok := d.GetOk("outbound_rule"); ok {
|
||||||
|
opts.OutboundRules = expandFirewallOutboundRules(v.(*schema.Set).List())
|
||||||
|
}
|
||||||
|
|
||||||
// Get tags
|
// Get tags
|
||||||
opts.Tags = expandTags(d.Get("tags").(*schema.Set).List())
|
opts.Tags = expandTags(d.Get("tags").(*schema.Set).List())
|
||||||
|
@ -307,78 +319,74 @@ func firewallRequest(d *schema.ResourceData, client *godo.Client) (*godo.Firewal
|
||||||
return opts, nil
|
return opts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func expandFirewallInboundRules(d *schema.ResourceData) []godo.InboundRule {
|
func expandFirewallDropletIds(droplets []interface{}) []int {
|
||||||
rules := make([]godo.InboundRule, 0, len(d.Get("inbound_rule").([]interface{})))
|
expandedDroplets := make([]int, len(droplets))
|
||||||
for _, rawRule := range d.Get("inbound_rule").([]interface{}) {
|
for i, v := range droplets {
|
||||||
|
expandedDroplets[i] = v.(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
return expandedDroplets
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandFirewallRuleStringSet(strings []interface{}) []string {
|
||||||
|
expandedStrings := make([]string, len(strings))
|
||||||
|
for i, v := range strings {
|
||||||
|
expandedStrings[i] = v.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return expandedStrings
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandFirewallInboundRules(rules []interface{}) []godo.InboundRule {
|
||||||
|
expandedRules := make([]godo.InboundRule, 0, len(rules))
|
||||||
|
for _, rawRule := range rules {
|
||||||
var src godo.Sources
|
var src godo.Sources
|
||||||
|
|
||||||
rule := rawRule.(map[string]interface{})
|
rule := rawRule.(map[string]interface{})
|
||||||
|
|
||||||
sourceAddresses := rule["source_addresses"].([]interface{})
|
src.DropletIDs = expandFirewallDropletIds(rule["source_droplet_ids"].(*schema.Set).List())
|
||||||
for _, address := range sourceAddresses {
|
|
||||||
src.Addresses = append(src.Addresses, address.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceTags := rule["source_tags"].([]interface{})
|
src.Addresses = expandFirewallRuleStringSet(rule["source_addresses"].(*schema.Set).List())
|
||||||
for _, tag := range sourceTags {
|
|
||||||
src.Tags = append(src.Tags, tag.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
dropletIds := rule["source_droplet_ids"].([]interface{})
|
src.LoadBalancerUIDs = expandFirewallRuleStringSet(rule["source_load_balancer_uids"].(*schema.Set).List())
|
||||||
for _, dropletId := range dropletIds {
|
|
||||||
src.DropletIDs = append(src.DropletIDs, dropletId.(int))
|
|
||||||
}
|
|
||||||
|
|
||||||
lbIds := rule["source_load_balancer_uids"].([]interface{})
|
src.Tags = expandTags(rule["source_tags"].(*schema.Set).List())
|
||||||
for _, lbId := range lbIds {
|
|
||||||
src.LoadBalancerUIDs = append(src.LoadBalancerUIDs, lbId.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
r := godo.InboundRule{
|
r := godo.InboundRule{
|
||||||
Protocol: rule["protocol"].(string),
|
Protocol: rule["protocol"].(string),
|
||||||
PortRange: rule["port_range"].(string),
|
PortRange: rule["port_range"].(string),
|
||||||
Sources: &src,
|
Sources: &src,
|
||||||
}
|
}
|
||||||
rules = append(rules, r)
|
|
||||||
|
expandedRules = append(expandedRules, r)
|
||||||
}
|
}
|
||||||
return rules
|
return expandedRules
|
||||||
}
|
}
|
||||||
|
|
||||||
func expandFirewallOutboundRules(d *schema.ResourceData) []godo.OutboundRule {
|
func expandFirewallOutboundRules(rules []interface{}) []godo.OutboundRule {
|
||||||
rules := make([]godo.OutboundRule, 0, len(d.Get("outbound_rule").([]interface{})))
|
expandedRules := make([]godo.OutboundRule, 0, len(rules))
|
||||||
for _, rawRule := range d.Get("outbound_rule").([]interface{}) {
|
for _, rawRule := range rules {
|
||||||
var dest godo.Destinations
|
var dest godo.Destinations
|
||||||
|
|
||||||
rule := rawRule.(map[string]interface{})
|
rule := rawRule.(map[string]interface{})
|
||||||
|
|
||||||
destinationAddresses := rule["destination_addresses"].([]interface{})
|
dest.DropletIDs = expandFirewallDropletIds(rule["destination_droplet_ids"].(*schema.Set).List())
|
||||||
for _, address := range destinationAddresses {
|
|
||||||
dest.Addresses = append(dest.Addresses, address.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
destinationTags := rule["destination_tags"].([]interface{})
|
dest.Addresses = expandFirewallRuleStringSet(rule["destination_addresses"].(*schema.Set).List())
|
||||||
for _, tag := range destinationTags {
|
|
||||||
dest.Tags = append(dest.Tags, tag.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
dropletIds := rule["destination_droplet_ids"].([]interface{})
|
dest.LoadBalancerUIDs = expandFirewallRuleStringSet(rule["destination_load_balancer_uids"].(*schema.Set).List())
|
||||||
for _, dropletId := range dropletIds {
|
|
||||||
dest.DropletIDs = append(dest.DropletIDs, dropletId.(int))
|
|
||||||
}
|
|
||||||
|
|
||||||
lbIds := rule["destination_load_balancer_uids"].([]interface{})
|
dest.Tags = expandTags(rule["destination_tags"].(*schema.Set).List())
|
||||||
for _, lbId := range lbIds {
|
|
||||||
dest.LoadBalancerUIDs = append(dest.LoadBalancerUIDs, lbId.(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
r := godo.OutboundRule{
|
r := godo.OutboundRule{
|
||||||
Protocol: rule["protocol"].(string),
|
Protocol: rule["protocol"].(string),
|
||||||
PortRange: rule["port_range"].(string),
|
PortRange: rule["port_range"].(string),
|
||||||
Destinations: &dest,
|
Destinations: &dest,
|
||||||
}
|
}
|
||||||
rules = append(rules, r)
|
|
||||||
|
expandedRules = append(expandedRules, r)
|
||||||
}
|
}
|
||||||
return rules
|
return expandedRules
|
||||||
}
|
}
|
||||||
|
|
||||||
func firewallPendingChanges(d *schema.ResourceData, firewall *godo.Firewall) []interface{} {
|
func firewallPendingChanges(d *schema.ResourceData, firewall *godo.Firewall) []interface{} {
|
||||||
|
@ -394,191 +402,120 @@ func firewallPendingChanges(d *schema.ResourceData, firewall *godo.Firewall) []i
|
||||||
return remote
|
return remote
|
||||||
}
|
}
|
||||||
|
|
||||||
func flattenFirewallInboundRules(d *schema.ResourceData, rules []godo.InboundRule) []interface{} {
|
func flattenFirewallDropletIds(droplets []int) *schema.Set {
|
||||||
|
if droplets == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
flattenedDroplets := schema.NewSet(schema.HashInt, []interface{}{})
|
||||||
|
for _, v := range droplets {
|
||||||
|
flattenedDroplets.Add(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenedDroplets
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenFirewallRuleStringSet(strings []string) *schema.Set {
|
||||||
|
flattenedStrings := schema.NewSet(schema.HashString, []interface{}{})
|
||||||
|
for _, v := range strings {
|
||||||
|
flattenedStrings.Add(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattenedStrings
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenFirewallInboundRules(rules []godo.InboundRule) []interface{} {
|
||||||
if rules == nil {
|
if rules == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the data.
|
flattenedRules := make([]interface{}, len(rules))
|
||||||
local := d.Get("inbound_rule").([]interface{})
|
for i, rule := range rules {
|
||||||
remote := make([]interface{}, 0, len(rules))
|
sources := rule.Sources
|
||||||
remoteMap := make(map[int]map[string]interface{})
|
protocol := rule.Protocol
|
||||||
for _, rule := range rules {
|
portRange := rule.PortRange
|
||||||
|
|
||||||
rawRule := map[string]interface{}{
|
rawRule := map[string]interface{}{
|
||||||
"protocol": rule.Protocol,
|
"protocol": protocol,
|
||||||
"port_range": rule.PortRange,
|
|
||||||
"source_droplet_ids": rule.Sources.DropletIDs,
|
|
||||||
"source_tags": rule.Sources.Tags,
|
|
||||||
"source_addresses": rule.Sources.Addresses,
|
|
||||||
"source_load_balancer_uids": rule.Sources.LoadBalancerUIDs,
|
|
||||||
}
|
|
||||||
remote = append(remote, rawRule)
|
|
||||||
hash := hashFirewallRule(rule.Protocol, rule.PortRange)
|
|
||||||
remoteMap[hash] = rawRule
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle special cases, both using the remote rules.
|
|
||||||
if len(remote) == 0 || len(local) == 0 {
|
|
||||||
return remote
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the local rules to only contains rules match
|
|
||||||
// to the remote rules.
|
|
||||||
match := make([]interface{}, 0, len(rules))
|
|
||||||
for _, rawRule := range local {
|
|
||||||
local := rawRule.(map[string]interface{})
|
|
||||||
protocol := local["protocol"].(string)
|
|
||||||
portRange := local["port_range"].(string)
|
|
||||||
hash := hashFirewallRule(protocol, portRange)
|
|
||||||
remote, ok := remoteMap[hash]
|
|
||||||
if !ok {
|
|
||||||
// No entry in the remote, remove it.
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// matches source lists.
|
// The API returns 0 when the port range was specified as all.
|
||||||
key := "source_droplet_ids"
|
// If protocol is `icmp` the API returns 0 for when port was
|
||||||
local[key] = matchFirewallIntLists(key, local, remote)
|
// not specified.
|
||||||
keys := []string{
|
if portRange == "0" {
|
||||||
"source_tags",
|
if protocol != "icmp" {
|
||||||
"source_addresses",
|
rawRule["port_range"] = "all"
|
||||||
"source_load_balancer_uids",
|
}
|
||||||
}
|
} else {
|
||||||
for _, key := range keys {
|
rawRule["port_range"] = portRange
|
||||||
local[key] = matchFirewallStringLists(key, local, remote)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match = append(match, local)
|
if sources.Tags != nil {
|
||||||
delete(remoteMap, hash)
|
rawRule["source_tags"] = flattenTags(sources.Tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sources.DropletIDs != nil {
|
||||||
|
rawRule["source_droplet_ids"] = flattenFirewallDropletIds(sources.DropletIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sources.Addresses != nil {
|
||||||
|
rawRule["source_addresses"] = flattenFirewallRuleStringSet(sources.Addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sources.LoadBalancerUIDs != nil {
|
||||||
|
rawRule["source_load_balancer_uids"] = flattenFirewallRuleStringSet(sources.LoadBalancerUIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
flattenedRules[i] = rawRule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the remaining remote rules.
|
return flattenedRules
|
||||||
for _, rawRule := range remoteMap {
|
|
||||||
match = append(match, rawRule)
|
|
||||||
}
|
|
||||||
|
|
||||||
return match
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func flattenFirewallOutboundRules(d *schema.ResourceData, rules []godo.OutboundRule) []interface{} {
|
func flattenFirewallOutboundRules(rules []godo.OutboundRule) []interface{} {
|
||||||
// Prepare the data.
|
if rules == nil {
|
||||||
local := d.Get("outbound_rule").([]interface{})
|
return nil
|
||||||
remote := make([]interface{}, 0, len(rules))
|
}
|
||||||
remoteMap := make(map[int]map[string]interface{})
|
|
||||||
for _, rule := range rules {
|
flattenedRules := make([]interface{}, len(rules))
|
||||||
|
for i, rule := range rules {
|
||||||
|
destinations := rule.Destinations
|
||||||
|
protocol := rule.Protocol
|
||||||
|
portRange := rule.PortRange
|
||||||
|
|
||||||
rawRule := map[string]interface{}{
|
rawRule := map[string]interface{}{
|
||||||
"protocol": rule.Protocol,
|
"protocol": protocol,
|
||||||
"port_range": rule.PortRange,
|
|
||||||
"destination_droplet_ids": rule.Destinations.DropletIDs,
|
|
||||||
"destination_tags": rule.Destinations.Tags,
|
|
||||||
"destination_addresses": rule.Destinations.Addresses,
|
|
||||||
"destination_load_balancer_uids": rule.Destinations.LoadBalancerUIDs,
|
|
||||||
}
|
|
||||||
remote = append(remote, rawRule)
|
|
||||||
hash := hashFirewallRule(rule.Protocol, rule.PortRange)
|
|
||||||
remoteMap[hash] = rawRule
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle special cases, both using the remote rules.
|
|
||||||
if len(remote) == 0 || len(local) == 0 {
|
|
||||||
return remote
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the local rules to only contains rules match
|
|
||||||
// to the remote rules.
|
|
||||||
match := make([]interface{}, 0, len(rules))
|
|
||||||
for _, rawRule := range local {
|
|
||||||
local := rawRule.(map[string]interface{})
|
|
||||||
protocol := local["protocol"].(string)
|
|
||||||
portRange := local["port_range"].(string)
|
|
||||||
hash := hashFirewallRule(protocol, portRange)
|
|
||||||
remote, ok := remoteMap[hash]
|
|
||||||
if !ok {
|
|
||||||
// No entry in the remote, remove it.
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// matches destination lists.
|
// The API returns 0 when the port range was specified as all.
|
||||||
key := "destination_droplet_ids"
|
// If protocol is `icmp` the API returns 0 for when port was
|
||||||
local[key] = matchFirewallIntLists(key, local, remote)
|
// not specified.
|
||||||
keys := []string{
|
if portRange == "0" {
|
||||||
"destination_tags",
|
if protocol != "icmp" {
|
||||||
"destination_addresses",
|
rawRule["port_range"] = "all"
|
||||||
"destination_load_balancer_uids",
|
}
|
||||||
}
|
} else {
|
||||||
for _, key := range keys {
|
rawRule["port_range"] = portRange
|
||||||
local[key] = matchFirewallStringLists(key, local, remote)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match = append(match, local)
|
if destinations.Tags != nil {
|
||||||
delete(remoteMap, hash)
|
rawRule["destination_tags"] = flattenTags(destinations.Tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
if destinations.DropletIDs != nil {
|
||||||
|
rawRule["destination_droplet_ids"] = flattenFirewallDropletIds(destinations.DropletIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
if destinations.Addresses != nil {
|
||||||
|
rawRule["destination_addresses"] = flattenFirewallRuleStringSet(destinations.Addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
if destinations.LoadBalancerUIDs != nil {
|
||||||
|
rawRule["destination_load_balancer_uids"] = flattenFirewallRuleStringSet(destinations.LoadBalancerUIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
flattenedRules[i] = rawRule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the remaining remote rules.
|
return flattenedRules
|
||||||
for _, rawRule := range remoteMap {
|
|
||||||
match = append(match, rawRule)
|
|
||||||
}
|
|
||||||
|
|
||||||
return match
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchFirewallIntLists(key string, local, remote map[string]interface{}) []interface{} {
|
|
||||||
remoteSize := len(remote[key].([]int))
|
|
||||||
remoteSet := make(map[int]bool)
|
|
||||||
matchedList := make([]interface{}, 0, remoteSize)
|
|
||||||
|
|
||||||
// Create a remote set out of the list for the quick comparison.
|
|
||||||
for _, i := range remote[key].([]int) {
|
|
||||||
remoteSet[i] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add only the item which exists in the remote list.
|
|
||||||
for _, i := range local[key].([]interface{}) {
|
|
||||||
if _, ok := remoteSet[i.(int)]; !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
matchedList = append(matchedList, i)
|
|
||||||
delete(remoteSet, i.(int))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append items only exists in the remote list.
|
|
||||||
for i := range remoteSet {
|
|
||||||
matchedList = append(matchedList, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchedList
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchFirewallStringLists(key string, local, remote map[string]interface{}) []interface{} {
|
|
||||||
remoteSize := len(remote[key].([]string))
|
|
||||||
remoteList := make([]interface{}, 0, remoteSize)
|
|
||||||
matchedList := make([]interface{}, 0, remoteSize)
|
|
||||||
|
|
||||||
// Create a remote set out of the list for the quick comparison.
|
|
||||||
for _, s := range remote[key].([]string) {
|
|
||||||
remoteList = append(remoteList, s)
|
|
||||||
}
|
|
||||||
remoteSet := schema.NewSet(schema.HashString, remoteList)
|
|
||||||
|
|
||||||
// Add only the item which exists in the remote list.
|
|
||||||
for _, s := range local[key].([]interface{}) {
|
|
||||||
if !remoteSet.Contains(s.(string)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
matchedList = append(matchedList, s)
|
|
||||||
remoteSet.Remove(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append items only exists in the remote list.
|
|
||||||
for _, s := range remoteSet.List() {
|
|
||||||
matchedList = append(matchedList, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchedList
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashFirewallRule(protocol, portRange string) int {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
buf.WriteString(fmt.Sprintf("%s-%s", protocol, portRange))
|
|
||||||
return hashcode.String(buf.String())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,6 @@ func TestAccDigitalOceanFirewall_AllowOnlyInbound(t *testing.T) {
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "1"),
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "1"),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.port_range", "22"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.0", "0.0.0.0/0"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.1", "::/0"),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -50,16 +45,6 @@ func TestAccDigitalOceanFirewall_AllowMultipleInbound(t *testing.T) {
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "2"),
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "2"),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.port_range", "22"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.0", "0.0.0.0/0"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.1", "::/0"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.port_range", "80"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.source_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.source_addresses.0", "1.2.3.0/24"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.source_addresses.1", "2002::/16"),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -80,11 +65,6 @@ func TestAccDigitalOceanFirewall_AllowOnlyOutbound(t *testing.T) {
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "1"),
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "1"),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.port_range", "22"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.0", "0.0.0.0/0"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.1", "::/0"),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -105,16 +85,6 @@ func TestAccDigitalOceanFirewall_AllowMultipleOutbound(t *testing.T) {
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "2"),
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "2"),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.port_range", "22"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.0", "192.168.1.0/24"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.1", "2002:1001::/48"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.port_range", "53"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.protocol", "udp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.destination_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.destination_addresses.0", "1.2.3.0/24"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.destination_addresses.1", "2002::/16"),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -136,31 +106,7 @@ func TestAccDigitalOceanFirewall_MultipleInboundAndOutbound(t *testing.T) {
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "2"),
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "2"),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.port_range", "443"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.source_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.source_addresses.0", "192.168.1.0/24"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.source_addresses.1", "2002:1001:1:2::/64"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.source_tags.#", "1"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.1.source_tags.0", tagName),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.port_range", "22"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.0", "0.0.0.0/0"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.1", "::/0"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "2"),
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "2"),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.port_range", "443"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.0", "192.168.1.0/24"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.1", "2002:1001:1:2::/64"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_tags.#", "1"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_tags.0", tagName),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.port_range", "53"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.protocol", "udp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.destination_addresses.#", "2"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.destination_addresses.0", "0.0.0.0/0"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.1.destination_addresses.1", "::/0"),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -181,15 +127,28 @@ func TestAccDigitalOceanFirewall_fullPortRange(t *testing.T) {
|
||||||
Check: resource.ComposeAggregateTestCheckFunc(
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "1"),
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "1"),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.port_range", "0"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.protocol", "tcp"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.#", "1"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.0", "192.168.1.1/32"),
|
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "1"),
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "1"),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.port_range", "0"),
|
),
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.protocol", "tcp"),
|
},
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.#", "1"),
|
},
|
||||||
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.0.destination_addresses.0", "192.168.1.2/32"),
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccDigitalOceanFirewall_icmp(t *testing.T) {
|
||||||
|
rName := acctest.RandString(10)
|
||||||
|
var firewall godo.Firewall
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckDigitalOceanFirewallDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
{
|
||||||
|
Config: testAccDigitalOceanFirewallConfig_icmp(rName),
|
||||||
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
|
testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall),
|
||||||
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "inbound_rule.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr("digitalocean_firewall.foobar", "outbound_rule.#", "1"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -337,6 +296,23 @@ resource "digitalocean_firewall" "foobar" {
|
||||||
`, rName)
|
`, rName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAccDigitalOceanFirewallConfig_icmp(rName string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "digitalocean_firewall" "foobar" {
|
||||||
|
name = "%s"
|
||||||
|
inbound_rule {
|
||||||
|
protocol = "icmp"
|
||||||
|
source_addresses = ["192.168.1.1/32"]
|
||||||
|
}
|
||||||
|
outbound_rule {
|
||||||
|
protocol = "icmp"
|
||||||
|
port_range = "1-65535"
|
||||||
|
destination_addresses = ["192.168.1.2/32"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, rName)
|
||||||
|
}
|
||||||
|
|
||||||
func testAccCheckDigitalOceanFirewallDestroy(s *terraform.State) error {
|
func testAccCheckDigitalOceanFirewallDestroy(s *terraform.State) error {
|
||||||
client := testAccProvider.Meta().(*godo.Client)
|
client := testAccProvider.Meta().(*godo.Client)
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,10 @@ resource "digitalocean_firewall" "web" {
|
||||||
port_range = "443"
|
port_range = "443"
|
||||||
source_addresses = ["0.0.0.0/0", "::/0"]
|
source_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
protocol = "icmp"
|
||||||
|
source_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
outbound_rule = [
|
outbound_rule = [
|
||||||
|
@ -55,6 +59,10 @@ resource "digitalocean_firewall" "web" {
|
||||||
port_range = "53"
|
port_range = "53"
|
||||||
destination_addresses = ["0.0.0.0/0", "::/0"]
|
destination_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
protocol = "icmp"
|
||||||
|
destination_addresses = ["0.0.0.0/0", "::/0"]
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -74,11 +82,12 @@ The following arguments are supported:
|
||||||
|
|
||||||
`inbound_rule` supports the following:
|
`inbound_rule` supports the following:
|
||||||
|
|
||||||
* `protocol` - (Optional) The type of traffic to be allowed.
|
* `protocol` - (Required) The type of traffic to be allowed.
|
||||||
This may be one of "tcp", "udp", or "icmp".
|
This may be one of "tcp", "udp", or "icmp".
|
||||||
* `port_range` - (Optional) The ports on which traffic will be allowed
|
* `port_range` - (Optional) The ports on which traffic will be allowed
|
||||||
specified as a string containing a single port, a range (e.g. "8000-9000"),
|
specified as a string containing a single port, a range (e.g. "8000-9000"),
|
||||||
or "1-65535" to open all ports for a protocol.
|
or "1-65535" to open all ports for a protocol. Required for when protocol is
|
||||||
|
`tcp` or `udp`.
|
||||||
* `source_addresses` - (Optional) An array of strings containing the IPv4
|
* `source_addresses` - (Optional) An array of strings containing the IPv4
|
||||||
addresses, IPv6 addresses, IPv4 CIDRs, and/or IPv6 CIDRs from which the
|
addresses, IPv6 addresses, IPv4 CIDRs, and/or IPv6 CIDRs from which the
|
||||||
inbound traffic will be accepted.
|
inbound traffic will be accepted.
|
||||||
|
@ -92,11 +101,12 @@ The following arguments are supported:
|
||||||
|
|
||||||
`outbound_rule` supports the following:
|
`outbound_rule` supports the following:
|
||||||
|
|
||||||
* `protocol` - (Optional) The type of traffic to be allowed.
|
* `protocol` - (Required) The type of traffic to be allowed.
|
||||||
This may be one of "tcp", "udp", or "icmp".
|
This may be one of "tcp", "udp", or "icmp".
|
||||||
* `port_range` - (Optional) The ports on which traffic will be allowed
|
* `port_range` - (Optional) The ports on which traffic will be allowed
|
||||||
specified as a string containing a single port, a range (e.g. "8000-9000"),
|
specified as a string containing a single port, a range (e.g. "8000-9000"),
|
||||||
or "1-65535" to open all ports for a protocol.
|
or "1-65535" to open all ports for a protocol. Required for when protocol is
|
||||||
|
`tcp` or `udp`.
|
||||||
* `destination_addresses` - (Optional) An array of strings containing the IPv4
|
* `destination_addresses` - (Optional) An array of strings containing the IPv4
|
||||||
addresses, IPv6 addresses, IPv4 CIDRs, and/or IPv6 CIDRs to which the
|
addresses, IPv6 addresses, IPv4 CIDRs, and/or IPv6 CIDRs to which the
|
||||||
outbound traffic will be allowed.
|
outbound traffic will be allowed.
|
||||||
|
|
Loading…
Reference in New Issue