-
Notifications
You must be signed in to change notification settings - Fork 630
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for
cloudflare_custom_pages
resource
This introduces support for managing the custom error pages as a Terraform resource. Depends on cloudflare/cloudflare-go#240 however I will wait for that to land and then propose a PR that updates the vendored library in a separate PR.
- Loading branch information
1 parent
6ee7a1a
commit 3572050
Showing
5 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
package cloudflare | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"strings" | ||
|
||
cloudflare "github.com/cloudflare/cloudflare-go" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"github.com/hashicorp/terraform/helper/validation" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
func resourceCloudflareCustomPages() *schema.Resource { | ||
return &schema.Resource{ | ||
// Pointing the `Create` at the `Update` method here is intentional. | ||
// Custom pages don't really get "created" as they are always | ||
// present in Cloudflare. We just update and toggle the settings to | ||
// be customised. | ||
Create: resourceCloudflareCustomPagesUpdate, | ||
Read: resourceCloudflareCustomPagesRead, | ||
Update: resourceCloudflareCustomPagesUpdate, | ||
Delete: resourceCloudflareCustomPagesDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: resourceCloudflareCustomPagesImport, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"zone_id": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ConflictsWith: []string{"account_id"}, | ||
}, | ||
"account_id": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ConflictsWith: []string{"zone_id"}, | ||
}, | ||
"type": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ValidateFunc: validation.StringInSlice([]string{ | ||
"basic_challenge", | ||
"waf_challenge", | ||
"waf_block", | ||
"ratelimit_block", | ||
"country_challenge", | ||
"ip_block", | ||
"under_attack", | ||
"500_errors", | ||
"1000_errors", | ||
"always_online", | ||
}, true), | ||
}, | ||
"url": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"state": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ValidateFunc: validation.StringInSlice([]string{"default", "customized"}, true), | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceCloudflareCustomPagesRead(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*cloudflare.API) | ||
zoneID := d.Get("zone_id").(string) | ||
accountID := d.Get("account_id").(string) | ||
pageType := d.Get("type").(string) | ||
|
||
if accountID == "" && zoneID == "" { | ||
return fmt.Errorf("either `account_id` or `zone_id` must be set") | ||
} | ||
|
||
var pageOptions cloudflare.CustomPageOptions | ||
|
||
if accountID != "" { | ||
pageOptions = cloudflare.CustomPageOptions{AccountID: accountID} | ||
} else { | ||
pageOptions = cloudflare.CustomPageOptions{ZoneID: zoneID} | ||
} | ||
|
||
page, err := client.CustomPage(&pageOptions, pageType) | ||
if err != nil { | ||
return errors.New(err.Error()) | ||
} | ||
|
||
// If the `page.State` comes back as "default", it's safe to assume we | ||
// don't need to keep the ID managed anymore as it will be relying on | ||
// Cloudflare's default pages. | ||
if page.State == "default" { | ||
log.Printf("[INFO] removing custom page configuration for '%s' as it is marked as being in the default state", pageType) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
d.Set("state", page.State) | ||
d.Set("url", page.URL) | ||
d.Set("type", page.ID) | ||
|
||
return nil | ||
} | ||
|
||
func resourceCloudflareCustomPagesUpdate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*cloudflare.API) | ||
accountID := d.Get("account_id").(string) | ||
zoneID := d.Get("zone_id").(string) | ||
|
||
var pageOptions cloudflare.CustomPageOptions | ||
if accountID != "" { | ||
pageOptions = cloudflare.CustomPageOptions{AccountID: accountID} | ||
} else { | ||
pageOptions = cloudflare.CustomPageOptions{ZoneID: zoneID} | ||
} | ||
|
||
pageType := d.Get("type").(string) | ||
customPageParameters := cloudflare.CustomPageParameters{ | ||
URL: d.Get("url").(*string), | ||
State: "customized", | ||
} | ||
_, err := client.UpdateCustomPage(&pageOptions, pageType, customPageParameters) | ||
if err != nil { | ||
return errors.Wrap(err, fmt.Sprintf("failed to update '%s' custom page", pageType)) | ||
} | ||
|
||
return resourceCloudflareCustomPagesRead(d, meta) | ||
} | ||
|
||
func resourceCloudflareCustomPagesDelete(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*cloudflare.API) | ||
accountID := d.Get("account_id").(string) | ||
zoneID := d.Get("zoneID").(string) | ||
|
||
var pageOptions cloudflare.CustomPageOptions | ||
if accountID != "" { | ||
pageOptions = cloudflare.CustomPageOptions{AccountID: accountID} | ||
} else { | ||
pageOptions = cloudflare.CustomPageOptions{ZoneID: zoneID} | ||
} | ||
|
||
pageType := d.Get("type").(string) | ||
customPageParameters := cloudflare.CustomPageParameters{ | ||
URL: nil, | ||
State: "default", | ||
} | ||
_, err := client.UpdateCustomPage(&pageOptions, pageType, customPageParameters) | ||
if err != nil { | ||
return errors.Wrap(err, fmt.Sprintf("failed to update '%s' custom page", pageType)) | ||
} | ||
|
||
return resourceCloudflareCustomPagesRead(d, meta) | ||
} | ||
|
||
func resourceCloudflareCustomPagesImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { | ||
attributes := strings.SplitN(d.Id(), "/", 3) | ||
if len(attributes) != 3 { | ||
return nil, fmt.Errorf("invalid id (\"%s\") specified, should be in format \"requestType/ID/pageType\"", d.Id()) | ||
} | ||
requestType, identifier, pageType := attributes[0], attributes[1], attributes[2] | ||
|
||
d.Set("type", pageType) | ||
|
||
if requestType == "account" { | ||
d.Set("account_id", identifier) | ||
} else { | ||
d.Set("zone_id", identifier) | ||
} | ||
|
||
resourceCloudflareCustomPagesRead(d, meta) | ||
|
||
return []*schema.ResourceData{d}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
--- | ||
layout: "cloudflare" | ||
page_title: "Cloudflare: cloudflare_custom_pages" | ||
sidebar_current: "docs-cloudflare-resource-custom-pages" | ||
description: |- | ||
Provides a resource which manages Cloudflare custom pages. | ||
--- | ||
|
||
# cloudflare_custom_pages | ||
|
||
Provides a resource which manages Cloudflare custom error pages. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
resource "cloudflare_custom_pages" "basic_challenge" { | ||
zone_id = "d41d8cd98f00b204e9800998ecf8427e" | ||
type = "basic_challenge" | ||
url = "https://example.com/challenge.html" | ||
state = "customized" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `zone_id` - (Optional) The zone ID where the custom pages should be | ||
updated. Either `zone_id` or `account_id` must be provided. | ||
* `account_id` - (Optional) The account ID where the custom pages should be | ||
updated. Either `account_id` or `zone_id` must be provided. If | ||
`account_id` is present, it will override the zone setting. | ||
* `type` - (Required) The type of custom page you wish to update. Must | ||
be one of `basic_challenge`, `waf_challenge`, `waf_block`, | ||
`ratelimit_block`, `country_challenge`, `ip_block`, `under_attack`, | ||
`500_errors`, `1000_errors`, `always_online`. | ||
* `url` - (Required) URL of where the custom page source is located. | ||
* `state` - (Required) Managed state of the custom page. Must be one of | ||
`default`, `customised`. If the value is `default` it will be removed | ||
from the Terraform state management. | ||
|
||
## Import | ||
|
||
Custom pages can be imported using a composite ID formed of: | ||
|
||
* `customPageLevel` - Either `account` or `zone`. | ||
* `identifier` - The ID of the account or zone you intend to manage. | ||
* `pageType` - The value from the `type` argument. | ||
|
||
Example for a zone: | ||
|
||
``` | ||
$ terraform import cloudflare_custom_pages.basic_challenge zone/d41d8cd98f00b204e9800998ecf8427e/basic_challenge | ||
``` | ||
|
||
Example for an account: | ||
|
||
``` | ||
$ terraform import cloudflare_custom_pages.basic_challenge account/e268443e43d93dab7ebef303bbe9642f/basic_challenge | ||
``` |