Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support redirect lists #1700

Merged
Merged
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
7 changes: 7 additions & 0 deletions .changelog/1700.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:new-resource
resource/cloudflare_list: Added support for generic list types, including redirect lists.
```

```release-note:note
resource/cloudflare_ip_list: Deprecated cloudflare_ip_list in favor of cloudflare_list.
```
128 changes: 128 additions & 0 deletions docs/resources/list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
---
page_title: "cloudflare_list Resource - Cloudflare"
subcategory: ""
description: |-
Provides Lists (IPs, Redirects) 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 across all zones within the same account.

## Example Usage

```terraform
# IP list
resource "cloudflare_list" "example" {
account_id = "919f297a62fdfb28844177128ed4d331"
name = "example list"
description = "example IPs for a list"
kind = "ip"

item {
value {
ip = "192.0.2.0"
}
comment = "one"
}

item {
value {
ip = "192.0.2.1"
}
comment = "two"
}
}

# Redirect list
resource "cloudflare_list" "example" {
account_id = "919f297a62fdfb28844177128ed4d331"
name = "example list"
description = "example redirects for a list"
kind = "redirect"

item {
value {
redirect {
source_url = "example.com/blog"
target_url = "https://blog.example.com"
}
}
comment = "one"
}

item {
value {
redirect {
source_url = "example.com/foo"
target_url = "https://foo.example.com"
include_subdomains = true
subpath_matching = true
status_code = 301
preserve_query_string = true
preserve_path_suffix = false
}
}
comment = "two"
}
}
```
<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `account_id` (String) The account identifier to target for the resource.
- `kind` (String) The type of items the list will contain.
- `name` (String) The name of the list.

### Optional

- `description` (String) An optional description of the list.
- `item` (Block List) (see [below for nested schema](#nestedblock--item))

### Read-Only

- `id` (String) The ID of this resource.

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

Required:

- `value` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--item--value))

Optional:

- `comment` (String) An optional comment for the item.

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

Optional:

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

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

Required:

- `source_url` (String) The source url of the redirect.
- `target_url` (String) The target url of the redirect.

Optional:

- `include_subdomains` (Boolean) Whether the redirect also matches subdomains of the source url.
- `preserve_path_suffix` (Boolean) Whether to preserve the path suffix when doing subpath matching.
- `preserve_query_string` (Boolean) Whether the redirect target url should keep the query string of the request's url.
- `status_code` (Number) The status code to be used when redirecting a request.
- `subpath_matching` (Boolean) Whether the redirect also matches subpaths of the source url.

## Import

Import is supported using the following syntax:
```shell
$ terraform import cloudflare_list.example <account_id>/<list_id>
```
1 change: 1 addition & 0 deletions examples/resources/cloudflare_list/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$ terraform import cloudflare_list.example <account_id>/<list_id>
54 changes: 54 additions & 0 deletions examples/resources/cloudflare_list/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# IP list
resource "cloudflare_list" "example" {
account_id = "919f297a62fdfb28844177128ed4d331"
name = "example list"
description = "example IPs for a list"
kind = "ip"

item {
value {
ip = "192.0.2.0"
}
comment = "one"
}

item {
value {
ip = "192.0.2.1"
}
comment = "two"
}
}

# Redirect list
resource "cloudflare_list" "example" {
account_id = "919f297a62fdfb28844177128ed4d331"
name = "example list"
description = "example redirects for a list"
kind = "redirect"

item {
value {
redirect {
source_url = "example.com/blog"
target_url = "https://blog.example.com"
}
}
comment = "one"
}

item {
value {
redirect {
source_url = "example.com/foo"
target_url = "https://foo.example.com"
include_subdomains = true
subpath_matching = true
status_code = 301
preserve_query_string = true
preserve_path_suffix = false
}
}
comment = "two"
}
}
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ func New(version string) func() *schema.Provider {
"cloudflare_healthcheck": resourceCloudflareHealthcheck(),
"cloudflare_ip_list": resourceCloudflareIPList(),
"cloudflare_ipsec_tunnel": resourceCloudflareIPsecTunnel(),
"cloudflare_list": resourceCloudflareList(),
"cloudflare_load_balancer_monitor": resourceCloudflareLoadBalancerMonitor(),
"cloudflare_load_balancer_pool": resourceCloudflareLoadBalancerPool(),
"cloudflare_load_balancer": resourceCloudflareLoadBalancer(),
Expand Down
52 changes: 41 additions & 11 deletions internal/provider/resource_cloudflare_ip_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import (
"github.com/pkg/errors"
)

// The resource in this file is deprecated and should be removed on the next major release.
// Use the more general `list` resource instead.

func resourceCloudflareIPList() *schema.Resource {
return &schema.Resource{
Schema: resourceCloudflareIPListSchema(),
Expand All @@ -22,14 +25,20 @@ func resourceCloudflareIPList() *schema.Resource {
Importer: &schema.ResourceImporter{
StateContext: resourceCloudflareIPListImport,
},
DeprecationMessage: "This resource is deprecated, use the `cloudflare_list` instead.",
}
}

func resourceCloudflareIPListCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*cloudflare.API)
accountID := d.Get("account_id").(string)

list, err := client.CreateIPList(ctx, accountID, d.Get("name").(string), d.Get("description").(string), d.Get("kind").(string))
list, err := client.CreateList(ctx, cloudflare.ListCreateParams{
AccountID: accountID,
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Kind: d.Get("kind").(string),
})
if err != nil {
return diag.FromErr(errors.Wrap(err, fmt.Sprintf("error creating IP List %s", d.Get("name").(string))))
}
Expand All @@ -38,7 +47,11 @@ func resourceCloudflareIPListCreate(ctx context.Context, d *schema.ResourceData,

if items, ok := d.GetOk("item"); ok {
IPListItems := buildIPListItemsCreateRequest(items.(*schema.Set).List())
_, err = client.CreateIPListItems(ctx, accountID, d.Id(), IPListItems)
_, err = client.CreateListItems(ctx, cloudflare.ListCreateItemsParams{
AccountID: accountID,
ID: d.Id(),
Items: IPListItems,
})
if err != nil {
return diag.FromErr(errors.Wrap(err, fmt.Sprintf("error creating IP List Items")))
}
Expand Down Expand Up @@ -67,7 +80,10 @@ func resourceCloudflareIPListRead(ctx context.Context, d *schema.ResourceData, m
client := meta.(*cloudflare.API)
accountID := d.Get("account_id").(string)

list, err := client.GetIPList(ctx, accountID, d.Id())
list, err := client.GetList(ctx, cloudflare.ListGetParams{
AccountID: accountID,
ID: d.Id(),
})
if err != nil {
if strings.Contains(err.Error(), "could not find list") {
tflog.Info(ctx, fmt.Sprintf("IP List %s no longer exists", d.Id()))
Expand All @@ -81,7 +97,10 @@ func resourceCloudflareIPListRead(ctx context.Context, d *schema.ResourceData, m
d.Set("description", list.Description)
d.Set("kind", list.Kind)

items, err := client.ListIPListItems(ctx, accountID, d.Id())
items, err := client.ListListItems(ctx, cloudflare.ListListItemsParams{
AccountID: accountID,
ID: d.Id(),
})
if err != nil {
return diag.FromErr(errors.Wrap(err, fmt.Sprintf("error reading IP List Items")))
}
Expand All @@ -106,14 +125,22 @@ func resourceCloudflareIPListUpdate(ctx context.Context, d *schema.ResourceData,
client := meta.(*cloudflare.API)
accountID := d.Get("account_id").(string)

_, err := client.UpdateIPList(ctx, accountID, d.Id(), d.Get("description").(string))
_, err := client.UpdateList(ctx, cloudflare.ListUpdateParams{
AccountID: accountID,
ID: d.Id(),
Description: d.Get("description").(string),
})
if err != nil {
return diag.FromErr(errors.Wrap(err, fmt.Sprintf("error updating IP List description")))
}

if items, ok := d.GetOk("item"); ok {
IPListItems := buildIPListItemsCreateRequest(items.(*schema.Set).List())
_, err = client.ReplaceIPListItems(ctx, accountID, d.Id(), IPListItems)
_, err = client.ReplaceListItems(ctx, cloudflare.ListReplaceItemsParams{
AccountID: accountID,
ID: d.Id(),
Items: IPListItems,
})
if err != nil {
return diag.FromErr(errors.Wrap(err, fmt.Sprintf("error creating IP List Items")))
}
Expand All @@ -126,20 +153,23 @@ func resourceCloudflareIPListDelete(ctx context.Context, d *schema.ResourceData,
client := meta.(*cloudflare.API)
accountID := d.Get("account_id").(string)

_, err := client.DeleteIPList(ctx, accountID, d.Id())
_, err := client.DeleteList(ctx, cloudflare.ListDeleteParams{
AccountID: accountID,
ID: d.Id(),
})
if err != nil {
return diag.FromErr(errors.Wrap(err, fmt.Sprintf("error deleting IP List with ID %q", d.Id())))
}

return nil
}

func buildIPListItemsCreateRequest(items []interface{}) []cloudflare.IPListItemCreateRequest {
var IPListItems []cloudflare.IPListItemCreateRequest
func buildIPListItemsCreateRequest(items []interface{}) []cloudflare.ListItemCreateRequest {
var IPListItems []cloudflare.ListItemCreateRequest

for _, item := range items {
IPListItems = append(IPListItems, cloudflare.IPListItemCreateRequest{
IP: item.(map[string]interface{})["value"].(string),
IPListItems = append(IPListItems, cloudflare.ListItemCreateRequest{
IP: cloudflare.StringPtr(item.(map[string]interface{})["value"].(string)),
Comment: item.(map[string]interface{})["comment"].(string),
})
}
Expand Down
10 changes: 8 additions & 2 deletions internal/provider/resource_cloudflare_ip_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ func TestAccCloudflareIPList_Exists(t *testing.T) {
var IPList cloudflare.IPList

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckAccount(t) },
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAccount(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Expand Down Expand Up @@ -61,7 +64,10 @@ func TestAccCloudflareIPList_UpdateDescription(t *testing.T) {
var initialID string

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckAccount(t) },
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckAccount(t)
},
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Expand Down
Loading