Skip to content

Commit

Permalink
FW-5588: add ASN and hostname lists
Browse files Browse the repository at this point in the history
  • Loading branch information
Paschal Obba committed May 30, 2023
1 parent 38db1c6 commit 904a357
Show file tree
Hide file tree
Showing 9 changed files with 372 additions and 26 deletions.
3 changes: 3 additions & 0 deletions .changelog/2483.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/cloudflare_list: add support for Hostname and ASN lists.
```
61 changes: 59 additions & 2 deletions docs/resources/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
page_title: "cloudflare_list Resource - Cloudflare"
subcategory: ""
description: |-
Provides Lists (IPs, Redirects) to be used in Edge Rules Engine
Provides Lists (IPs, Redirects, Hostname, ASNs) to be used in Edge Rules Engine
across all zones within the same account.
---

# cloudflare_list (Resource)

Provides Lists (IPs, Redirects) to be used in Edge Rules Engine
Provides Lists (IPs, Redirects, Hostname, ASNs) to be used in Edge Rules Engine
across all zones within the same account.

~> The `cloudflare_list` resource supports defining list items in line with the `item` attribute. The provider also has a `cloudflare_list_item` resource for managing items as independent resources. Using both in line `item` definitions _and_ `cloudflare_list_items` on the same list is not supported and will cause Terraform into an irreconcilable state.
Expand Down Expand Up @@ -38,6 +38,28 @@ resource "cloudflare_list" "example" {
}
}
# ASN list
resource "cloudflare_list" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example_list"
description = "example ASNs for a list"
kind = "asn"
item {
value {
asn = 5678
}
comment = "one"
}
item {
value {
asn = 9810
}
comment = "two"
}
}
# Redirect list
resource "cloudflare_list" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
Expand Down Expand Up @@ -70,6 +92,32 @@ resource "cloudflare_list" "example" {
comment = "two"
}
}
# Hostname list
resource "cloudflare_list" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example_list"
description = "example hostnames for a list"
kind = "hostname"
item {
value {
hostname {
url_hostname = "example.com"
}
}
comment = "one"
}
item {
value {
hostname {
url_hostname = "*.example.com"
}
}
comment = "two"
}
}
```

<!-- schema generated by tfplugindocs -->
Expand Down Expand Up @@ -108,6 +156,8 @@ Optional:

- `ip` (String)
- `redirect` (Block List) (see [below for nested schema](#nestedblock--item--value--redirect))
- `hostname` (Block List) (see [below for nested schema](#nestedblock--item--value--hostname))
- `asn` (Number)

<a id="nestedblock--item--value--redirect"></a>
### Nested Schema for `item.value.redirect`
Expand All @@ -125,6 +175,13 @@ Optional:
- `status_code` (Number) The status code to be used when redirecting a request.
- `subpath_matching` (String) Whether the redirect also matches subpaths of the source url. Available values: `disabled`, `enabled`.

<a id="nestedblock--item--value--hostname"></a>
### Nested Schema for `item.value.hostname`

Required:

- `url_hostname` (String) The hostname to match on.

## Import

Import is supported using the following syntax:
Expand Down
49 changes: 49 additions & 0 deletions examples/resources/cloudflare_list/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,52 @@ resource "cloudflare_list" "example" {
comment = "two"
}
}

# ASN list
resource "cloudflare_list" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example_list"
description = "example ASNs for a list"
kind = "asn"

item {
value {
asn = 677
}
comment = "one"
}

item {
value {
asn = 989
}
comment = "two"
}
}


# Hostname list
resource "cloudflare_list" "example" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example_list"
description = "example hostnames for a list"
kind = "hostname"

item {
value {
hostname {
url_hostname = "example.com"
}
}
comment = "one"
}

item {
value {
hostname {
url_hostname = "*.example.com"
}
}
comment = "two"
}
}
32 changes: 32 additions & 0 deletions examples/resources/cloudflare_list_item/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,35 @@ resource "cloudflare_list_item" "test_two" {
subpath_matching = "enabled"
}
}

# ASN list
resource "cloudflare_list" "example_asn_list" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example_asn_list"
description = "example ASNs for a list"
kind = "asn"
}

# ASN List Item
resource "cloudflare_list_item" "example_asn_item" {
account_id = "f037e56e89293a057740de681ac9abbe"
list_id = cloudflare_list.example_asn_list.id
comment = "List Item Comment"
asn = 6789
}

# Hostname list
resource "cloudflare_list" "example_hostname_list" {
account_id = "f037e56e89293a057740de681ac9abbe"
name = "example_hostname_list"
description = "example Hostnames for a list"
kind = "hostname"
}

