provider/fastly: Add Fastly Provider, ServiceV1 resource
This commit is contained in:
parent
2cc8adefb8
commit
2ad37bba4a
|
@ -0,0 +1,12 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/builtin/providers/fastly"
|
||||
"github.com/hashicorp/terraform/plugin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
plugin.Serve(&plugin.ServeOpts{
|
||||
ProviderFunc: fastly.Provider,
|
||||
})
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package main
|
|
@ -0,0 +1,31 @@
|
|||
package fastly
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
gofastly "github.com/sethvargo/go-fastly"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ApiKey string
|
||||
}
|
||||
|
||||
type FastlyClient struct {
|
||||
conn *gofastly.Client
|
||||
}
|
||||
|
||||
func (c *Config) Client() (interface{}, error) {
|
||||
var client FastlyClient
|
||||
|
||||
if c.ApiKey == "" {
|
||||
return nil, fmt.Errorf("[Err] No API key for Fastly")
|
||||
}
|
||||
|
||||
fconn, err := gofastly.NewClient(c.ApiKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.conn = fconn
|
||||
return &client, nil
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package fastly
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
// Provider returns a terraform.ResourceProvider.
|
||||
func Provider() terraform.ResourceProvider {
|
||||
return &schema.Provider{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"api_key": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.MultiEnvDefaultFunc([]string{
|
||||
"FASTLY_API_KEY",
|
||||
}, nil),
|
||||
Description: "Fastly API Key from https://app.fastly.com/#account",
|
||||
},
|
||||
},
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"fastly_service_v1": resourceServiceV1(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
}
|
||||
}
|
||||
|
||||
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||
config := Config{
|
||||
ApiKey: d.Get("api_key").(string),
|
||||
}
|
||||
return config.Client()
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package fastly
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
var testAccProviders map[string]terraform.ResourceProvider
|
||||
var testAccProvider *schema.Provider
|
||||
|
||||
func init() {
|
||||
testAccProvider = Provider().(*schema.Provider)
|
||||
testAccProviders = map[string]terraform.ResourceProvider{
|
||||
"fastly": testAccProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider(t *testing.T) {
|
||||
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_impl(t *testing.T) {
|
||||
var _ terraform.ResourceProvider = Provider()
|
||||
}
|
||||
|
||||
func testAccPreCheck(t *testing.T) {
|
||||
if v := os.Getenv("FASTLY_API_KEY"); v == "" {
|
||||
t.Fatal("FASTLY_API_KEY must be set for acceptance tests")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,603 @@
|
|||
package fastly
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
gofastly "github.com/sethvargo/go-fastly"
|
||||
)
|
||||
|
||||
var fastlyNoServiceFoundErr = errors.New("No matching Fastly Service found")
|
||||
|
||||
func resourceServiceV1() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceServiceV1Create,
|
||||
Read: resourceServiceV1Read,
|
||||
Update: resourceServiceV1Update,
|
||||
Delete: resourceServiceV1Delete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "Unique name for this Service",
|
||||
},
|
||||
|
||||
// Active Version represents the currently activated version in Fastly. In
|
||||
// Terraform, we abstract this number away from the users and manage
|
||||
// creating and activating. It's used internally, but also exported for
|
||||
// users to see.
|
||||
"active_version": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"domain": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Required: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "The domain that this Service will respond to",
|
||||
},
|
||||
|
||||
"comment": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"default_ttl": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 3600,
|
||||
Description: "The default Time-to-live (TTL) for the version",
|
||||
},
|
||||
|
||||
"default_host": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Description: "The default hostname for the version",
|
||||
},
|
||||
|
||||
"backend": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Required: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
// required fields
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "A name for this Backend",
|
||||
},
|
||||
"address": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "An IPv4, hostname, or IPv6 address for the Backend",
|
||||
},
|
||||
// Optional fields, defaults where they exist
|
||||
"auto_loadbalance": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
Description: "Should this Backend be load balanced",
|
||||
},
|
||||
"between_bytes_timeout": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 10000,
|
||||
Description: "How long to wait between bytes in milliseconds",
|
||||
},
|
||||
"connect_timeout": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 1000,
|
||||
Description: "How long to wait for a timeout in milliseconds",
|
||||
},
|
||||
"error_threshold": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 0,
|
||||
Description: "Number of errors to allow before the Backend is marked as down",
|
||||
},
|
||||
"first_byte_timeout": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 15000,
|
||||
Description: "How long to wait for the first bytes in milliseconds",
|
||||
},
|
||||
"max_conn": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 200,
|
||||
Description: "Maximum number of connections for this Backend",
|
||||
},
|
||||
"port": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 80,
|
||||
Description: "The port number Backend responds on. Default 80",
|
||||
},
|
||||
"ssl_check_cert": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
Description: "Be strict on checking SSL certs",
|
||||
},
|
||||
// UseSSL is something we want to support in the future, but
|
||||
// requires SSL setup we don't yet have
|
||||
// TODO: Provide all SSL fields from https://docs.fastly.com/api/config#backend
|
||||
// "use_ssl": &schema.Schema{
|
||||
// Type: schema.TypeBool,
|
||||
// Optional: true,
|
||||
// Default: false,
|
||||
// Description: "Whether or not to use SSL to reach the Backend",
|
||||
// },
|
||||
"weight": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 100,
|
||||
Description: "How long to wait for the first bytes in milliseconds",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"force_destroy": &schema.Schema{
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceServiceV1Create(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*FastlyClient).conn
|
||||
service, err := conn.CreateService(&gofastly.CreateServiceInput{
|
||||
Name: d.Get("name").(string),
|
||||
Comment: "Managed by Terraform",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.SetId(service.ID)
|
||||
return resourceServiceV1Update(d, meta)
|
||||
}
|
||||
|
||||
func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*FastlyClient).conn
|
||||
|
||||
// Update Name. No new verions is required for this
|
||||
if d.HasChange("name") {
|
||||
_, err := conn.UpdateService(&gofastly.UpdateServiceInput{
|
||||
ID: d.Id(),
|
||||
Name: d.Get("name").(string),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Once activated, Versions are locked and become immutable. This is true for
|
||||
// versions that are no longer active. For Domains, Backends, DefaultHost and
|
||||
// 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
|
||||
var needsChange bool
|
||||
for _, v := range []string{"domain", "backend", "default_host", "default_ttl"} {
|
||||
if d.HasChange(v) {
|
||||
needsChange = true
|
||||
}
|
||||
}
|
||||
|
||||
if needsChange {
|
||||
latestVersion := d.Get("active_version").(string)
|
||||
if latestVersion == "" {
|
||||
// If the service was just created, there is an empty Version 1 available
|
||||
// that is unlocked and can be updated
|
||||
latestVersion = "1"
|
||||
} else {
|
||||
// Clone the latest version, giving us an unlocked version we can modify
|
||||
log.Printf("[DEBUG] Creating clone of version (%s) for updates", latestVersion)
|
||||
newVersion, err := conn.CloneVersion(&gofastly.CloneVersionInput{
|
||||
Service: d.Id(),
|
||||
Version: latestVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The new version number is named "Number", but it's actually a string
|
||||
latestVersion = newVersion.Number
|
||||
|
||||
// New versions are not immediately found in the API, or are not
|
||||
// immediately mutable, so we need to sleep a few and let Fastly ready
|
||||
// itself. Typically, 7 seconds is enough
|
||||
time.Sleep(7 * time.Second)
|
||||
}
|
||||
|
||||
// update general settings
|
||||
if d.HasChange("default_host") || d.HasChange("default_ttl") {
|
||||
opts := gofastly.UpdateSettingsInput{
|
||||
Service: d.Id(),
|
||||
Version: latestVersion,
|
||||
// default_ttl has the same default value of 3600 that is provided by
|
||||
// the Fastly API, so it's safe to include here
|
||||
DefaultTTL: uint(d.Get("default_ttl").(int)),
|
||||
}
|
||||
|
||||
if attr, ok := d.GetOk("default_host"); ok {
|
||||
opts.DefaultHost = attr.(string)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Update Settings opts: %#v", opts)
|
||||
_, err := conn.UpdateSettings(&opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Find differences in domains
|
||||
if d.HasChange("domain") {
|
||||
// Note: we don't utilize the PUT endpoint to update a Domain, 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
|
||||
od, nd := d.GetChange("domain")
|
||||
if od == nil {
|
||||
od = new(schema.Set)
|
||||
}
|
||||
if nd == nil {
|
||||
nd = new(schema.Set)
|
||||
}
|
||||
|
||||
ods := od.(*schema.Set)
|
||||
nds := nd.(*schema.Set)
|
||||
|
||||
remove := ods.Difference(nds).List()
|
||||
add := nds.Difference(ods).List()
|
||||
|
||||
// Delete removed domains
|
||||
for _, dRaw := range remove {
|
||||
df := dRaw.(map[string]interface{})
|
||||
opts := gofastly.DeleteDomainInput{
|
||||
Service: d.Id(),
|
||||
Version: latestVersion,
|
||||
Name: df["name"].(string),
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Fastly Domain Removal opts: %#v", opts)
|
||||
err := conn.DeleteDomain(&opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// POST new Domains
|
||||
for _, dRaw := range add {
|
||||
df := dRaw.(map[string]interface{})
|
||||
opts := gofastly.CreateDomainInput{
|
||||
Service: d.Id(),
|
||||
Version: latestVersion,
|
||||
Name: df["name"].(string),
|
||||
}
|
||||
|
||||
if v, ok := df["comment"]; ok {
|
||||
opts.Comment = v.(string)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Fastly Domain Addition opts: %#v", opts)
|
||||
_, err := conn.CreateDomain(&opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find difference in backends
|
||||
if d.HasChange("backend") {
|
||||
// POST new Backends
|
||||
// Note: we don't utilize the PUT endpoint to update a Backend, 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
|
||||
ob, nb := d.GetChange("backend")
|
||||
if ob == nil {
|
||||
ob = new(schema.Set)
|
||||
}
|
||||
if nb == nil {
|
||||
nb = new(schema.Set)
|
||||
}
|
||||
|
||||
obs := ob.(*schema.Set)
|
||||
nbs := nb.(*schema.Set)
|
||||
removeBackends := obs.Difference(nbs).List()
|
||||
addBackends := nbs.Difference(obs).List()
|
||||
|
||||
// DELETE old Backends
|
||||
for _, bRaw := range removeBackends {
|
||||
bf := bRaw.(map[string]interface{})
|
||||
opts := gofastly.DeleteBackendInput{
|
||||
Service: d.Id(),
|
||||
Version: latestVersion,
|
||||
Name: bf["name"].(string),
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Fastly Backend Removal opts: %#v", opts)
|
||||
err := conn.DeleteBackend(&opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, dRaw := range addBackends {
|
||||
df := dRaw.(map[string]interface{})
|
||||
opts := gofastly.CreateBackendInput{
|
||||
Service: d.Id(),
|
||||
Version: latestVersion,
|
||||
Name: df["name"].(string),
|
||||
Address: df["address"].(string),
|
||||
AutoLoadbalance: df["auto_loadbalance"].(bool),
|
||||
SSLCheckCert: df["ssl_check_cert"].(bool),
|
||||
Port: uint(df["port"].(int)),
|
||||
BetweenBytesTimeout: uint(df["between_bytes_timeout"].(int)),
|
||||
ConnectTimeout: uint(df["connect_timeout"].(int)),
|
||||
ErrorThreshold: uint(df["error_threshold"].(int)),
|
||||
FirstByteTimeout: uint(df["first_byte_timeout"].(int)),
|
||||
MaxConn: uint(df["max_conn"].(int)),
|
||||
Weight: uint(df["weight"].(int)),
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Create Backend Opts: %#v", opts)
|
||||
_, err := conn.CreateBackend(&opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// validate version
|
||||
log.Printf("[DEBUG] Validating Fastly Service (%s), Version (%s)", d.Id(), latestVersion)
|
||||
valid, msg, err := conn.ValidateVersion(&gofastly.ValidateVersionInput{
|
||||
Service: d.Id(),
|
||||
Version: latestVersion,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("[ERR] Error checking validation: %s", err)
|
||||
}
|
||||
|
||||
if !valid {
|
||||
return fmt.Errorf("[WARN] Invalid configuration for Fastly Service (%s): %s", d.Id(), msg)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Activating Fastly Service (%s), Version (%s)", d.Id(), latestVersion)
|
||||
_, err = conn.ActivateVersion(&gofastly.ActivateVersionInput{
|
||||
Service: d.Id(),
|
||||
Version: latestVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("[ERR] Error activating version (%s): %s", latestVersion, err)
|
||||
}
|
||||
|
||||
// Only if the version is valid and activated do we set the active_version.
|
||||
// This prevents us from getting stuck in cloning an invalid version
|
||||
d.Set("active_version", latestVersion)
|
||||
}
|
||||
|
||||
return resourceServiceV1Read(d, meta)
|
||||
}
|
||||
|
||||
func resourceServiceV1Read(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*FastlyClient).conn
|
||||
|
||||
// Find the Service. Discard the service because we need the ServiceDetails,
|
||||
// not just a Service record
|
||||
_, err := findService(d.Id(), meta)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case fastlyNoServiceFoundErr:
|
||||
log.Printf("[WARN] %s for ID (%s)", err, d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s, err := conn.GetServiceDetails(&gofastly.GetServiceInput{
|
||||
ID: d.Id(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Set("name", s.Name)
|
||||
d.Set("active_version", s.ActiveVersion.Number)
|
||||
|
||||
// If CreateService succeeds, but initial updates to the Service fail, we'll
|
||||
// have an empty ActiveService version (no version is active, so we can't
|
||||
// query for information on it)
|
||||
if s.ActiveVersion.Number != "" {
|
||||
settingsOpts := gofastly.GetSettingsInput{
|
||||
Service: d.Id(),
|
||||
Version: s.ActiveVersion.Number,
|
||||
}
|
||||
if settings, err := conn.GetSettings(&settingsOpts); err == nil {
|
||||
d.Set("default_host", settings.DefaultHost)
|
||||
d.Set("default_ttl", settings.DefaultTTL)
|
||||
} else {
|
||||
return fmt.Errorf("[ERR] Error looking up Version settings for (%s), version (%s): %s", d.Id(), s.ActiveVersion.Number, err)
|
||||
}
|
||||
|
||||
// TODO: update go-fastly to support an ActiveVersion struct, which contains
|
||||
// domain and backend info in the response. Here we do 2 additional queries
|
||||
// to find out that info
|
||||
domainList, err := conn.ListDomains(&gofastly.ListDomainsInput{
|
||||
Service: d.Id(),
|
||||
Version: s.ActiveVersion.Number,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("[ERR] Error looking up Domains for (%s), version (%s): %s", d.Id(), s.ActiveVersion.Number, err)
|
||||
}
|
||||
|
||||
// Refresh Domains
|
||||
dl := flattenDomains(domainList)
|
||||
|
||||
if err := d.Set("domain", dl); err != nil {
|
||||
log.Printf("[WARN] Error setting Domains for (%s): %s", d.Id(), err)
|
||||
}
|
||||
|
||||
// Refresh Backends
|
||||
backendList, err := conn.ListBackends(&gofastly.ListBackendsInput{
|
||||
Service: d.Id(),
|
||||
Version: s.ActiveVersion.Number,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("[ERR] Error looking up Backends for (%s), version (%s): %s", d.Id(), s.ActiveVersion.Number, err)
|
||||
}
|
||||
|
||||
bl := flattenBackends(backendList)
|
||||
|
||||
if err := d.Set("backend", bl); err != nil {
|
||||
log.Printf("[WARN] Error setting Backends for (%s): %s", d.Id(), err)
|
||||
}
|
||||
} else {
|
||||
log.Printf("[DEBUG] Active Version for Service (%s) is empty, no state to refresh", d.Id())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceServiceV1Delete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*FastlyClient).conn
|
||||
|
||||
// Fastly will fail to delete any service with an Active Version.
|
||||
// If `force_destroy` is given, we deactivate the active version and then send
|
||||
// the DELETE call
|
||||
if d.Get("force_destroy").(bool) {
|
||||
s, err := conn.GetServiceDetails(&gofastly.GetServiceInput{
|
||||
ID: d.Id(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if s.ActiveVersion.Number != "" {
|
||||
_, err := conn.DeactivateVersion(&gofastly.DeactivateVersionInput{
|
||||
Service: d.Id(),
|
||||
Version: s.ActiveVersion.Number,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := conn.DeleteService(&gofastly.DeleteServiceInput{
|
||||
ID: d.Id(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = findService(d.Id(), meta)
|
||||
if err != nil {
|
||||
switch err {
|
||||
// we expect no records to be found here
|
||||
case fastlyNoServiceFoundErr:
|
||||
d.SetId("")
|
||||
return nil
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// findService above returned something and nil error, but shouldn't have
|
||||
return fmt.Errorf("[WARN] Tried deleting Service (%s), but was still found", d.Id())
|
||||
|
||||
}
|
||||
|
||||
func flattenDomains(list []*gofastly.Domain) []map[string]interface{} {
|
||||
dl := make([]map[string]interface{}, 0, len(list))
|
||||
|
||||
for _, d := range list {
|
||||
dl = append(dl, map[string]interface{}{
|
||||
"name": d.Name,
|
||||
"comment": d.Comment,
|
||||
})
|
||||
}
|
||||
|
||||
return dl
|
||||
}
|
||||
|
||||
func flattenBackends(backendList []*gofastly.Backend) []map[string]interface{} {
|
||||
var bl []map[string]interface{}
|
||||
for _, b := range backendList {
|
||||
// Convert Backend to a map for saving to state.
|
||||
nb := map[string]interface{}{
|
||||
"name": b.Name,
|
||||
"address": b.Address,
|
||||
"auto_loadbalance": b.AutoLoadbalance,
|
||||
"between_bytes_timeout": int(b.BetweenBytesTimeout),
|
||||
"connect_timeout": int(b.ConnectTimeout),
|
||||
"error_threshold": int(b.ErrorThreshold),
|
||||
"first_byte_timeout": int(b.FirstByteTimeout),
|
||||
"max_conn": int(b.MaxConn),
|
||||
"port": int(b.Port),
|
||||
"ssl_check_cert": b.SSLCheckCert,
|
||||
"weight": int(b.Weight),
|
||||
}
|
||||
|
||||
bl = append(bl, nb)
|
||||
}
|
||||
return bl
|
||||
}
|
||||
|
||||
// findService finds a Fastly Service via the ListServices endpoint, returning
|
||||
// the Service if found.
|
||||
//
|
||||
// Fastly API does not include any "deleted_at" type parameter to indicate
|
||||
// that a Service has been deleted. GET requests to a deleted Service will
|
||||
// return 200 OK and have the full output of the Service for an unknown time
|
||||
// (days, in my testing). In order to determine if a Service is deleted, we
|
||||
// need to hit /service and loop the returned Services, searching for the one
|
||||
// in question. This endpoint only returns active or "alive" services. If the
|
||||
// Service is not included, then it's "gone"
|
||||
//
|
||||
// Returns a fastlyNoServiceFoundErr error if the Service is not found in the
|
||||
// ListServices response.
|
||||
func findService(id string, meta interface{}) (*gofastly.Service, error) {
|
||||
conn := meta.(*FastlyClient).conn
|
||||
|
||||
l, err := conn.ListServices(&gofastly.ListServicesInput{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[WARN] Error listing servcies when deleting Fastly Service (%s): %s", id, err)
|
||||
}
|
||||
|
||||
for _, s := range l {
|
||||
if s.ID == id {
|
||||
log.Printf("[DEBUG] Found Service (%s)", id)
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fastlyNoServiceFoundErr
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
package fastly
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"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 TestResourceFastlyFlattenDomains(t *testing.T) {
|
||||
cases := []struct {
|
||||
remote []*gofastly.Domain
|
||||
local []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
remote: []*gofastly.Domain{
|
||||
&gofastly.Domain{
|
||||
Name: "test.notexample.com",
|
||||
Comment: "not comment",
|
||||
},
|
||||
},
|
||||
local: []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "test.notexample.com",
|
||||
"comment": "not comment",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
remote: []*gofastly.Domain{
|
||||
&gofastly.Domain{
|
||||
Name: "test.notexample.com",
|
||||
},
|
||||
},
|
||||
local: []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "test.notexample.com",
|
||||
"comment": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
out := flattenDomains(c.remote)
|
||||
if !reflect.DeepEqual(out, c.local) {
|
||||
t.Fatalf("Error matching:\nexpected: %#v\ngot: %#v", c.local, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceFastlyFlattenBackend(t *testing.T) {
|
||||
cases := []struct {
|
||||
remote []*gofastly.Backend
|
||||
local []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
remote: []*gofastly.Backend{
|
||||
&gofastly.Backend{
|
||||
Name: "test.notexample.com",
|
||||
Address: "www.notexample.com",
|
||||
Port: uint(80),
|
||||
AutoLoadbalance: true,
|
||||
BetweenBytesTimeout: uint(10000),
|
||||
ConnectTimeout: uint(1000),
|
||||
ErrorThreshold: uint(0),
|
||||
FirstByteTimeout: uint(15000),
|
||||
MaxConn: uint(200),
|
||||
SSLCheckCert: true,
|
||||
Weight: uint(100),
|
||||
},
|
||||
},
|
||||
local: []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "test.notexample.com",
|
||||
"address": "www.notexample.com",
|
||||
"port": 80,
|
||||
"auto_loadbalance": true,
|
||||
"between_bytes_timeout": 10000,
|
||||
"connect_timeout": 1000,
|
||||
"error_threshold": 0,
|
||||
"first_byte_timeout": 15000,
|
||||
"max_conn": 200,
|
||||
"ssl_check_cert": true,
|
||||
"weight": 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
out := flattenBackends(c.remote)
|
||||
if !reflect.DeepEqual(out, c.local) {
|
||||
t.Fatalf("Error matching:\nexpected: %#v\ngot: %#v", c.local, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccFastlyServiceV1_updateDomain(t *testing.T) {
|
||||
var service gofastly.ServiceDetail
|
||||
name := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||
nameUpdate := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||
domainName1 := fmt.Sprintf("%s.notadomain.com", acctest.RandString(10))
|
||||
domainName2 := 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: testAccServiceV1Config(name, domainName1),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
|
||||
testAccCheckFastlyServiceV1Attributes(&service, name, []string{domainName1}),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "name", name),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "active_version", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "domain.#", "1"),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccServiceV1Config_domainUpdate(nameUpdate, domainName1, domainName2),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
|
||||
testAccCheckFastlyServiceV1Attributes(&service, nameUpdate, []string{domainName1, domainName2}),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "name", nameUpdate),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "active_version", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "domain.#", "2"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccFastlyServiceV1_updateBackend(t *testing.T) {
|
||||
var service gofastly.ServiceDetail
|
||||
name := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||
backendName := fmt.Sprintf("%s.aws.amazon.com", acctest.RandString(3))
|
||||
backendName2 := fmt.Sprintf("%s.aws.amazon.com", acctest.RandString(3))
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckServiceV1Destroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccServiceV1Config_backend(name, backendName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
|
||||
testAccCheckFastlyServiceV1Attributes_backends(&service, name, []string{backendName}),
|
||||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
Config: testAccServiceV1Config_backend_update(name, backendName, backendName2),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
|
||||
testAccCheckFastlyServiceV1Attributes_backends(&service, name, []string{backendName, backendName2}),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "active_version", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "backend.#", "2"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccFastlyServiceV1_basic(t *testing.T) {
|
||||
var service gofastly.ServiceDetail
|
||||
name := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
|
||||
domainName := 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: testAccServiceV1Config(name, domainName),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
|
||||
testAccCheckFastlyServiceV1Attributes(&service, name, []string{domainName}),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "name", name),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "active_version", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"fastly_service_v1.foo", "domain.#", "1"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckServiceV1Exists(n string, service *gofastly.ServiceDetail) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No Service ID is set")
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*FastlyClient).conn
|
||||
latest, err := conn.GetServiceDetails(&gofastly.GetServiceInput{
|
||||
ID: rs.Primary.ID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*service = *latest
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckFastlyServiceV1Attributes(service *gofastly.ServiceDetail, name string, domains []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
|
||||
domainList, err := conn.ListDomains(&gofastly.ListDomainsInput{
|
||||
Service: service.ID,
|
||||
Version: service.ActiveVersion.Number,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("[ERR] Error looking up Domains for (%s), version (%s): %s", service.Name, service.ActiveVersion.Number, err)
|
||||
}
|
||||
|
||||
expected := len(domains)
|
||||
for _, d := range domainList {
|
||||
for _, e := range domains {
|
||||
if d.Name == e {
|
||||
expected--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if expected > 0 {
|
||||
return fmt.Errorf("Domain count mismatch, expected: %#v, got: %#v", domains, domainList)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckFastlyServiceV1Attributes_backends(service *gofastly.ServiceDetail, name string, backends []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
|
||||
backendList, err := conn.ListBackends(&gofastly.ListBackendsInput{
|
||||
Service: service.ID,
|
||||
Version: service.ActiveVersion.Number,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("[ERR] Error looking up Backends for (%s), version (%s): %s", service.Name, service.ActiveVersion.Number, err)
|
||||
}
|
||||
|
||||
expected := len(backendList)
|
||||
for _, b := range backendList {
|
||||
for _, e := range backends {
|
||||
if b.Address == e {
|
||||
expected--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if expected > 0 {
|
||||
return fmt.Errorf("Backend count mismatch, expected: %#v, got: %#v", backends, backendList)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckServiceV1Destroy(s *terraform.State) error {
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "fastly_service_v1" {
|
||||
continue
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*FastlyClient).conn
|
||||
l, err := conn.ListServices(&gofastly.ListServicesInput{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("[WARN] Error listing servcies when deleting Fastly Service (%s): %s", rs.Primary.ID, err)
|
||||
}
|
||||
|
||||
for _, s := range l {
|
||||
if s.ID == rs.Primary.ID {
|
||||
// service still found
|
||||
return fmt.Errorf("[WARN] Tried deleting Service (%s), but was still found", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccServiceV1Config(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"
|
||||
}
|
||||
|
||||
force_destroy = true
|
||||
}`, name, domain)
|
||||
}
|
||||
|
||||
func testAccServiceV1Config_domainUpdate(name, domain1, domain2 string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "fastly_service_v1" "foo" {
|
||||
name = "%s"
|
||||
|
||||
domain {
|
||||
name = "%s"
|
||||
comment = "tf-testing-domain"
|
||||
}
|
||||
|
||||
domain {
|
||||
name = "%s"
|
||||
comment = "tf-testing-other-domain"
|
||||
}
|
||||
|
||||
backend {
|
||||
address = "aws.amazon.com"
|
||||
name = "amazon docs"
|
||||
}
|
||||
|
||||
force_destroy = true
|
||||
}`, name, domain1, domain2)
|
||||
}
|
||||
|
||||
func testAccServiceV1Config_backend(name, backend string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "fastly_service_v1" "foo" {
|
||||
name = "%s"
|
||||
|
||||
domain {
|
||||
name = "test.notadomain.com"
|
||||
comment = "tf-testing-domain"
|
||||
}
|
||||
|
||||
backend {
|
||||
address = "%s"
|
||||
name = "tf -test backend"
|
||||
}
|
||||
|
||||
force_destroy = true
|
||||
}`, name, backend)
|
||||
}
|
||||
|
||||
func testAccServiceV1Config_backend_update(name, backend, backend2 string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "fastly_service_v1" "foo" {
|
||||
name = "%s"
|
||||
|
||||
default_ttl = 3400
|
||||
|
||||
domain {
|
||||
name = "test.notadomain.com"
|
||||
comment = "tf-testing-domain"
|
||||
}
|
||||
|
||||
backend {
|
||||
address = "%s"
|
||||
name = "tf-test-backend"
|
||||
}
|
||||
|
||||
backend {
|
||||
address = "%s"
|
||||
name = "tf-test-backend-other"
|
||||
}
|
||||
|
||||
force_destroy = true
|
||||
}`, name, backend, backend2)
|
||||
}
|
|
@ -22,6 +22,7 @@ body.layout-dnsimple,
|
|||
body.layout-docker,
|
||||
body.layout-dyn,
|
||||
body.layout-github,
|
||||
body.layout-fastly,
|
||||
body.layout-google,
|
||||
body.layout-heroku,
|
||||
body.layout-influxdb,
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
layout: "fastly"
|
||||
page_title: "Provider: Fastly"
|
||||
sidebar_current: "docs-fastly-index"
|
||||
description: |-
|
||||
Fastly
|
||||
---
|
||||
|
||||
# Fastly Provider
|
||||
|
||||
The Fastly provider is used to interact with the content delivery network (CDN)
|
||||
provided by Fastly.
|
||||
|
||||
In order to use this Provider, you must have an active account with Fastly.
|
||||
Pricing and signup information can be found at https://www.fastly.com/signup
|
||||
|
||||
Use the navigation to the left to read about the available resources.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
# Configure the Fastly Provider
|
||||
provider "fastly" {
|
||||
api_key = "test"
|
||||
}
|
||||
|
||||
# Create a Service
|
||||
resource "fastly_service_v1" "myservice" {
|
||||
name = "myawesometestservice"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
The Fastly provider offers an API key based method of providing credentials for
|
||||
authentication. The following methods are supported, in this order, and
|
||||
explained below:
|
||||
|
||||
- Static API key
|
||||
- Environment variables
|
||||
|
||||
|
||||
### Static API Key ###
|
||||
|
||||
Static credentials can be provided by adding a `api_key` in-line in the
|
||||
fastly provider block:
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
provider "fastly" {
|
||||
api_key = "test"
|
||||
}
|
||||
```
|
||||
|
||||
The API key for an account can be found on the Account page: https://app.fastly.com/#account
|
||||
|
||||
###Environment variables
|
||||
|
||||
You can provide your API key via `FASTLY_API_KEY` environment variable,
|
||||
representing your Fastly API key.
|
||||
|
||||
```
|
||||
provider "fastly" {}
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
||||
```
|
||||
$ export FASTLY_API_KEY="afastlyapikey"
|
||||
$ terraform plan
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported in the `provider` block:
|
||||
|
||||
* `api_key` - (Optional) This is the API key. It must be provided, but
|
||||
it can also be sourced from the `FASTLY_API_KEY` environment variable
|
|
@ -0,0 +1,136 @@
|
|||
---
|
||||
layout: "fastly"
|
||||
page_title: "Fastly: aws_vpc"
|
||||
sidebar_current: "docs-fastly-resource-service-v1"
|
||||
description: |-
|
||||
Provides an Fastly Service
|
||||
---
|
||||
|
||||
# fastly\_service\_v1
|
||||
|
||||
Provides an Fastly Service, representing the configuration for a website, app,
|
||||
api, or anything else to be served through Fastly. A Service encompasses Domains
|
||||
and Backends.
|
||||
|
||||
The Service resource requires a domain name that is correctly setup to direct
|
||||
traffic to the Fastly service. See Fastly's guide on [Adding CNAME Records][2]
|
||||
on their documentation site for guidance.
|
||||
|
||||
## Example Usage
|
||||
|
||||
Basic usage:
|
||||
|
||||
```
|
||||
resource "fastly_service_v1" "demo" {
|
||||
name = "demofastly"
|
||||
|
||||
domain {
|
||||
name = "demo.notexample.com"
|
||||
comment = "demo"
|
||||
}
|
||||
|
||||
backend {
|
||||
address = "127.0.0.1"
|
||||
name = "localhost"
|
||||
port = 80
|
||||
}
|
||||
|
||||
force_destroy = true
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Basic usage with an Amazon S3 Website:
|
||||
|
||||
```
|
||||
resource "fastly_service_v1" "demo" {
|
||||
name = "demofastly"
|
||||
|
||||
domain {
|
||||
name = "demo.notexample.com"
|
||||
comment = "demo"
|
||||
}
|
||||
|
||||
backend {
|
||||
address = "demo.notexample.com.s3-website-us-west-2.amazonaws.com"
|
||||
name = "AWS S3 hosting"
|
||||
port = 80
|
||||
}
|
||||
|
||||
default_host = "${aws_s3_bucket.website.name}.s3-website-us-west-2.amazonaws.com"
|
||||
|
||||
force_destroy = true
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket" "website" {
|
||||
bucket = "demo.notexample.com"
|
||||
acl = "public-read"
|
||||
|
||||
website {
|
||||
index_document = "index.html"
|
||||
error_document = "error.html"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** For an AWS S3 Bucket, the Backend address is
|
||||
`<domain>.s3-website-<region>.amazonaws.com`. The `default_host` attribute
|
||||
should be set to `<bucket_name>.s3-website-<region>.amazonaws.com`. See the
|
||||
Fastly documentation on [Amazon S3][1]
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `name` - (Required) The unique name for the Service to create
|
||||
* `domain` - (Required) A set of Domain names to serve as entry points for your
|
||||
Service. Defined below.
|
||||
* `backend` - (Required) A set of Backends to service requests from your Domains.
|
||||
Defined below.
|
||||
* `default_host` - (Optional) The default hostname
|
||||
* `default_ttl` - (Optional) The default Time-to-live (TTL) for requests
|
||||
* `force_destroy` - (Optional) Services that are active cannot be destroyed. In
|
||||
order to destroy the Service, set `force_destroy` to `true`. Default `false`.
|
||||
|
||||
|
||||
The `domain` block supports:
|
||||
|
||||
* `name` - (Required) The domain that this Service will respond to
|
||||
* `comment` - (Optional) An optional comment about the Domain
|
||||
|
||||
The `backend` block supports:
|
||||
|
||||
* `name` - (Required, string) Name for this Backend. Must be unique to this Service
|
||||
* `address` - (Required, string) An IPv4, hostname, or IPv6 address for the Backend
|
||||
* `auto_loadbalance` - (Optional, boolean) Denote if this Backend should be
|
||||
included in the pool of backends that requests are load balanced against.
|
||||
Default `true`
|
||||
* `between_bytes_timeout` - (Optional) How long to wait between bytes in milliseconds. Default `10000`
|
||||
* `connect_timeout` - (Optional) How long to wait for a timeout in milliseconds.
|
||||
Default `1000`
|
||||
* `error_threshold` - (Optional) Number of errors to allow before the Backend is marked as down. Default `0`
|
||||
* `first_byte_timeout` - (Optional) How long to wait for the first bytes in milliseconds. Default `15000`
|
||||
* `max_conn` - (Optional) Maximum number of connections for this Backend.
|
||||
Default `200`
|
||||
* `port` - (Optional) The port number Backend responds on. Default `80`
|
||||
* `ssl_check_cert` - (Optional) Be strict on checking SSL certs. Default `true`
|
||||
* `weight` - (Optional) How long to wait for the first bytes in milliseconds.
|
||||
Default `100`
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The ID of the Service
|
||||
* `name` – Name of this service
|
||||
* `active_version` - The currently active version of your Fastly Service
|
||||
* `domain` – Set of Domains. See above for details
|
||||
* `backend` – Set of Backends. See above for details
|
||||
* `default_host` – Default host specified
|
||||
* `default_ttl` - Default TTL
|
||||
* `force_destroy` - Force the destruction of the Service on delete
|
||||
|
||||
|
||||
[1]: https://docs.fastly.com/guides/integrations/amazon-s3
|
||||
[2]: https://docs.fastly.com/guides/basic-setup/adding-cname-records
|
||||
|
|
@ -193,6 +193,10 @@
|
|||
<a href="/docs/providers/github/index.html">Github</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-providers-fastly") %>>
|
||||
<a href="/docs/providers/fastly/index.html">Fastly</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-providers-google") %>>
|
||||
<a href="/docs/providers/google/index.html">Google Cloud</a>
|
||||
</li>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<% wrap_layout :inner do %>
|
||||
<% content_for :sidebar do %>
|
||||
<div class="docs-sidebar hidden-print affix-top" role="complementary">
|
||||
<ul class="nav docs-sidenav">
|
||||
<li<%= sidebar_current("docs-home") %>>
|
||||
<a href="/docs/providers/index.html">« Documentation Home</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-fastly-index") %>>
|
||||
<a href="/docs/providers/fastly/index.html">Fastly Provider</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current(/^docs-fastly-resource/) %>>
|
||||
<a href="#">Resources</a>
|
||||
|
||||
<ul class="nav nav-visible">
|
||||
<li<%= sidebar_current("docs-fastly-resource-service-v1") %>>
|
||||
<a href="/docs/providers/fastly/r/service_v1.html">service_v1</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= yield %>
|
||||
<% end %>
|
Loading…
Reference in New Issue