diff --git a/builtin/providers/cloudflare/provider.go b/builtin/providers/cloudflare/provider.go index 5dae2005b64f..ea698cf1f38e 100644 --- a/builtin/providers/cloudflare/provider.go +++ b/builtin/providers/cloudflare/provider.go @@ -26,6 +26,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "cloudflare_record": resourceCloudFlareRecord(), + "cloudflare_page_rule": resourceCloudFlarePageRule(), }, ConfigureFunc: providerConfigure, diff --git a/builtin/providers/cloudflare/resource_cloudflare_page_rule.go b/builtin/providers/cloudflare/resource_cloudflare_page_rule.go new file mode 100644 index 000000000000..81b4463fe874 --- /dev/null +++ b/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.") +} diff --git a/builtin/providers/cloudflare/validators.go b/builtin/providers/cloudflare/validators.go index 15dc51c6d601..0e3ec6ca6e12 100644 --- a/builtin/providers/cloudflare/validators.go +++ b/builtin/providers/cloudflare/validators.go @@ -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.")} +} diff --git a/builtin/providers/cloudflare/validators_test.go b/builtin/providers/cloudflare/validators_test.go index 0c97b18dc041..58f2a508f6ee 100644 --- a/builtin/providers/cloudflare/validators_test.go +++ b/builtin/providers/cloudflare/validators_test.go @@ -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) + } + } +}