# Hostname List Item
resource "cloudflare_list_item" "example_hostname_item" {
account_id = "f037e56e89293a057740de681ac9abbe"
list_id = cloudflare_list.example_hostname_list.id
comment = "List Item Comment"
asn = "example.com"
}
34 changes: 34 additions & 0 deletions internal/sdkv2provider/resource_cloudflare_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ func resourceCloudflareListRead(ctx context.Context, d *schema.ResourceData, met
if i.IP != nil {
value["ip"] = *i.IP
}
if i.ASN != nil {
value["asn"] = *i.ASN
}
if i.Hostname != nil {
value["hostname"] = []map[string]interface{}{{
"url_hostname": i.Hostname.UrlHostname,
}}
}
if i.Redirect != nil {
optBoolToString := func(b *bool) string {
if b != nil {
Expand Down Expand Up @@ -207,6 +215,30 @@ func buildListItemsCreateRequest(items []interface{}) []cloudflare.ListItemCreat
}
}

var asn *uint32

if field, ok := value["asn"]; ok {
if field, ok := field.(int); ok {
f := uint32(field)
asn = &f
}
}

var hostname *cloudflare.Hostname

if field, ok := value["hostname"]; ok {
if field, ok := field.([]interface{}); ok && len(field) > 0 {
if field, ok := field[0].(map[string]interface{}); ok {
if field != nil {
urlHostname := field["url_hostname"].(string)
hostname = &cloudflare.Hostname{
UrlHostname: urlHostname,
}
}
}
}
}

var redirect *cloudflare.Redirect = nil
var r map[string]interface{} = nil

Expand Down Expand Up @@ -264,6 +296,8 @@ func buildListItemsCreateRequest(items []interface{}) []cloudflare.ListItemCreat
listItems = append(listItems, cloudflare.ListItemCreateRequest{
IP: ip,
Redirect: redirect,
ASN: asn,
Hostname: hostname,
Comment: item.(map[string]interface{})["comment"].(string),
})
}
Expand Down
68 changes: 47 additions & 21 deletions internal/sdkv2provider/resource_cloudflare_list_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ func resourceCloudflareListItemRead(ctx context.Context, d *schema.ResourceData,
d.Set("ip", listItem.IP)
}

if listItem.ASN != nil {
d.Set("asn", listItem.ASN)
}

if listItem.Hostname != nil {
d.Set("url_hostname", listItem.Hostname.UrlHostname)
}

if listItem.Redirect != nil {
optBoolToString := func(b *bool) string {
if b != nil {
Expand Down Expand Up @@ -157,21 +165,24 @@ func listItemType(d *schema.ResourceData) string {
return "ip"
}

return "redirect"
}

func buildListItemCreateRequest(d *schema.ResourceData) cloudflare.ListItemCreateRequest {
itemType := listItemType(d)
if _, ok := d.GetOk("redirect"); ok {
return "redirect"
}

request := cloudflare.ListItemCreateRequest{
Comment: d.Get("comment").(string),
if _, ok := d.GetOk("hostname"); ok {
return "hostname"
}

if itemType == "ip" {
request.IP = cloudflare.StringPtr(d.Get("ip").(string))
return request
if _, ok := d.GetOk("asn"); ok {
return "asn"
}

return ""
}

func buildListItemCreateRequest(d *schema.ResourceData) cloudflare.ListItemCreateRequest {
itemType := listItemType(d)

stringToOptBool := func(r map[string]interface{}, s string) *bool {
switch r[s] {
case "enabled":
Expand All @@ -183,21 +194,36 @@ func buildListItemCreateRequest(d *schema.ResourceData) cloudflare.ListItemCreat
}
}

redirect := d.Get("redirect").([]interface{})[0].(map[string]interface{})
request.Redirect = &cloudflare.Redirect{
SourceUrl: redirect["source_url"].(string),
TargetUrl: redirect["target_url"].(string),
request := cloudflare.ListItemCreateRequest{
Comment: d.Get("comment").(string),
}

if value, ok := redirect["status_code"]; ok && value != 0 {
request.Redirect.StatusCode = cloudflare.IntPtr(value.(int))
}
switch itemType {
case "ip":
request.IP = cloudflare.StringPtr(d.Get("ip").(string))
case "asn":
request.ASN = cloudflare.Uint32Ptr(uint32(d.Get("asn").(int)))
case "hostname":
hostname := d.Get("hostname").([]interface{})[0].(map[string]interface{})
request.Hostname = &cloudflare.Hostname{
UrlHostname: *cloudflare.StringPtr(hostname["url_hostname"].(string)),
}
case "redirect":
redirect := d.Get("redirect").([]interface{})[0].(map[string]interface{})
request.Redirect = &cloudflare.Redirect{
SourceUrl: redirect["source_url"].(string),
TargetUrl: redirect["target_url"].(string),
}

request.Redirect.IncludeSubdomains = stringToOptBool(redirect, "include_subdomains")
request.Redirect.PreserveQueryString = stringToOptBool(redirect, "preserve_query_string")
request.Redirect.SubpathMatching = stringToOptBool(redirect, "subpath_matching")
request.Redirect.PreservePathSuffix = stringToOptBool(redirect, "preserve_path_suffix")
if value, ok := redirect["status_code"]; ok && value != 0 {
request.Redirect.StatusCode = cloudflare.IntPtr(value.(int))
}

request.Redirect.IncludeSubdomains = stringToOptBool(redirect, "include_subdomains")
request.Redirect.PreserveQueryString = stringToOptBool(redirect, "preserve_query_string")
request.Redirect.SubpathMatching = stringToOptBool(redirect, "subpath_matching")
request.Redirect.PreservePathSuffix = stringToOptBool(redirect, "preserve_path_suffix")
}
return request
}

Expand Down
Loading

0 comments on commit 904a357

Please sign in to comment.