Skip to content

Commit

Permalink
New resource: cloudflare_zone. Closes #58
Browse files Browse the repository at this point in the history
  • Loading branch information
patryk committed Oct 18, 2018
1 parent 739e4b8 commit 0f29f0b
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 0 deletions.
1 change: 1 addition & 0 deletions cloudflare/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func Provider() terraform.ResourceProvider {
"cloudflare_waf_rule": resourceCloudflareWAFRule(),
"cloudflare_worker_route": resourceCloudflareWorkerRoute(),
"cloudflare_worker_script": resourceCloudflareWorkerScript(),
"cloudflare_zone": resourceCloudflareZone(),
"cloudflare_zone_lockdown": resourceCloudflareZoneLockdown(),
"cloudflare_zone_settings_override": resourceCloudflareZoneSettingsOverride(),
"cloudflare_account_member": resourceCloudflareAccountMember(),
Expand Down
189 changes: 189 additions & 0 deletions cloudflare/resource_cloudflare_zone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package cloudflare

import (
"fmt"
"log"
"regexp"
"strconv"
"strings"

cloudflare "github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

func resourceCloudflareZone() *schema.Resource {
return &schema.Resource{
Create: resourceCloudflareZoneCreate,
Read: resourceCloudflareZoneRead,
Update: resourceCloudflareZoneUpdate,
Delete: resourceCloudflareZoneDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"zone": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile("^([a-zA-Z0-9][\\-a-zA-Z0-9]*\\.)+[\\-a-zA-Z0-9]{2,20}$"), ""),
},
"jump_start": {
Type: schema.TypeBool,
Optional: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return true
},
},
"paused": {
Type: schema.TypeBool,
Optional: true,
},
"vanity_name_servers": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"meta": {
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"page_rule_quota": {
Type: schema.TypeInt,
},
"wildcard_proxiable": {
Type: schema.TypeBool,
},
"phishing_detected": {
Type: schema.TypeBool,
},
},
},
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"type": {
Type: schema.TypeString,
Computed: true,
},
"name_servers": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}
func resourceCloudflareZoneCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)

zoneName := d.Get("zone").(string)
jumpstart := d.Get("jump_start").(bool)
organization := cloudflare.Organization{
ID: client.OrganizationID,
}

log.Printf("[INFO] Creating Cloudflare Zone: name %s", zoneName)

zone, err := client.CreateZone(zoneName, jumpstart, organization)

if err != nil {
return fmt.Errorf("Error creating zone %q: %s", zoneName, err)
}

d.SetId(zone.ID)

if paused, ok := d.GetOk("paused"); ok {
if paused.(bool) == true {
_, err := client.ZoneSetPaused(zone.ID, paused.(bool))

if err != nil {
return fmt.Errorf("Error updating zone_id %q: %s", zone.ID, err)
}
}
}

return resourceCloudflareZoneRead(d, meta)
}

func resourceCloudflareZoneRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)
zoneID := d.Id()

zone, err := client.ZoneDetails(zoneID)

log.Printf("[DEBUG] ZoneDetails: %#v", zone)
log.Printf("[DEBUG] ZoneDetails error: %#v", err)

if err != nil {
if strings.Contains(err.Error(), "HTTP status 404") {
log.Printf("[INFO] Zone %s no longer exists", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("Error finding Zone %q: %s", d.Id(), err)
}

d.Set("paused", zone.Paused)
d.Set("vanity_name_servers", zone.VanityNS)
d.Set("status", zone.Status)
d.Set("type", zone.Type)
d.Set("name_servers", zone.NameServers)
d.Set("meta", flattenMeta(d, zone.Meta))

return nil
}

func resourceCloudflareZoneUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)
zoneID := d.Id()

log.Printf("[INFO] Updating Cloudflare Zone: id %s", zoneID)

if paused, ok := d.GetOkExists("paused"); ok {
log.Printf("[DEBUG] _ paused")

_, err := client.ZoneSetPaused(zoneID, paused.(bool))

if err != nil {
return fmt.Errorf("Error updating zone_id %q: %s", zoneID, err)
}
}

return resourceCloudflareZoneRead(d, meta)
}

func resourceCloudflareZoneDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*cloudflare.API)
zoneID := d.Id()

