Skip to content

Commit

Permalink
Add structs; impl Create for CloudFlare PageRules
Browse files Browse the repository at this point in the history
This commit adds most of the boilerplate for implementing CloudFlare
Page Rules, and implements the Create method.

`PageRuleActionValue`s still need a validator; this is complex and
depends on `PageRuleActionId`.

Read, Update, and Delete methods will throw 'not implemented' errors.

Towards hashicorp#9040.
  • Loading branch information
OJFord committed Jan 18, 2017
1 parent b4eda2f commit 58e53b4
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 1 deletion.
3 changes: 2 additions & 1 deletion builtin/providers/cloudflare/provider.go
Expand Up @@ -25,7 +25,8 @@ func Provider() terraform.ResourceProvider {
},

ResourcesMap: map[string]*schema.Resource{
"cloudflare_record": resourceCloudFlareRecord(),
"cloudflare_record": resourceCloudFlareRecord(),
"cloudflare_page_rule": resourceCloudFlarePageRule(),
},

ConfigureFunc: providerConfigure,
Expand Down
139 changes: 139 additions & 0 deletions builtin/providers/cloudflare/resource_cloudflare_page_rule.go
@@ -0,0 +1,139 @@
package cloudflare

import (
"fmt"
"log"

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

func resourceCloudFlarePageRule() *schema.Resource {
return &schema.Resource{
Create: resourceCloudFlarePageRuleCreate,
Read: resourceCloudFlarePageRuleRead,
Update: resourceCloudFlarePageRuleUpdate,
Delete: resourceCloudFlarePageRuleDelete,

SchemaVersion: 1,
Schema: map[string]*schema.Schema{
"domain": &schema.Schema{
Type: schema.TypeString,
Required: true,
},

"targets": &schema.Schema{
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"url_pattern": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
},
},
},

"actions": &schema.Schema{
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"action": &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: validatePageRuleActionID,
},

"value": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ValidateFunc: validatePageRuleActionValue,
},
},
},
},

"priority": &schema.Schema{
Type: schema.TypeInt,
Default: 1,
Optional: true,
},

"status": &schema.Schema{
Type: schema.TypeString,
Required: true,
Default: "active",
ValidateFunc: validatePageRuleStatus,
},
},
}
}

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

targets := d.Get("targets").([]interface{})
actions := d.Get("actions").([]interface{})

newPageRuleTargets := make([]cloudflare.PageRuleTarget, 0, len(targets))
newPageRuleActions := make([]cloudflare.PageRuleAction, 0, len(actions))

for _, target := range targets {
newPageRuleTarget := cloudflare.PageRuleTarget{
Target: "url",
Constraint: struct {
Operator string `json:"operator"`
Value string `json:"value"`
}{
Operator: "matches",
Value: target.(schema.Resource).Schema["url_pattern"].Elem.(string),
},
}
newPageRuleTargets = append(newPageRuleTargets, newPageRuleTarget)
}

for _, action := range actions {
newPageRuleActions = append(newPageRuleActions, cloudflare.PageRuleAction{
ID: action.(schema.Resource).Schema["action"].Elem.(string),
Value: action.(schema.Resource).Schema["value"].Elem.(string),
})
}

newPageRule := cloudflare.PageRule{
Targets: newPageRuleTargets,
Actions: newPageRuleActions,
Priority: d.Get("priority").(int),
Status: d.Get("status").(string),
}

zoneName := d.Get("domain").(string)

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

d.Set("zone_id", zoneId)
log.Printf("[DEBUG] CloudFlare Page Rule create configuration: %#v", newPageRule)

err = client.CreatePageRule(zoneId, newPageRule)
if err != nil {
return fmt.Errorf("Failed to create page rule: %s", err)
}

return resourceCloudFlarePageRuleRead(d, meta)
}

func resourceCloudFlarePageRuleRead(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("Page Rule Read not implemented.")
}

func resourceCloudFlarePageRuleUpdate(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("Page Rule Update not implemented.")
}

func resourceCloudFlarePageRuleDelete(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("Page Rule Delete not implemented.")
}
52 changes: 52 additions & 0 deletions builtin/providers/cloudflare/validators.go
Expand Up @@ -49,3 +49,55 @@ func validateRecordName(t string, value string) error {

return nil
}

func validatePageRuleStatus(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)

validStatuses := map[string]struct{}{
"active": {},
"paused": {},
}

if _, ok := validStatuses[value]; !ok {
errors = append(errors, fmt.Errorf(
`%q contains an invalid status %q. Valid statuses are "active" or "paused"`, k, value))
}
return
}

func validatePageRuleActionID(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)

validIDs := map[string]struct{}{
"always_online": {},
"always_use_https": {},
"browser_cache_ttl": {},
"browser_check": {},
"cache_level": {},
"disable_apps": {},
"disable_performance": {},
"disable_railgun": {},
"disable_security": {},
"edge_cache_ttl": {},
"email_obfuscation": {},
"forwarding_url": {},
"ip_geolocation": {},
"mirage": {},
"rocket_loader": {},
"security_level": {},
"server_side_exclude": {},
"smart_errors": {},
"ssl": {},
"waf": {},
}

if _, ok := validIDs[value]; !ok {
errors = append(errors, fmt.Errorf(
`%q contains an invalid action ID %q. Valid IDs are "always_online", "always_use_https", "browser_cache_ttl", "browser_check", "cache_level", "disable_apps", "disable_performance", "disable_railgun", "disable_security", "edge_cache_ttl", "email_obfuscation", "forwarding_url", "ip_geolocation", "mirage", "rocket_loader", "security_level", "server_side_exclude", "smart_errors", "ssl", or "waf"`, k, value))
}
return
}

func validatePageRuleActionValue(v interface{}, k string) (ws []string, errors []error) {
return []string{}, []error{fmt.Errorf("Page Rule action value validation not implemented.")}
}
74 changes: 74 additions & 0 deletions builtin/providers/cloudflare/validators_test.go
Expand Up @@ -59,3 +59,77 @@ func TestValidateRecordName(t *testing.T) {
}
}
}

func TestValidatePageRuleStatus(t *testing.T) {
validStatuses := []string{
"active",
"paused",
}
for _, v := range validStatuses {
_, errors := validatePageRuleStatus(v, "status")
if len(errors) != 0 {
t.Fatalf("%q should be a valid page rule status: %q", v, errors)
}
}

invalidStatuses := []string{
"on",
"live",
"yes",
"no",
"true",
"false",
"running",
"stopped",
}
for _, v := range invalidStatuses {
_, errors := validatePageRuleStatus(v, "status")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid page rule status: %q", v, errors)
}
}
}

func TestValidatePageRuleActionIDs(t *testing.T) {
validActionIDs := []string{
"always_online",
"always_use_https",
"browser_cache_ttl",
"browser_check",
"cache_level",
"disable_apps",
"disable_performance",
"disable_railgun",
"disable_security",
"edge_cache_ttl",
"email_obfuscation",
"forwarding_url",
"ip_geolocation",
"mirage",
"rocket_loader",
"security_level",
"server_side_exclude",
"smart_errors",
"ssl",
"waf",
}
for _, v := range validActionIDs {
_, errors := validatePageRuleActionID(v, "action")
if len(errors) != 0 {
t.Fatalf("%q should be a valid page rule action: %q", v, errors)
}
}

invalidActionIDs := []string{
"foo",
"tls",
"disable_foobar",
"hunter2",
}
for _, v := range invalidActionIDs {
_, errors := validatePageRuleActionID(v, "action")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid page rule action: %q", v, errors)
}
}
}

0 comments on commit 58e53b4

Please sign in to comment.