Skip to content

Commit

Permalink
New Data Source: cloudflare_zones
Browse files Browse the repository at this point in the history
1. Tested website manually
2. Tested website with `make website-test`
3. Tested new data source with new integration tests

Signed-off-by: Edward Wilde <[email protected]>
  • Loading branch information
ewilde committed Nov 25, 2018
1 parent eda9add commit ac8b484
Show file tree
Hide file tree
Showing 5 changed files with 347 additions and 1 deletion.
124 changes: 124 additions & 0 deletions cloudflare/data_source_zones.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package cloudflare

import (
"fmt"
"github.com/cloudflare/cloudflare-go"
"github.com/hashicorp/terraform/helper/schema"
"log"
"regexp"
"time"
)

func dataSourceCloudflareZones() *schema.Resource {
return &schema.Resource{
Read: dataSourceCloudflareZonesRead,

Schema: map[string]*schema.Schema{

"filter": {
Type: schema.TypeList,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"zone": {
Type: schema.TypeString,
Optional: true,
},
"status": {
Type: schema.TypeString,
Optional: true,
},
"paused": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
},
},
"zones": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
},
}
}

func dataSourceCloudflareZonesRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("[DEBUG] Reading Zones")
client := meta.(*cloudflare.API)
filter, err := expandFilter(d.Get("filter"))
if err != nil {
return err
}

zones, err := client.ListZones()
if err != nil {
return fmt.Errorf("error listing Zone: %s", err)
}

var zoneNames []string
for _, v := range zones {

if filter.zone != nil {
if !filter.zone.Match([]byte(v.Name)) {
continue
}
}

if filter.paused != v.Paused {
continue
}

if filter.status != "" && filter.status != v.Status {
continue
}

zoneNames = append(zoneNames, v.Name)
}

err = d.Set("zones", zoneNames)
if err != nil {
return fmt.Errorf("Error setting zones: %s", err)
}

d.SetId(time.Now().UTC().String())
return nil
}

func expandFilter(d interface{}) (*searchFilter, error) {
cfg := d.([]interface{})
filter := &searchFilter{}

m := cfg[0].(map[string]interface{})
zone, ok := m["zone"]
if ok {
match, err := regexp.Compile(zone.(string))
if err != nil {
return nil, err
}

filter.zone = match
}

paused, ok := m["paused"]
if ok {
filter.paused = paused.(bool)
}

status, ok := m["status"]
if ok {
filter.status = status.(string)
}

return filter, nil
}

type searchFilter struct {
zone *regexp.Regexp
status string
paused bool
}
160 changes: 160 additions & 0 deletions cloudflare/data_source_zones_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package cloudflare

import (
"fmt"
"strconv"
"testing"

"github.com/hashicorp/terraform/terraform"

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

func TestAccCloudflareZonesMatchName(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCloudflareZonesConfigMatchName(),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudflareZonesDataSourceID("data.cloudflare_zones.examples_domains"),
resource.TestCheckResourceAttr("data.cloudflare_zones.examples_domains", "zones.#", "2"),
),
},
},
})
}

func TestAccCloudflareZonesMatchPaused(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCloudflareZonesConfigMatchPaused(),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudflareZonesDataSourceID("data.cloudflare_zones.examples_domains"),
resource.TestCheckResourceAttr("data.cloudflare_zones.examples_domains", "zones.#", "1"),
),
},
},
})
}

func TestAccCloudflareZonesMatchStatus(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccCloudflareZonesConfigMatchStatus(),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudflareZonesDataSourceID("data.cloudflare_zones.examples_domains"),
testAccCheckCloudflareZonesReturned("data.cloudflare_zones.examples_domains", "zones.#", func(i int) bool {
return i >= 1 && i <= 2
}),
),
},
},
})
}

func testAccCheckCloudflareZonesDataSourceID(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
all := s.RootModule().Resources
rs, ok := all[n]
if !ok {
return fmt.Errorf("Can't find zones data source: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("Snapshot zones source ID not set")
}
return nil
}
}

