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/terraform#9040; cloudflare#3.
  • Loading branch information
OJFord committed Jul 5, 2017
1 parent 2e22029 commit 69eaf3c
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 69 deletions.
3 changes: 2 additions & 1 deletion 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 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,
Default: "active",
Optional: true,
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.")
}
106 changes: 70 additions & 36 deletions cloudflare/validators.go
Expand Up @@ -7,44 +7,26 @@ import (
)

// validateRecordType ensures that the cloudflare record type is valid
func validateRecordType(t string, proxied bool) error {
switch t {
case "A":
return nil
case "AAAA":
return nil
case "CNAME":
return nil
case "TXT":
if !proxied {
return nil
}
case "SRV":
if !proxied {
return nil
}
case "LOC":
if !proxied {
return nil
}
case "MX":
if !proxied {
return nil
}
case "NS":
if !proxied {
return nil
}
case "SPF":
if !proxied {
return nil
}
default:
return fmt.Errorf(
`Invalid type %q. Valid types are "A", "AAAA", "CNAME", "TXT", "SRV", "LOC", "MX", "NS" or "SPF"`, t)
func validateRecordType(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)

validTypes := map[string]struct{}{
"A": {},
"AAAA": {},
"CNAME": {},
"TXT": {},
"SRV": {},
"LOC": {},
"MX": {},
"NS": {},
"SPF": {},
}

return fmt.Errorf("Type %q cannot be proxied", t)
if _, ok := validTypes[value]; !ok {
errors = append(errors, fmt.Errorf(
`%q contains an invalid type %q. Valid types are "A", "AAAA", "CNAME", "TXT", "SRV", "LOC", "MX", "NS" or "SPF"`, k, value))
}
return
}

// validateRecordName ensures that based on supplied record type, the name content matches
Expand All @@ -67,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.")}
}

0 comments on commit 69eaf3c

Please sign in to comment.