diff --git a/GNUmakefile b/GNUmakefile index bf36d7e96..445df5375 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -8,7 +8,7 @@ build: fmtcheck go install test: fmtcheck - go test -i $(TEST) || exit 1 + go test $(TEST) || exit 1 echo $(TEST) | \ xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 diff --git a/digitalocean/datasource_digitalocean_firewall.go b/digitalocean/datasource_digitalocean_firewall.go new file mode 100644 index 000000000..c200e8c28 --- /dev/null +++ b/digitalocean/datasource_digitalocean_firewall.go @@ -0,0 +1,33 @@ +package digitalocean + +import ( + "context" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceDigitalOceanFirewall() *schema.Resource { + fwSchema := firewallSchema() + + for _, f := range fwSchema { + f.Computed = true + f.Required = false + } + + fwSchema["name"].ValidateFunc = nil + + fwSchema["firewall_id"] = &schema.Schema{ + Type: schema.TypeString, + Required: true, + } + + return &schema.Resource{ + ReadContext: dataSourceDigitalOceanFirewallRead, + Schema: fwSchema, + } +} + +func dataSourceDigitalOceanFirewallRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + d.SetId(d.Get("firewall_id").(string)) + return resourceDigitalOceanFirewallRead(ctx, d, meta) +} diff --git a/digitalocean/datasource_digitalocean_firewall_test.go b/digitalocean/datasource_digitalocean_firewall_test.go new file mode 100644 index 000000000..02ca797d7 --- /dev/null +++ b/digitalocean/datasource_digitalocean_firewall_test.go @@ -0,0 +1,77 @@ +package digitalocean + +import ( + "fmt" + "github.com/digitalocean/godo" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceDigitalOceanFirewall_Basic(t *testing.T) { + fwDataConfig := ` +data "digitalocean_firewall" "foobar" { + firewall_id = digitalocean_firewall.foobar.id +}` + + var firewall godo.Firewall + fwName := randomTestName() + + fwCreateConfig := fmt.Sprintf(testAccDigitalOceanFirewallConfig_OnlyInbound(fwName)) + updatedFWCreateConfig := testAccDigitalOceanFirewallConfig_OnlyMultipleInbound(fwName) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: fwCreateConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckDigitalOceanFirewallExists("digitalocean_firewall.foobar", &firewall), + ), + }, + { + Config: fwCreateConfig + fwDataConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "name", "foobar-"+fwName), + resource.TestCheckResourceAttrPair("digitalocean_firewall.foobar", "id", + "data.digitalocean_firewall.foobar", "firewall_id"), + resource.TestCheckResourceAttrPair("digitalocean_firewall.foobar", "droplet_ids", + "data.digitalocean_firewall.foobar", "droplet_ids"), + resource.TestCheckResourceAttrPair("digitalocean_firewall.foobar", "inbound_rule", + "data.digitalocean_firewall.foobar", "inbound_rule"), + resource.TestCheckResourceAttrPair("digitalocean_firewall.foobar", "outbound_rule", + "data.digitalocean_firewall.foobar", "outbound_rule"), + resource.TestCheckResourceAttrPair("digitalocean_firewall.foobar", "status", + "data.digitalocean_firewall.foobar", "status"), + resource.TestCheckResourceAttrPair("digitalocean_firewall.foobar", "created_at", + "data.digitalocean_firewall.foobar", "created_at"), + resource.TestCheckResourceAttrPair("digitalocean_firewall.foobar", "pending_changes", + "data.digitalocean_firewall.foobar", "pending_changes"), + resource.TestCheckResourceAttrPair("digitalocean_firewall.foobar", "tags", + "data.digitalocean_firewall.foobar", "tags"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.0.protocol", "tcp"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.0.port_range", "22"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.0", "0.0.0.0/0"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.1", "::/0"), + ), + }, + { + Config: updatedFWCreateConfig, + }, + { + Config: updatedFWCreateConfig + fwDataConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.0.protocol", "tcp"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.0.port_range", "22"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.0", "0.0.0.0/0"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.0.source_addresses.1", "::/0"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.1.protocol", "tcp"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.1.port_range", "80"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.1.source_addresses.0", "1.2.3.0/24"), + resource.TestCheckResourceAttr("data.digitalocean_firewall.foobar", "inbound_rule.1.source_addresses.1", "2002::/16"), + ), + }, + }, + }) +} diff --git a/digitalocean/firewalls.go b/digitalocean/firewalls.go new file mode 100644 index 000000000..df80cf6ae --- /dev/null +++ b/digitalocean/firewalls.go @@ -0,0 +1,316 @@ +package digitalocean + +import ( + "github.com/digitalocean/godo" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func firewallSchema() map[string]*schema.Schema { + return 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: firewallRuleSchema("source"), + }, + + "outbound_rule": { + Type: schema.TypeSet, + Optional: true, + Elem: firewallRuleSchema("destination"), + }, + + "status": { + Type: schema.TypeString, + Computed: true, + }, + + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + + "pending_changes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "droplet_id": { + Type: schema.TypeInt, + Optional: true, + }, + "removing": { + Type: schema.TypeBool, + Optional: true, + }, + "status": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "tags": tagsSchema(), + } +} + +func firewallRuleSchema(prefix string) *schema.Resource { + if prefix != "" && prefix[len(prefix)-1:] != "_" { + prefix += "_" + } + + return &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, + }, + prefix + "addresses": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Optional: true, + }, + prefix + "droplet_ids": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeInt}, + Optional: true, + }, + prefix + "load_balancer_uids": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Optional: true, + }, + prefix + "tags": tagsSchema(), + }, + } +} + +func expandFirewallDropletIds(droplets []interface{}) []int { + expandedDroplets := make([]int, len(droplets)) + 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 + + rule := rawRule.(map[string]interface{}) + + src.DropletIDs = expandFirewallDropletIds(rule["source_droplet_ids"].(*schema.Set).List()) + + src.Addresses = expandFirewallRuleStringSet(rule["source_addresses"].(*schema.Set).List()) + + src.LoadBalancerUIDs = expandFirewallRuleStringSet(rule["source_load_balancer_uids"].(*schema.Set).List()) + + src.Tags = expandTags(rule["source_tags"].(*schema.Set).List()) + + r := godo.InboundRule{ + Protocol: rule["protocol"].(string), + PortRange: rule["port_range"].(string), + Sources: &src, + } + + expandedRules = append(expandedRules, r) + } + return expandedRules +} + +func expandFirewallOutboundRules(rules []interface{}) []godo.OutboundRule { + expandedRules := make([]godo.OutboundRule, 0, len(rules)) + for _, rawRule := range rules { + var dest godo.Destinations + + rule := rawRule.(map[string]interface{}) + + dest.DropletIDs = expandFirewallDropletIds(rule["destination_droplet_ids"].(*schema.Set).List()) + + dest.Addresses = expandFirewallRuleStringSet(rule["destination_addresses"].(*schema.Set).List()) + + dest.LoadBalancerUIDs = expandFirewallRuleStringSet(rule["destination_load_balancer_uids"].(*schema.Set).List()) + + dest.Tags = expandTags(rule["destination_tags"].(*schema.Set).List()) + + r := godo.OutboundRule{ + Protocol: rule["protocol"].(string), + PortRange: rule["port_range"].(string), + Destinations: &dest, + } + + expandedRules = append(expandedRules, r) + } + return expandedRules +} + +func firewallPendingChanges(d *schema.ResourceData, firewall *godo.Firewall) []interface{} { + remote := make([]interface{}, 0, len(firewall.PendingChanges)) + for _, change := range firewall.PendingChanges { + rawChange := map[string]interface{}{ + "droplet_id": change.DropletID, + "removing": change.Removing, + "status": change.Status, + } + remote = append(remote, rawChange) + } + return remote +} + +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 { + return nil + } + + flattenedRules := make([]interface{}, len(rules)) + for i, rule := range rules { + sources := rule.Sources + protocol := rule.Protocol + portRange := rule.PortRange + + rawRule := map[string]interface{}{ + "protocol": protocol, + } + + // The API returns 0 when the port range was specified as all. + // If protocol is `icmp` the API returns 0 for when port was + // not specified. + if portRange == "0" { + if protocol != "icmp" { + rawRule["port_range"] = "all" + } + } else { + rawRule["port_range"] = portRange + } + + if sources.Tags != nil { + 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 + } + + return flattenedRules +} + +func flattenFirewallOutboundRules(rules []godo.OutboundRule) []interface{} { + if rules == nil { + return nil + } + + flattenedRules := make([]interface{}, len(rules)) + for i, rule := range rules { + destinations := rule.Destinations + protocol := rule.Protocol + portRange := rule.PortRange + + rawRule := map[string]interface{}{ + "protocol": protocol, + } + + // The API returns 0 when the port range was specified as all. + // If protocol is `icmp` the API returns 0 for when port was + // not specified. + if portRange == "0" { + if protocol != "icmp" { + rawRule["port_range"] = "all" + } + } else { + rawRule["port_range"] = portRange + } + + if destinations.Tags != nil { + 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 + } + + return flattenedRules +} diff --git a/digitalocean/provider.go b/digitalocean/provider.go index c0060478e..1a49ef20c 100644 --- a/digitalocean/provider.go +++ b/digitalocean/provider.go @@ -58,6 +58,7 @@ func Provider() *schema.Provider { "digitalocean_droplet": dataSourceDigitalOceanDroplet(), "digitalocean_droplets": dataSourceDigitalOceanDroplets(), "digitalocean_droplet_snapshot": dataSourceDigitalOceanDropletSnapshot(), + "digitalocean_firewall": dataSourceDigitalOceanFirewall(), "digitalocean_floating_ip": dataSourceDigitalOceanFloatingIp(), "digitalocean_image": dataSourceDigitalOceanImage(), "digitalocean_images": dataSourceDigitalOceanImages(), diff --git a/digitalocean/resource_digitalocean_firewall.go b/digitalocean/resource_digitalocean_firewall.go index 3d51e279a..eb1478ed5 100644 --- a/digitalocean/resource_digitalocean_firewall.go +++ b/digitalocean/resource_digitalocean_firewall.go @@ -9,7 +9,6 @@ import ( "github.com/digitalocean/godo" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceDigitalOceanFirewall() *schema.Resource { @@ -22,142 +21,7 @@ func resourceDigitalOceanFirewall() *schema.Resource { State: schema.ImportStatePassthrough, }, - 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": { - Type: schema.TypeString, - Computed: true, - }, - - "created_at": { - Type: schema.TypeString, - Computed: true, - }, - - "pending_changes": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "droplet_id": { - Type: schema.TypeInt, - Optional: true, - }, - "removing": { - Type: schema.TypeBool, - Optional: true, - }, - "status": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - - "tags": tagsSchema(), - }, + Schema: firewallSchema(), CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, v interface{}) error { @@ -319,204 +183,3 @@ func firewallRequest(d *schema.ResourceData, client *godo.Client) (*godo.Firewal return opts, nil } - -func expandFirewallDropletIds(droplets []interface{}) []int { - expandedDroplets := make([]int, len(droplets)) - 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 - - rule := rawRule.(map[string]interface{}) - - src.DropletIDs = expandFirewallDropletIds(rule["source_droplet_ids"].(*schema.Set).List()) - - src.Addresses = expandFirewallRuleStringSet(rule["source_addresses"].(*schema.Set).List()) - - src.LoadBalancerUIDs = expandFirewallRuleStringSet(rule["source_load_balancer_uids"].(*schema.Set).List()) - - src.Tags = expandTags(rule["source_tags"].(*schema.Set).List()) - - r := godo.InboundRule{ - Protocol: rule["protocol"].(string), - PortRange: rule["port_range"].(string), - Sources: &src, - } - - expandedRules = append(expandedRules, r) - } - return expandedRules -} - -func expandFirewallOutboundRules(rules []interface{}) []godo.OutboundRule { - expandedRules := make([]godo.OutboundRule, 0, len(rules)) - for _, rawRule := range rules { - var dest godo.Destinations - - rule := rawRule.(map[string]interface{}) - - dest.DropletIDs = expandFirewallDropletIds(rule["destination_droplet_ids"].(*schema.Set).List()) - - dest.Addresses = expandFirewallRuleStringSet(rule["destination_addresses"].(*schema.Set).List()) - - dest.LoadBalancerUIDs = expandFirewallRuleStringSet(rule["destination_load_balancer_uids"].(*schema.Set).List()) - - dest.Tags = expandTags(rule["destination_tags"].(*schema.Set).List()) - - r := godo.OutboundRule{ - Protocol: rule["protocol"].(string), - PortRange: rule["port_range"].(string), - Destinations: &dest, - } - - expandedRules = append(expandedRules, r) - } - return expandedRules -} - -func firewallPendingChanges(d *schema.ResourceData, firewall *godo.Firewall) []interface{} { - remote := make([]interface{}, 0, len(firewall.PendingChanges)) - for _, change := range firewall.PendingChanges { - rawChange := map[string]interface{}{ - "droplet_id": change.DropletID, - "removing": change.Removing, - "status": change.Status, - } - remote = append(remote, rawChange) - } - return remote -} - -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 { - return nil - } - - flattenedRules := make([]interface{}, len(rules)) - for i, rule := range rules { - sources := rule.Sources - protocol := rule.Protocol - portRange := rule.PortRange - - rawRule := map[string]interface{}{ - "protocol": protocol, - } - - // The API returns 0 when the port range was specified as all. - // If protocol is `icmp` the API returns 0 for when port was - // not specified. - if portRange == "0" { - if protocol != "icmp" { - rawRule["port_range"] = "all" - } - } else { - rawRule["port_range"] = portRange - } - - if sources.Tags != nil { - 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 - } - - return flattenedRules -} - -func flattenFirewallOutboundRules(rules []godo.OutboundRule) []interface{} { - if rules == nil { - return nil - } - - flattenedRules := make([]interface{}, len(rules)) - for i, rule := range rules { - destinations := rule.Destinations - protocol := rule.Protocol - portRange := rule.PortRange - - rawRule := map[string]interface{}{ - "protocol": protocol, - } - - // The API returns 0 when the port range was specified as all. - // If protocol is `icmp` the API returns 0 for when port was - // not specified. - if portRange == "0" { - if protocol != "icmp" { - rawRule["port_range"] = "all" - } - } else { - rawRule["port_range"] = portRange - } - - if destinations.Tags != nil { - 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 - } - - return flattenedRules -} diff --git a/docs/data-sources/firewall.md b/docs/data-sources/firewall.md new file mode 100644 index 000000000..1aa780773 --- /dev/null +++ b/docs/data-sources/firewall.md @@ -0,0 +1,84 @@ +--- +page_title: "DigitalOcean: digitalocean_firewall" +--- + +# digitalocean_firewall + +Get information on a DigitalOcean Firewall. + +## Example Usage + +Get the firewall: + +```hcl +data "digitalocean_firewall" "example" { + firewall_id = "1df48973-6eef-4214-854f-fa7726e7e583" +} + +output "example_firewall_name" { + value = data.digitalocean_firewall.example.name +} +``` + +## Argument Reference + +* `firewall_id` - (Required) The ID of the firewall to retrieve information + about. + +## Attributes Reference + +The following attributes are exported: + +* `id` - A unique ID that can be used to identify and reference a Firewall. +* `status` - A status string indicating the current state of the Firewall. + This can be "waiting", "succeeded", or "failed". +* `created_at` - A time value given in ISO8601 combined date and time format + that represents when the Firewall was created. +* `pending_changes` - A set of object containing the fields, `droplet_id`, + `removing`, and `status`. It is provided to detail exactly which Droplets + are having their security policies updated. When empty, all changes + have been successfully applied. +* `name` - The name of the Firewall. +* `droplet_ids` - The list of the IDs of the Droplets assigned to + the Firewall. +* `tags` - The names of the Tags assigned to the Firewall. +* `inbound_rules` - The inbound access rule block for the Firewall. +* `outbound_rules` - The outbound access rule block for the Firewall. + +`inbound_rule` supports the following: + +* `protocol` - The type of traffic to be allowed. + This may be one of "tcp", "udp", or "icmp". +* `port_range` - The ports on which traffic will be allowed + specified as a string containing a single port, a range (e.g. "8000-9000"), + or "1-65535" to open all ports for a protocol. Required for when protocol is + `tcp` or `udp`. +* `source_addresses` - An array of strings containing the IPv4 + addresses, IPv6 addresses, IPv4 CIDRs, and/or IPv6 CIDRs from which the + inbound traffic will be accepted. +* `source_droplet_ids` - An array containing the IDs of + the Droplets from which the inbound traffic will be accepted. +* `source_tags` - A set of names of Tags corresponding to group of + Droplets from which the inbound traffic will be accepted. +* `source_load_balancer_uids` - An array containing the IDs + of the Load Balancers from which the inbound traffic will be accepted. + +`outbound_rule` supports the following: + +* `protocol` - The type of traffic to be allowed. + This may be one of "tcp", "udp", or "icmp". +* `port_range` - The ports on which traffic will be allowed + specified as a string containing a single port, a range (e.g. "8000-9000"), + or "1-65535" to open all ports for a protocol. Required for when protocol is + `tcp` or `udp`. +* `destination_addresses` - An array of strings containing the IPv4 + addresses, IPv6 addresses, IPv4 CIDRs, and/or IPv6 CIDRs to which the + outbound traffic will be allowed. +* `destination_droplet_ids` - An array containing the IDs of + the Droplets to which the outbound traffic will be allowed. +* `destination_tags` - An array containing the names of Tags + corresponding to groups of Droplets to which the outbound traffic will + be allowed. + traffic. +* `destination_load_balancer_uids` - An array containing the IDs + of the Load Balancers to which the outbound traffic will be allowed.