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 2a9c015
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 1 deletion.
3 changes: 2 additions & 1 deletion builtin/providers/cloudflare/provider.go
Original file line number Diff line number Diff line change
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
138 changes: 138 additions & 0 deletions builtin/providers/cloudflare/resource_cloudflare_page_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
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,
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 2a9c015

Please sign in to comment.