func testAccCheckCloudflareZonesReturned(n string, a string, check func(int) bool) resource.TestCheckFunc {
return func(s *terraform.State) error {
all := s.RootModule().Resources
rs, ok := all[n]
if !ok {
return fmt.Errorf("Can't find zones data source: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("Snapshot zones source ID not set")
}

count, _ := strconv.Atoi(rs.Primary.Attributes[a])
if !check(count) {
return fmt.Errorf("Error evaluating %s.%s actual count: %d", n, a, count)
}
return nil
}
}

func testAccCloudflareZonesConfigMatchName() string {
return fmt.Sprintf(`
data "cloudflare_zones" "examples_domains" {
filter {
zone = "baa.*"
paused = "${cloudflare_zone.foo_net.paused}" // true
}
}
%s
`, testZones)
}

func testAccCloudflareZonesConfigMatchPaused() string {
return fmt.Sprintf(`
data "cloudflare_zones" "examples_domains" {
filter {
zone = "baa.*"
paused = "${cloudflare_zone.baa_com.paused}" // false
}
}
%s
`, testZones)
}

func testAccCloudflareZonesConfigMatchStatus() string {
return fmt.Sprintf(`
data "cloudflare_zones" "examples_domains" {
filter {
status = "active"
paused = "${cloudflare_zone.baa_com.paused}" // false
}
}
%s
`, testZones)
}

const testZones = `resource "cloudflare_zone" "baa_com" {
zone = "baa.com"
paused = false
jump_start = false
}
resource "cloudflare_zone" "baa_org" {
zone = "baa.org"
paused = true
jump_start = false
}
resource "cloudflare_zone" "baa_net" {
zone = "baa.net"
paused = true
jump_start = false
}
resource "cloudflare_zone" "foo_net" {
zone = "foo.net"
paused = true
jump_start = false
depends_on = ["cloudflare_zone.baa_net", "cloudflare_zone.baa_org", "cloudflare_zone.baa_com"]
}`
1 change: 1 addition & 0 deletions cloudflare/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func Provider() terraform.ResourceProvider {

DataSourcesMap: map[string]*schema.Resource{
"cloudflare_ip_ranges": dataSourceCloudflareIPRanges(),
"cloudflare_zones": dataSourceCloudflareZones(),
},

ResourcesMap: map[string]*schema.Resource{
Expand Down
5 changes: 4 additions & 1 deletion website/cloudflare.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
<li<%= sidebar_current("docs-cloudflare-datasource-ip_ranges") %>>
<a href="/docs/providers/cloudflare/d/ip_ranges.html">cloudflare_ip_ranges</a>
</li>
</ul>
<li<%= sidebar_current("docs-cloudflare-datasource-zones") %>>
<a href="/docs/providers/cloudflare/d/zones.html">cloudflare_zones</a>
</li>
</ul>
</li>

<li<%= sidebar_current("docs-cloudflare-resource") %>>
Expand Down
58 changes: 58 additions & 0 deletions website/docs/d/zones.html.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
layout: "cloudflare"
page_title: "Cloudflare: cloudflare_zones"
sidebar_current: "docs-cloudflare-datasource-zones"
description: |-
Get information on a Cloudflare Zones.
---

# cloudflare_zones

Use this data source to look up [Zone][1] records.

## Example Usage

The example below matches all `active` zones that begin with `example.` and are not paused. The matched zones are then
locked down using the `cloudflare_zone_lockdown` resource.

```hcl
data "cloudflare_zones" "test" {
filter {
zone = "example.*"
status = "active"
paused = false
}
}
resource "cloudflare_zone_lockdown" "endpoint_lockdown" {
count = "${length(data.cloudflare_zones.test.zones)}"
zone = "${element(data.cloudflare_zones.test.zones, count.index)}"
paused = "false"
description = "Restrict access to these endpoints to requests from a known IP address"
urls = [
"api.mysite.com/some/endpoint*",
]
configurations = [
{
"target" = "ip"
"value" = "198.51.100.4"
},
]
}
```

## Argument Reference
- `filter` - (Required) One or more values used to look up zone records. If more than one value is given all
values must match in order to be included, see below for full list.

**filter**

- `zone` - (Optional) A regular expression matching the zone to lookup.
- `status` - (Optional) Status of the zone to lookup. Valid values: active, pending, initializing, moved, deleted, deactivated and read only.
- `paused` - (Optional) Paused status of the zone to lookup. Valid values are `true` or `false`.

## Attributes Reference

- `zones` - A list of zone names

[1]: https://api.cloudflare.com/#zone-properties

0 comments on commit ac8b484

Please sign in to comment.