log.Printf("[INFO] Deleting Cloudflare Zone: id %s", zoneID)

_, err := client.DeleteZone(zoneID)

if err != nil {
return fmt.Errorf("Error deleting Cloudflare Zone: %s", err)
}

return nil
}

func flattenMeta(d *schema.ResourceData, meta cloudflare.ZoneMeta) map[string]interface{} {
cfg := map[string]interface{}{}

cfg["page_rule_quota"] = strconv.Itoa(meta.PageRuleQuota)
cfg["wildcard_proxiable"] = strconv.FormatBool(meta.WildcardProxiable)
cfg["phishing_detected"] = strconv.FormatBool(meta.PhishingDetected)

log.Printf("[DEBUG] flattenMeta %#v", cfg)

return cfg
}
36 changes: 36 additions & 0 deletions cloudflare/resource_cloudflare_zone_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cloudflare

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/resource"
)

func TestZone(t *testing.T) {
name := "cloudflare_zone.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testZoneConfig("test", "example.org", "true", "false"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(name, "zone", "example.org"),
resource.TestCheckResourceAttr(name, "paused", "true"),
resource.TestCheckResourceAttr(name, "name_servers.#", "2"),
),
},
},
})
}

func testZoneConfig(resourceID, zoneName, paused, jumpStart string) string {
return fmt.Sprintf(`
resource "cloudflare_zone" "%[1]s" {
zone = "%[2]s"
paused = %[3]s
jump_start = %[4]s
}`, resourceID, zoneName, paused, jumpStart)
}
3 changes: 3 additions & 0 deletions website/cloudflare.erb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
<li<%= sidebar_current("docs-cloudflare-resource-worker-script") %>>
<a href="/docs/providers/cloudflare/r/worker_script.html">cloudflare_worker_script</a>
</li>
<li<%= sidebar_current("docs-cloudflare-resource-zone") %>>
<a href="/docs/providers/cloudflare/r/zone.html">cloudflare_zone</a>
</li>
<li<%= sidebar_current("docs-cloudflare-resource-zone-lockdown") %>>
<a href="/docs/providers/cloudflare/r/zone_lockdown.html">cloudflare_zone_lockdown</a>
</li>
Expand Down
51 changes: 51 additions & 0 deletions website/docs/r/zone.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
layout: "cloudflare"
page_title: "Cloudflare: cloudflare_zone"
sidebar_current: "docs-cloudflare-resource-zone"
description: |-
Provides a Cloudflare resource to create and modify a zone.
---

# cloudflare_zone

Provides a Cloudflare Zone resource. Zone is the basic resource for working with Cloudflare and is roughly equivalent to a domain name that the user purchases.

## Example Usage

```hcl
resource "cloudflare_zone" "example" {
zone = "example.com"
}
```

## Argument Reference

The following arguments are supported:
* `zone` - (Required) The DNS zone name which will be added.
* `paused` - (Optional) Boolean of whether this zone is paused (traffic bypasses Cloudflare). Default: false.
* `jump_start` - (Optional) Boolean of whether to scan for DNS records on creation. Ignored after zone is created. Default: false.

## Attributes Reference

The following attributes are exported:

* `id` - The zone ID.
* `vanity_name_servers` - List of Vanity Nameservers (if set).
* `meta.page_rule_quota` - Number of page rules that can be created.
* `meta.wildcard_proxiable` - Indicates whether wildcard DNS records can receive Cloudflare security and performance features.
* `meta.phishing_detected` - Indicates if URLs on the zone have been identified as hosting phishing content.
* `status` - Status of the zone. Valid values: `active`, `pending`, `initializing`, `moved`, `deleted`, `deactivated`
* `type` - A full zone implies that DNS is hosted with Cloudflare. A partial zone is typically a partner-hosted zone or a CNAME setup. Valid values: `full`, `partial`
* `name_servers` - Cloudflare-assigned name servers. This is only populated for zones that use Cloudflare DNS.

## Import

Zone resource can be imported using a zone ID, e.g.

```
$ terraform import cloudflare_zone.example d41d8cd98f00b204e9800998ecf8427e
```

where:

* `d41d8cd98f00b204e9800998ecf8427e` - zone ID, as returned from [API](https://api.cloudflare.com/#zone-list-zones)

0 comments on commit 0f29f0b

Please sign in to comment.