provider/fastly: Add support for Request Headers (#6197)
* provider/fastly: Add support for managing Headers Adds support for managing Headers in a Fastly configuration. * update acc test * update website with example of adding a header block
This commit is contained in:
parent
fcdcb4b916
commit
25f89c8756
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
@ -156,6 +157,110 @@ func resourceServiceV1() *schema.Resource {
|
||||||
Type: schema.TypeBool,
|
Type: schema.TypeBool,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"header": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
// required fields
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "A name to refer to this Header object",
|
||||||
|
},
|
||||||
|
"action": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "One of set, append, delete, regex, or regex_repeat",
|
||||||
|
ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
|
||||||
|
var found bool
|
||||||
|
for _, t := range []string{"set", "append", "delete", "regex", "regex_repeat"} {
|
||||||
|
if v.(string) == t {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
es = append(es, fmt.Errorf(
|
||||||
|
"Fastly Header action is case sensitive and must be one of 'set', 'append', 'delete', 'regex', or 'regex_repeat'; found: %s", v.(string)))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"type": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Type to manipulate: request, fetch, cache, response",
|
||||||
|
ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
|
||||||
|
var found bool
|
||||||
|
for _, t := range []string{"request", "fetch", "cache", "response"} {
|
||||||
|
if v.(string) == t {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
es = append(es, fmt.Errorf(
|
||||||
|
"Fastly Header type is case sensitive and must be one of 'request', 'fetch', 'cache', or 'response'; found: %s", v.(string)))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"destination": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
Description: "Header this affects",
|
||||||
|
},
|
||||||
|
// Optional fields, defaults where they exist
|
||||||
|
"ignore_if_set": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: false,
|
||||||
|
Description: "Don't add the header if it is already. (Only applies to 'set' action.). Default `false`",
|
||||||
|
},
|
||||||
|
"source": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Variable to be used as a source for the header content (Does not apply to 'delete' action.)",
|
||||||
|
},
|
||||||
|
"regex": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Regular expression to use (Only applies to 'regex' and 'regex_repeat' actions.)",
|
||||||
|
},
|
||||||
|
"substitution": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Value to substitute in place of regular expression. (Only applies to 'regex' and 'regex_repeat'.)",
|
||||||
|
},
|
||||||
|
"priority": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
Default: 100,
|
||||||
|
Description: "Lower priorities execute first. (Default: 100.)",
|
||||||
|
},
|
||||||
|
// These fields represent Fastly options that Terraform does not
|
||||||
|
// currently support
|
||||||
|
"request_condition": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional name of a RequestCondition to apply.",
|
||||||
|
},
|
||||||
|
"cache_condition": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional name of a CacheCondition to apply.",
|
||||||
|
},
|
||||||
|
"response_condition": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
Description: "Optional name of a ResponseCondition to apply.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +299,7 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
|
||||||
// DefaultTTL, a new Version must be created first, and updates posted to that
|
// DefaultTTL, a new Version must be created first, and updates posted to that
|
||||||
// Version. Loop these attributes and determine if we need to create a new version first
|
// Version. Loop these attributes and determine if we need to create a new version first
|
||||||
var needsChange bool
|
var needsChange bool
|
||||||
for _, v := range []string{"domain", "backend", "default_host", "default_ttl"} {
|
for _, v := range []string{"domain", "backend", "default_host", "default_ttl", "header"} {
|
||||||
if d.HasChange(v) {
|
if d.HasChange(v) {
|
||||||
needsChange = true
|
needsChange = true
|
||||||
}
|
}
|
||||||
|
@ -369,6 +474,60 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if d.HasChange("header") {
|
||||||
|
// Note: we don't utilize the PUT endpoint to update a Header, we simply
|
||||||
|
// destroy it and create a new one. This is how Terraform works with nested
|
||||||
|
// sub resources, we only get the full diff not a partial set item diff.
|
||||||
|
// Because this is done on a new version of the configuration, this is
|
||||||
|
// considered safe
|
||||||
|
oh, nh := d.GetChange("header")
|
||||||
|
if oh == nil {
|
||||||
|
oh = new(schema.Set)
|
||||||
|
}
|
||||||
|
if nh == nil {
|
||||||
|
nh = new(schema.Set)
|
||||||
|
}
|
||||||
|
|
||||||
|
ohs := oh.(*schema.Set)
|
||||||
|
nhs := nh.(*schema.Set)
|
||||||
|
|
||||||
|
remove := ohs.Difference(nhs).List()
|
||||||
|
add := nhs.Difference(ohs).List()
|
||||||
|
|
||||||
|
// Delete removed headers
|
||||||
|
for _, dRaw := range remove {
|
||||||
|
df := dRaw.(map[string]interface{})
|
||||||
|
opts := gofastly.DeleteHeaderInput{
|
||||||
|
Service: d.Id(),
|
||||||
|
Version: latestVersion,
|
||||||
|
Name: df["name"].(string),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Fastly Header Removal opts: %#v", opts)
|
||||||
|
err := conn.DeleteHeader(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST new Headers
|
||||||
|
for _, dRaw := range add {
|
||||||
|
opts, err := buildHeader(dRaw.(map[string]interface{}))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[DEBUG] Error building Header: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
opts.Service = d.Id()
|
||||||
|
opts.Version = latestVersion
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Fastly Header Addition opts: %#v", opts)
|
||||||
|
_, err = conn.CreateHeader(opts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// validate version
|
// validate version
|
||||||
log.Printf("[DEBUG] Validating Fastly Service (%s), Version (%s)", d.Id(), latestVersion)
|
log.Printf("[DEBUG] Validating Fastly Service (%s), Version (%s)", d.Id(), latestVersion)
|
||||||
valid, msg, err := conn.ValidateVersion(&gofastly.ValidateVersionInput{
|
valid, msg, err := conn.ValidateVersion(&gofastly.ValidateVersionInput{
|
||||||
|
@ -447,6 +606,7 @@ func resourceServiceV1Read(d *schema.ResourceData, meta interface{}) error {
|
||||||
// TODO: update go-fastly to support an ActiveVersion struct, which contains
|
// TODO: update go-fastly to support an ActiveVersion struct, which contains
|
||||||
// domain and backend info in the response. Here we do 2 additional queries
|
// domain and backend info in the response. Here we do 2 additional queries
|
||||||
// to find out that info
|
// to find out that info
|
||||||
|
log.Printf("[DEBUG] Refreshing Domains for (%s)", d.Id())
|
||||||
domainList, err := conn.ListDomains(&gofastly.ListDomainsInput{
|
domainList, err := conn.ListDomains(&gofastly.ListDomainsInput{
|
||||||
Service: d.Id(),
|
Service: d.Id(),
|
||||||
Version: s.ActiveVersion.Number,
|
Version: s.ActiveVersion.Number,
|
||||||
|
@ -464,6 +624,7 @@ func resourceServiceV1Read(d *schema.ResourceData, meta interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh Backends
|
// Refresh Backends
|
||||||
|
log.Printf("[DEBUG] Refreshing Backends for (%s)", d.Id())
|
||||||
backendList, err := conn.ListBackends(&gofastly.ListBackendsInput{
|
backendList, err := conn.ListBackends(&gofastly.ListBackendsInput{
|
||||||
Service: d.Id(),
|
Service: d.Id(),
|
||||||
Version: s.ActiveVersion.Number,
|
Version: s.ActiveVersion.Number,
|
||||||
|
@ -478,6 +639,24 @@ func resourceServiceV1Read(d *schema.ResourceData, meta interface{}) error {
|
||||||
if err := d.Set("backend", bl); err != nil {
|
if err := d.Set("backend", bl); err != nil {
|
||||||
log.Printf("[WARN] Error setting Backends for (%s): %s", d.Id(), err)
|
log.Printf("[WARN] Error setting Backends for (%s): %s", d.Id(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// refresh headers
|
||||||
|
log.Printf("[DEBUG] Refreshing Headers for (%s)", d.Id())
|
||||||
|
headerList, err := conn.ListHeaders(&gofastly.ListHeadersInput{
|
||||||
|
Service: d.Id(),
|
||||||
|
Version: s.ActiveVersion.Number,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("[ERR] Error looking up Headers for (%s), version (%s): %s", d.Id(), s.ActiveVersion.Number, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hl := flattenHeaders(headerList)
|
||||||
|
|
||||||
|
if err := d.Set("header", hl); err != nil {
|
||||||
|
log.Printf("[WARN] Error setting Headers for (%s): %s", d.Id(), err)
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[DEBUG] Active Version for Service (%s) is empty, no state to refresh", d.Id())
|
log.Printf("[DEBUG] Active Version for Service (%s) is empty, no state to refresh", d.Id())
|
||||||
}
|
}
|
||||||
|
@ -590,7 +769,7 @@ func findService(id string, meta interface{}) (*gofastly.Service, error) {
|
||||||
|
|
||||||
l, err := conn.ListServices(&gofastly.ListServicesInput{})
|
l, err := conn.ListServices(&gofastly.ListServicesInput{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("[WARN] Error listing servcies when deleting Fastly Service (%s): %s", id, err)
|
return nil, fmt.Errorf("[WARN] Error listing services when deleting Fastly Service (%s): %s", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range l {
|
for _, s := range l {
|
||||||
|
@ -602,3 +781,77 @@ func findService(id string, meta interface{}) (*gofastly.Service, error) {
|
||||||
|
|
||||||
return nil, fastlyNoServiceFoundErr
|
return nil, fastlyNoServiceFoundErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func flattenHeaders(headerList []*gofastly.Header) []map[string]interface{} {
|
||||||
|
var hl []map[string]interface{}
|
||||||
|
for _, h := range headerList {
|
||||||
|
// Convert Header to a map for saving to state.
|
||||||
|
nh := map[string]interface{}{
|
||||||
|
"name": h.Name,
|
||||||
|
"action": h.Action,
|
||||||
|
"ignore_if_set": h.IgnoreIfSet,
|
||||||
|
"type": h.Type,
|
||||||
|
"destination": h.Destination,
|
||||||
|
"source": h.Source,
|
||||||
|
"regex": h.Regex,
|
||||||
|
"substitution": h.Substitution,
|
||||||
|
"priority": int(h.Priority),
|
||||||
|
"request_condition": h.RequestCondition,
|
||||||
|
"cache_condition": h.CacheCondition,
|
||||||
|
"response_condition": h.ResponseCondition,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range nh {
|
||||||
|
if v == "" {
|
||||||
|
delete(nh, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hl = append(hl, nh)
|
||||||
|
}
|
||||||
|
return hl
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildHeader(headerMap interface{}) (*gofastly.CreateHeaderInput, error) {
|
||||||
|
df := headerMap.(map[string]interface{})
|
||||||
|
opts := gofastly.CreateHeaderInput{
|
||||||
|
Name: df["name"].(string),
|
||||||
|
IgnoreIfSet: df["ignore_if_set"].(bool),
|
||||||
|
Destination: df["destination"].(string),
|
||||||
|
Priority: uint(df["priority"].(int)),
|
||||||
|
Source: df["source"].(string),
|
||||||
|
Regex: df["regex"].(string),
|
||||||
|
Substitution: df["substitution"].(string),
|
||||||
|
RequestCondition: df["request_condition"].(string),
|
||||||
|
CacheCondition: df["cache_condition"].(string),
|
||||||
|
ResponseCondition: df["response_condition"].(string),
|
||||||
|
}
|
||||||
|
|
||||||
|
act := strings.ToLower(df["action"].(string))
|
||||||
|
switch act {
|
||||||
|
case "set":
|
||||||
|
opts.Action = gofastly.HeaderActionSet
|
||||||
|
case "append":
|
||||||
|
opts.Action = gofastly.HeaderActionAppend
|
||||||
|
case "delete":
|
||||||
|
opts.Action = gofastly.HeaderActionDelete
|
||||||
|
case "regex":
|
||||||
|
opts.Action = gofastly.HeaderActionRegex
|
||||||
|
case "regex_repeat":
|
||||||
|
opts.Action = gofastly.HeaderActionRegexRepeat
|
||||||
|
}
|
||||||
|
|
||||||
|
ty := strings.ToLower(df["type"].(string))
|
||||||
|
switch ty {
|
||||||
|
case "request":
|
||||||
|
opts.Type = gofastly.HeaderTypeRequest
|
||||||
|
case "fetch":
|
||||||
|
opts.Type = gofastly.HeaderTypeFetch
|
||||||
|
case "cache":
|
||||||
|
opts.Type = gofastly.HeaderTypeCache
|
||||||
|
case "response":
|
||||||
|
opts.Type = gofastly.HeaderTypeResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
return &opts, nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
package fastly
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
gofastly "github.com/sethvargo/go-fastly"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFastlyServiceV1_BuildHeaders(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
remote *gofastly.CreateHeaderInput
|
||||||
|
local map[string]interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
remote: &gofastly.CreateHeaderInput{
|
||||||
|
Name: "someheadder",
|
||||||
|
Action: gofastly.HeaderActionDelete,
|
||||||
|
IgnoreIfSet: true,
|
||||||
|
Type: gofastly.HeaderTypeCache,
|
||||||
|
Destination: "http.aws-id",
|
||||||
|
Priority: uint(100),
|
||||||
|
},
|
||||||
|
local: map[string]interface{}{
|
||||||
|
"name": "someheadder",
|
||||||
|
"action": "delete",
|
||||||
|
"ignore_if_set": true,
|
||||||
|
"destination": "http.aws-id",
|
||||||
|
"priority": 100,
|
||||||
|
"source": "",
|
||||||
|
"regex": "",
|
||||||
|
"substitution": "",
|
||||||
|
"request_condition": "",
|
||||||
|
"cache_condition": "",
|
||||||
|
"response_condition": "",
|
||||||
|
"type": "cache",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
remote: &gofastly.CreateHeaderInput{
|
||||||
|
Name: "someheadder",
|
||||||
|
Action: gofastly.HeaderActionSet,
|
||||||
|
Type: gofastly.HeaderTypeCache,
|
||||||
|
Destination: "http.aws-id",
|
||||||
|
Priority: uint(100),
|
||||||
|
Source: "http.server-name",
|
||||||
|
},
|
||||||
|
local: map[string]interface{}{
|
||||||
|
"name": "someheadder",
|
||||||
|
"action": "set",
|
||||||
|
"ignore_if_set": false,
|
||||||
|
"destination": "http.aws-id",
|
||||||
|
"priority": 100,
|
||||||
|
"source": "http.server-name",
|
||||||
|
"regex": "",
|
||||||
|
"substitution": "",
|
||||||
|
"request_condition": "",
|
||||||
|
"cache_condition": "",
|
||||||
|
"response_condition": "",
|
||||||
|
"type": "cache",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
out, _ := buildHeader(c.local)
|
||||||
|
if !reflect.DeepEqual(out, c.remote) {
|
||||||
|
t.Fatalf("Error matching:\nexpected: %#v\ngot: %#v", c.remote, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccFastlyServiceV1_headers_basic(t *testing.T) {
|
||||||
|
var service gofastly.ServiceDetail
|
||||||
|
name := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||||
|
domainName1 := fmt.Sprintf("%s.notadomain.com", acctest.RandString(10))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckServiceV1Destroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccServiceV1HeadersConfig(name, domainName1),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
|
||||||
|
testAccCheckFastlyServiceV1HeaderAttributes(&service, name, []string{"http.x-amz-request-id", "http.Server"}, nil),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"fastly_service_v1.foo", "name", name),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"fastly_service_v1.foo", "header.#", "2"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccServiceV1HeadersConfig_update(name, domainName1),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
|
||||||
|
testAccCheckFastlyServiceV1HeaderAttributes(&service, name, []string{"http.x-amz-request-id", "http.Server"}, []string{"http.server-name"}),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"fastly_service_v1.foo", "name", name),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"fastly_service_v1.foo", "header.#", "3"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"fastly_service_v1.foo", "header.1147514417.source", "server.identity"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckFastlyServiceV1HeaderAttributes(service *gofastly.ServiceDetail, name string, headersDeleted, headersAdded []string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
|
||||||
|
if service.Name != name {
|
||||||
|
return fmt.Errorf("Bad name, expected (%s), got (%s)", name, service.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*FastlyClient).conn
|
||||||
|
headersList, err := conn.ListHeaders(&gofastly.ListHeadersInput{
|
||||||
|
Service: service.ID,
|
||||||
|
Version: service.ActiveVersion.Number,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("[ERR] Error looking up Headers for (%s), version (%s): %s", service.Name, service.ActiveVersion.Number, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var deleted []string
|
||||||
|
var added []string
|
||||||
|
for _, h := range headersList {
|
||||||
|
if h.Action == gofastly.HeaderActionDelete {
|
||||||
|
deleted = append(deleted, h.Destination)
|
||||||
|
}
|
||||||
|
if h.Action == gofastly.HeaderActionSet {
|
||||||
|
added = append(added, h.Destination)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(headersAdded)
|
||||||
|
sort.Strings(headersDeleted)
|
||||||
|
sort.Strings(deleted)
|
||||||
|
sort.Strings(added)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(headersDeleted, deleted) {
|
||||||
|
return fmt.Errorf("Deleted Headers did not match.\n\tExpected: (%#v)\n\tGot: (%#v)", headersDeleted, deleted)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(headersAdded, added) {
|
||||||
|
return fmt.Errorf("Added Headers did not match.\n\tExpected: (%#v)\n\tGot: (%#v)", headersAdded, added)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccServiceV1HeadersConfig(name, domain string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "fastly_service_v1" "foo" {
|
||||||
|
name = "%s"
|
||||||
|
|
||||||
|
domain {
|
||||||
|
name = "%s"
|
||||||
|
comment = "tf-testing-domain"
|
||||||
|
}
|
||||||
|
|
||||||
|
backend {
|
||||||
|
address = "aws.amazon.com"
|
||||||
|
name = "amazon docs"
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
destination = "http.x-amz-request-id"
|
||||||
|
type = "cache"
|
||||||
|
action = "delete"
|
||||||
|
name = "remove x-amz-request-id"
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
destination = "http.Server"
|
||||||
|
type = "cache"
|
||||||
|
action = "delete"
|
||||||
|
name = "remove s3 server"
|
||||||
|
}
|
||||||
|
|
||||||
|
force_destroy = true
|
||||||
|
}`, name, domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccServiceV1HeadersConfig_update(name, domain string) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "fastly_service_v1" "foo" {
|
||||||
|
name = "%s"
|
||||||
|
|
||||||
|
domain {
|
||||||
|
name = "%s"
|
||||||
|
comment = "tf-testing-domain"
|
||||||
|
}
|
||||||
|
|
||||||
|
backend {
|
||||||
|
address = "aws.amazon.com"
|
||||||
|
name = "amazon docs"
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
destination = "http.x-amz-request-id"
|
||||||
|
type = "cache"
|
||||||
|
action = "delete"
|
||||||
|
name = "remove x-amz-request-id"
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
destination = "http.Server"
|
||||||
|
type = "cache"
|
||||||
|
action = "delete"
|
||||||
|
name = "DESTROY S3"
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
destination = "http.server-name"
|
||||||
|
type = "request"
|
||||||
|
action = "set"
|
||||||
|
source = "server.identity"
|
||||||
|
name = "Add server name"
|
||||||
|
}
|
||||||
|
|
||||||
|
force_destroy = true
|
||||||
|
}`, name, domain)
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ resource "fastly_service_v1" "demo" {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Basic usage with an Amazon S3 Website:
|
Basic usage with an Amazon S3 Website, and removes the `x-amz-request-id` header:
|
||||||
|
|
||||||
```
|
```
|
||||||
resource "fastly_service_v1" "demo" {
|
resource "fastly_service_v1" "demo" {
|
||||||
|
@ -57,6 +57,13 @@ resource "fastly_service_v1" "demo" {
|
||||||
port = 80
|
port = 80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
destination = "http.x-amz-request-id"
|
||||||
|
type = "cache"
|
||||||
|
action = "delete"
|
||||||
|
name = "remove x-amz-request-id"
|
||||||
|
}
|
||||||
|
|
||||||
default_host = "${aws_s3_bucket.website.name}.s3-website-us-west-2.amazonaws.com"
|
default_host = "${aws_s3_bucket.website.name}.s3-website-us-west-2.amazonaws.com"
|
||||||
|
|
||||||
force_destroy = true
|
force_destroy = true
|
||||||
|
@ -76,7 +83,7 @@ resource "aws_s3_bucket" "website" {
|
||||||
**Note:** For an AWS S3 Bucket, the Backend address is
|
**Note:** For an AWS S3 Bucket, the Backend address is
|
||||||
`<domain>.s3-website-<region>.amazonaws.com`. The `default_host` attribute
|
`<domain>.s3-website-<region>.amazonaws.com`. The `default_host` attribute
|
||||||
should be set to `<bucket_name>.s3-website-<region>.amazonaws.com`. See the
|
should be set to `<bucket_name>.s3-website-<region>.amazonaws.com`. See the
|
||||||
Fastly documentation on [Amazon S3][fastly-s3]
|
Fastly documentation on [Amazon S3][fastly-s3].
|
||||||
|
|
||||||
## Argument Reference
|
## Argument Reference
|
||||||
|
|
||||||
|
@ -87,6 +94,8 @@ The following arguments are supported:
|
||||||
Service. Defined below.
|
Service. Defined below.
|
||||||
* `backend` - (Required) A set of Backends to service requests from your Domains.
|
* `backend` - (Required) A set of Backends to service requests from your Domains.
|
||||||
Defined below.
|
Defined below.
|
||||||
|
* `header` - (Optional) A set of Headers to manipulate for each request. Defined
|
||||||
|
below.
|
||||||
* `default_host` - (Optional) The default hostname
|
* `default_host` - (Optional) The default hostname
|
||||||
* `default_ttl` - (Optional) The default Time-to-live (TTL) for requests
|
* `default_ttl` - (Optional) The default Time-to-live (TTL) for requests
|
||||||
* `force_destroy` - (Optional) Services that are active cannot be destroyed. In
|
* `force_destroy` - (Optional) Services that are active cannot be destroyed. In
|
||||||
|
@ -117,6 +126,25 @@ Default `200`
|
||||||
* `weight` - (Optional) How long to wait for the first bytes in milliseconds.
|
* `weight` - (Optional) How long to wait for the first bytes in milliseconds.
|
||||||
Default `100`
|
Default `100`
|
||||||
|
|
||||||
|
The `Header` block supports adding, removing, or modifying Request and Response
|
||||||
|
headers. See Fastly's documentation on
|
||||||
|
[Adding or modifying headers on HTTP requests and responses](https://docs.fastly.com/guides/basic-configuration/adding-or-modifying-headers-on-http-requests-and-responses#field-description-table) for more detailed information on any
|
||||||
|
of the properties below.
|
||||||
|
|
||||||
|
* `name` - (Required) A unique name to refer to this header attribute
|
||||||
|
* `action` - (Required) The Header manipulation action to take; must be one of
|
||||||
|
`set`, `append`, `delete`, `regex`, or `regex_repeat`
|
||||||
|
* `type` - (Required) The Request type to apply the selected Action on
|
||||||
|
* `destination` - (Required) The name of the header that is going to be affected
|
||||||
|
by the Action
|
||||||
|
* `ignore_if_set` - (Optional) Do not add the header if it is already present.
|
||||||
|
(Only applies to `set` action.). Default `false`
|
||||||
|
* `source` - (Optional) Variable to be used as a source for the header content
|
||||||
|
(Does not apply to `delete` action.)
|
||||||
|
* `regex` - (Optional) Regular expression to use (Only applies to `regex` and `regex_repeat` actions.)
|
||||||
|
* `substitution` - (Optional) Value to substitute in place of regular expression. (Only applies to `regex` and `regex_repeat`.)
|
||||||
|
* `priority` - (Optional) Lower priorities execute first. (Default: `100`.)
|
||||||
|
|
||||||
## Attributes Reference
|
## Attributes Reference
|
||||||
|
|
||||||
The following attributes are exported:
|
The following attributes are exported:
|
||||||
|
@ -126,6 +154,7 @@ The following attributes are exported:
|
||||||
* `active_version` - The currently active version of your Fastly Service
|
* `active_version` - The currently active version of your Fastly Service
|
||||||
* `domain` – Set of Domains. See above for details
|
* `domain` – Set of Domains. See above for details
|
||||||
* `backend` – Set of Backends. See above for details
|
* `backend` – Set of Backends. See above for details
|
||||||
|
* `header` – Set of Headers. See above for details
|
||||||
* `default_host` – Default host specified
|
* `default_host` – Default host specified
|
||||||
* `default_ttl` - Default TTL
|
* `default_ttl` - Default TTL
|
||||||
* `force_destroy` - Force the destruction of the Service on delete
|
* `force_destroy` - Force the destruction of the Service on delete
|
||||||
|
@ -133,4 +162,3 @@ The following attributes are exported:
|
||||||
|
|
||||||
[fastly-s3]: https://docs.fastly.com/guides/integrations/amazon-s3
|
[fastly-s3]: https://docs.fastly.com/guides/integrations/amazon-s3
|
||||||
[fastly-cname]: https://docs.fastly.com/guides/basic-setup/adding-cname-records
|
[fastly-cname]: https://docs.fastly.com/guides/basic-setup/adding-cname-records
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue