provider/fastly: Allow specifying log format version

Allows the user to specify the log format version when setting up `s3logging` on the fastly service resource.

Requires an update to the vendored `go-fastly` dependency.

Also adds an additional acceptance test for the new attribute.

```
$ make testacc TEST=./builtin/providers/fastly TESTARGS='-run=TestAccFastlyServiceV1_s3logging'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/02/06 14:51:55 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/fastly -v -run=TestAccFastlyServiceV1_s3logging -timeout 120m
=== RUN   TestAccFastlyServiceV1_s3logging_basic
--- PASS: TestAccFastlyServiceV1_s3logging_basic (36.11s)
=== RUN   TestAccFastlyServiceV1_s3logging_s3_env
--- PASS: TestAccFastlyServiceV1_s3logging_s3_env (15.35s)
=== RUN   TestAccFastlyServiceV1_s3logging_formatVersion
--- PASS: TestAccFastlyServiceV1_s3logging_formatVersion (15.71s)
PASS
ok      github.com/hashicorp/terraform/builtin/providers/fastly 67.186s
```
This commit is contained in:
Jake Champlin 2017-02-06 14:54:58 -05:00
parent 17dfa0c8e3
commit 5481fd941a
No known key found for this signature in database
GPG Key ID: DC31F41958EF4AC2
7 changed files with 234 additions and 96 deletions

View File

@ -26,7 +26,7 @@ func resourceServiceV1() *schema.Resource {
}, },
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Unique name for this Service", Description: "Unique name for this Service",
@ -36,23 +36,23 @@ func resourceServiceV1() *schema.Resource {
// Terraform, we abstract this number away from the users and manage // Terraform, we abstract this number away from the users and manage
// creating and activating. It's used internally, but also exported for // creating and activating. It's used internally, but also exported for
// users to see. // users to see.
"active_version": &schema.Schema{ "active_version": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
}, },
"domain": &schema.Schema{ "domain": {
Type: schema.TypeSet, Type: schema.TypeSet,
Required: true, Required: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "The domain that this Service will respond to", Description: "The domain that this Service will respond to",
}, },
"comment": &schema.Schema{ "comment": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
}, },
@ -60,16 +60,16 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
"condition": &schema.Schema{ "condition": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
}, },
"statement": &schema.Schema{ "statement": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "The statement used to determine if the condition is met", Description: "The statement used to determine if the condition is met",
@ -79,12 +79,12 @@ func resourceServiceV1() *schema.Resource {
return strings.TrimSpace(value) return strings.TrimSpace(value)
}, },
}, },
"priority": &schema.Schema{ "priority": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
Description: "A number used to determine the order in which multiple conditions execute. Lower numbers execute first", Description: "A number used to determine the order in which multiple conditions execute. Lower numbers execute first",
}, },
"type": &schema.Schema{ "type": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Type of the condition, either `REQUEST`, `RESPONSE`, or `CACHE`", Description: "Type of the condition, either `REQUEST`, `RESPONSE`, or `CACHE`",
@ -93,98 +93,98 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
"default_ttl": &schema.Schema{ "default_ttl": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 3600, Default: 3600,
Description: "The default Time-to-live (TTL) for the version", Description: "The default Time-to-live (TTL) for the version",
}, },
"default_host": &schema.Schema{ "default_host": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
Description: "The default hostname for the version", Description: "The default hostname for the version",
}, },
"backend": &schema.Schema{ "backend": {
Type: schema.TypeSet, Type: schema.TypeSet,
Required: true, Required: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
// required fields // required fields
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "A name for this Backend", Description: "A name for this Backend",
}, },
"address": &schema.Schema{ "address": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "An IPv4, hostname, or IPv6 address for the Backend", Description: "An IPv4, hostname, or IPv6 address for the Backend",
}, },
// Optional fields, defaults where they exist // Optional fields, defaults where they exist
"auto_loadbalance": &schema.Schema{ "auto_loadbalance": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: true, Default: true,
Description: "Should this Backend be load balanced", Description: "Should this Backend be load balanced",
}, },
"between_bytes_timeout": &schema.Schema{ "between_bytes_timeout": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 10000, Default: 10000,
Description: "How long to wait between bytes in milliseconds", Description: "How long to wait between bytes in milliseconds",
}, },
"connect_timeout": &schema.Schema{ "connect_timeout": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 1000, Default: 1000,
Description: "How long to wait for a timeout in milliseconds", Description: "How long to wait for a timeout in milliseconds",
}, },
"error_threshold": &schema.Schema{ "error_threshold": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 0, Default: 0,
Description: "Number of errors to allow before the Backend is marked as down", Description: "Number of errors to allow before the Backend is marked as down",
}, },
"first_byte_timeout": &schema.Schema{ "first_byte_timeout": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 15000, Default: 15000,
Description: "How long to wait for the first bytes in milliseconds", Description: "How long to wait for the first bytes in milliseconds",
}, },
"max_conn": &schema.Schema{ "max_conn": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 200, Default: 200,
Description: "Maximum number of connections for this Backend", Description: "Maximum number of connections for this Backend",
}, },
"port": &schema.Schema{ "port": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 80, Default: 80,
Description: "The port number Backend responds on. Default 80", Description: "The port number Backend responds on. Default 80",
}, },
"request_condition": &schema.Schema{ "request_condition": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Default: "", Default: "",
Description: "Condition, which if met, will select this backend during a request.", Description: "Condition, which if met, will select this backend during a request.",
}, },
"shield": &schema.Schema{ "shield": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Default: "", Default: "",
Description: "The POP of the shield designated to reduce inbound load.", Description: "The POP of the shield designated to reduce inbound load.",
}, },
"ssl_check_cert": &schema.Schema{ "ssl_check_cert": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: true, Default: true,
Description: "Be strict on checking SSL certs", Description: "Be strict on checking SSL certs",
}, },
"ssl_hostname": &schema.Schema{ "ssl_hostname": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Default: "", Default: "",
@ -199,7 +199,7 @@ func resourceServiceV1() *schema.Resource {
// Default: false, // Default: false,
// Description: "Whether or not to use SSL to reach the Backend", // Description: "Whether or not to use SSL to reach the Backend",
// }, // },
"weight": &schema.Schema{ "weight": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 100, Default: 100,
@ -209,40 +209,40 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
"force_destroy": &schema.Schema{ "force_destroy": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
}, },
"cache_setting": &schema.Schema{ "cache_setting": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
// required fields // required fields
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "A name to refer to this Cache Setting", Description: "A name to refer to this Cache Setting",
}, },
"cache_condition": &schema.Schema{ "cache_condition": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Condition to check if this Cache Setting applies", Description: "Condition to check if this Cache Setting applies",
}, },
"action": &schema.Schema{ "action": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Description: "Action to take", Description: "Action to take",
}, },
// optional // optional
"stale_ttl": &schema.Schema{ "stale_ttl": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Description: "Max 'Time To Live' for stale (unreachable) objects.", Description: "Max 'Time To Live' for stale (unreachable) objects.",
Default: 300, Default: 300,
}, },
"ttl": &schema.Schema{ "ttl": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Description: "The 'Time To Live' for the object", Description: "The 'Time To Live' for the object",
@ -251,25 +251,25 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
"gzip": &schema.Schema{ "gzip": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
// required fields // required fields
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "A name to refer to this gzip condition", Description: "A name to refer to this gzip condition",
}, },
// optional fields // optional fields
"content_types": &schema.Schema{ "content_types": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Description: "Content types to apply automatic gzip to", Description: "Content types to apply automatic gzip to",
Elem: &schema.Schema{Type: schema.TypeString}, Elem: &schema.Schema{Type: schema.TypeString},
}, },
"extensions": &schema.Schema{ "extensions": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Description: "File extensions to apply automatic gzip to. Do not include '.'", Description: "File extensions to apply automatic gzip to. Do not include '.'",
@ -277,7 +277,7 @@ func resourceServiceV1() *schema.Resource {
}, },
// These fields represent Fastly options that Terraform does not // These fields represent Fastly options that Terraform does not
// currently support // currently support
"cache_condition": &schema.Schema{ "cache_condition": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
Description: "Optional name of a CacheCondition to apply.", Description: "Optional name of a CacheCondition to apply.",
@ -286,18 +286,18 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
"header": &schema.Schema{ "header": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
// required fields // required fields
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "A name to refer to this Header object", Description: "A name to refer to this Header object",
}, },
"action": &schema.Schema{ "action": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "One of set, append, delete, regex, or regex_repeat", Description: "One of set, append, delete, regex, or regex_repeat",
@ -315,7 +315,7 @@ func resourceServiceV1() *schema.Resource {
return return
}, },
}, },
"type": &schema.Schema{ "type": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Type to manipulate: request, fetch, cache, response", Description: "Type to manipulate: request, fetch, cache, response",
@ -333,37 +333,37 @@ func resourceServiceV1() *schema.Resource {
return return
}, },
}, },
"destination": &schema.Schema{ "destination": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Header this affects", Description: "Header this affects",
}, },
// Optional fields, defaults where they exist // Optional fields, defaults where they exist
"ignore_if_set": &schema.Schema{ "ignore_if_set": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: false, Default: false,
Description: "Don't add the header if it is already. (Only applies to 'set' action.). Default `false`", Description: "Don't add the header if it is already. (Only applies to 'set' action.). Default `false`",
}, },
"source": &schema.Schema{ "source": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
Description: "Variable to be used as a source for the header content (Does not apply to 'delete' action.)", Description: "Variable to be used as a source for the header content (Does not apply to 'delete' action.)",
}, },
"regex": &schema.Schema{ "regex": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
Description: "Regular expression to use (Only applies to 'regex' and 'regex_repeat' actions.)", Description: "Regular expression to use (Only applies to 'regex' and 'regex_repeat' actions.)",
}, },
"substitution": &schema.Schema{ "substitution": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Computed: true, Computed: true,
Description: "Value to substitute in place of regular expression. (Only applies to 'regex' and 'regex_repeat'.)", Description: "Value to substitute in place of regular expression. (Only applies to 'regex' and 'regex_repeat'.)",
}, },
"priority": &schema.Schema{ "priority": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 100, Default: 100,
@ -371,17 +371,17 @@ func resourceServiceV1() *schema.Resource {
}, },
// These fields represent Fastly options that Terraform does not // These fields represent Fastly options that Terraform does not
// currently support // currently support
"request_condition": &schema.Schema{ "request_condition": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
Description: "Optional name of a RequestCondition to apply.", Description: "Optional name of a RequestCondition to apply.",
}, },
"cache_condition": &schema.Schema{ "cache_condition": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
Description: "Optional name of a CacheCondition to apply.", Description: "Optional name of a CacheCondition to apply.",
}, },
"response_condition": &schema.Schema{ "response_condition": {
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
Description: "Optional name of a ResponseCondition to apply.", Description: "Optional name of a ResponseCondition to apply.",
@ -390,64 +390,71 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
"s3logging": &schema.Schema{ "s3logging": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
// Required fields // Required fields
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Unique name to refer to this logging setup", Description: "Unique name to refer to this logging setup",
}, },
"bucket_name": &schema.Schema{ "bucket_name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "S3 Bucket name to store logs in", Description: "S3 Bucket name to store logs in",
}, },
"s3_access_key": &schema.Schema{ "s3_access_key": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
DefaultFunc: schema.EnvDefaultFunc("FASTLY_S3_ACCESS_KEY", ""), DefaultFunc: schema.EnvDefaultFunc("FASTLY_S3_ACCESS_KEY", ""),
Description: "AWS Access Key", Description: "AWS Access Key",
}, },
"s3_secret_key": &schema.Schema{ "s3_secret_key": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
DefaultFunc: schema.EnvDefaultFunc("FASTLY_S3_SECRET_KEY", ""), DefaultFunc: schema.EnvDefaultFunc("FASTLY_S3_SECRET_KEY", ""),
Description: "AWS Secret Key", Description: "AWS Secret Key",
}, },
// Optional fields // Optional fields
"path": &schema.Schema{ "path": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Description: "Path to store the files. Must end with a trailing slash", Description: "Path to store the files. Must end with a trailing slash",
}, },
"domain": &schema.Schema{ "domain": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Description: "Bucket endpoint", Description: "Bucket endpoint",
}, },
"gzip_level": &schema.Schema{ "gzip_level": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 0, Default: 0,
Description: "Gzip Compression level", Description: "Gzip Compression level",
}, },
"period": &schema.Schema{ "period": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 3600, Default: 3600,
Description: "How frequently the logs should be transferred, in seconds (Default 3600)", Description: "How frequently the logs should be transferred, in seconds (Default 3600)",
}, },
"format": &schema.Schema{ "format": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Default: "%h %l %u %t %r %>s", Default: "%h %l %u %t %r %>s",
Description: "Apache-style string or VCL variables to use for log formatting", Description: "Apache-style string or VCL variables to use for log formatting",
}, },
"timestamp_format": &schema.Schema{ "format_version": {
Type: schema.TypeInt,
Optional: true,
Default: 1,
Description: "The version of the custom logging format used for the configured endpoint. Can be either 1 or 2. (Default: 1)",
ValidateFunc: validateS3FormatVersion,
},
"timestamp_format": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Default: "%Y-%m-%dT%H:%M:%S.000", Default: "%Y-%m-%dT%H:%M:%S.000",
@ -457,29 +464,29 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
"papertrail": &schema.Schema{ "papertrail": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
// Required fields // Required fields
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Unique name to refer to this logging setup", Description: "Unique name to refer to this logging setup",
}, },
"address": &schema.Schema{ "address": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "The address of the papertrail service", Description: "The address of the papertrail service",
}, },
"port": &schema.Schema{ "port": {
Type: schema.TypeInt, Type: schema.TypeInt,
Required: true, Required: true,
Description: "The port of the papertrail service", Description: "The port of the papertrail service",
}, },
// Optional // Optional
"format": &schema.Schema{ "format": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Default: "%h %l %u %t %r %>s", Default: "%h %l %u %t %r %>s",
@ -489,71 +496,71 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
"request_setting": &schema.Schema{ "request_setting": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
// Required fields // Required fields
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Unique name to refer to this Request Setting", Description: "Unique name to refer to this Request Setting",
}, },
"request_condition": &schema.Schema{ "request_condition": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "Name of a RequestCondition to apply.", Description: "Name of a RequestCondition to apply.",
}, },
// Optional fields // Optional fields
"max_stale_age": &schema.Schema{ "max_stale_age": {
Type: schema.TypeInt, Type: schema.TypeInt,
Optional: true, Optional: true,
Default: 60, Default: 60,
Description: "How old an object is allowed to be, in seconds. Default `60`", Description: "How old an object is allowed to be, in seconds. Default `60`",
}, },
"force_miss": &schema.Schema{ "force_miss": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Description: "Force a cache miss for the request", Description: "Force a cache miss for the request",
}, },
"force_ssl": &schema.Schema{ "force_ssl": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Description: "Forces the request use SSL", Description: "Forces the request use SSL",
}, },
"action": &schema.Schema{ "action": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Description: "Allows you to terminate request handling and immediately perform an action", Description: "Allows you to terminate request handling and immediately perform an action",
}, },
"bypass_busy_wait": &schema.Schema{ "bypass_busy_wait": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Description: "Disable collapsed forwarding", Description: "Disable collapsed forwarding",
}, },
"hash_keys": &schema.Schema{ "hash_keys": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Description: "Comma separated list of varnish request object fields that should be in the hash key", Description: "Comma separated list of varnish request object fields that should be in the hash key",
}, },
"xff": &schema.Schema{ "xff": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Default: "append", Default: "append",
Description: "X-Forwarded-For options", Description: "X-Forwarded-For options",
}, },
"timer_support": &schema.Schema{ "timer_support": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Description: "Injects the X-Timer info into the request", Description: "Injects the X-Timer info into the request",
}, },
"geo_headers": &schema.Schema{ "geo_headers": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Description: "Inject Fastly-Geo-Country, Fastly-Geo-City, and Fastly-Geo-Region", Description: "Inject Fastly-Geo-Country, Fastly-Geo-City, and Fastly-Geo-Region",
}, },
"default_host": &schema.Schema{ "default_host": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
Description: "the host header", Description: "the host header",
@ -561,17 +568,17 @@ func resourceServiceV1() *schema.Resource {
}, },
}, },
}, },
"vcl": &schema.Schema{ "vcl": {
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
Elem: &schema.Resource{ Elem: &schema.Resource{
Schema: map[string]*schema.Schema{ Schema: map[string]*schema.Schema{
"name": &schema.Schema{ "name": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "A name to refer to this VCL configuration", Description: "A name to refer to this VCL configuration",
}, },
"content": &schema.Schema{ "content": {
Type: schema.TypeString, Type: schema.TypeString,
Required: true, Required: true,
Description: "The contents of this VCL configuration", Description: "The contents of this VCL configuration",
@ -585,7 +592,7 @@ func resourceServiceV1() *schema.Resource {
} }
}, },
}, },
"main": &schema.Schema{ "main": {
Type: schema.TypeBool, Type: schema.TypeBool,
Optional: true, Optional: true,
Default: false, Default: false,
@ -682,7 +689,7 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
// New versions are not immediately found in the API, or are not // 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 // immediately mutable, so we need to sleep a few and let Fastly ready
// itself. Typically, 7 seconds is enough // itself. Typically, 7 seconds is enough
log.Printf("[DEBUG] Sleeping 7 seconds to allow Fastly Version to be available") log.Print("[DEBUG] Sleeping 7 seconds to allow Fastly Version to be available")
time.Sleep(7 * time.Second) time.Sleep(7 * time.Second)
} }
@ -1056,6 +1063,7 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
Domain: sf["domain"].(string), Domain: sf["domain"].(string),
Path: sf["path"].(string), Path: sf["path"].(string),
Format: sf["format"].(string), Format: sf["format"].(string),
FormatVersion: uint(sf["format_version"].(int)),
TimestampFormat: sf["timestamp_format"].(string), TimestampFormat: sf["timestamp_format"].(string),
} }
@ -1811,6 +1819,7 @@ func flattenS3s(s3List []*gofastly.S3) []map[string]interface{} {
"domain": s.Domain, "domain": s.Domain,
"gzip_level": s.GzipLevel, "gzip_level": s.GzipLevel,
"format": s.Format, "format": s.Format,
"format_version": s.FormatVersion,
"timestamp_format": s.TimestampFormat, "timestamp_format": s.TimestampFormat,
} }
@ -2013,10 +2022,10 @@ func validateVCLs(d *schema.ResourceData) error {
} }
} }
if numberOfMainVCLs == 0 && numberOfIncludeVCLs > 0 { if numberOfMainVCLs == 0 && numberOfIncludeVCLs > 0 {
return fmt.Errorf("if you include VCL configurations, one of them should have main = true") return errors.New("if you include VCL configurations, one of them should have main = true")
} }
if numberOfMainVCLs > 1 { if numberOfMainVCLs > 1 {
return fmt.Errorf("you cannot have more than one VCL configuration with main = true") return errors.New("you cannot have more than one VCL configuration with main = true")
} }
return nil return nil
} }

View File

@ -27,6 +27,7 @@ func TestAccFastlyServiceV1_s3logging_basic(t *testing.T) {
Period: uint(3600), Period: uint(3600),
GzipLevel: uint(0), GzipLevel: uint(0),
Format: "%h %l %u %t %r %>s", Format: "%h %l %u %t %r %>s",
FormatVersion: 1,
TimestampFormat: "%Y-%m-%dT%H:%M:%S.000", TimestampFormat: "%Y-%m-%dT%H:%M:%S.000",
} }
@ -40,6 +41,7 @@ func TestAccFastlyServiceV1_s3logging_basic(t *testing.T) {
GzipLevel: uint(3), GzipLevel: uint(3),
Period: uint(60), Period: uint(60),
Format: "%h %l %u %t %r %>s", Format: "%h %l %u %t %r %>s",
FormatVersion: 1,
TimestampFormat: "%Y-%m-%dT%H:%M:%S.000", TimestampFormat: "%Y-%m-%dT%H:%M:%S.000",
} }
@ -48,7 +50,7 @@ func TestAccFastlyServiceV1_s3logging_basic(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckServiceV1Destroy, CheckDestroy: testAccCheckServiceV1Destroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccServiceV1S3LoggingConfig(name, domainName1), Config: testAccServiceV1S3LoggingConfig(name, domainName1),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service), testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
@ -60,7 +62,7 @@ func TestAccFastlyServiceV1_s3logging_basic(t *testing.T) {
), ),
}, },
resource.TestStep{ {
Config: testAccServiceV1S3LoggingConfig_update(name, domainName1), Config: testAccServiceV1S3LoggingConfig_update(name, domainName1),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service), testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
@ -95,6 +97,7 @@ func TestAccFastlyServiceV1_s3logging_s3_env(t *testing.T) {
Period: uint(3600), Period: uint(3600),
GzipLevel: uint(0), GzipLevel: uint(0),
Format: "%h %l %u %t %r %>s", Format: "%h %l %u %t %r %>s",
FormatVersion: 1,
TimestampFormat: "%Y-%m-%dT%H:%M:%S.000", TimestampFormat: "%Y-%m-%dT%H:%M:%S.000",
} }
@ -103,7 +106,7 @@ func TestAccFastlyServiceV1_s3logging_s3_env(t *testing.T) {
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckServiceV1Destroy, CheckDestroy: testAccCheckServiceV1Destroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ {
Config: testAccServiceV1S3LoggingConfig_env(name, domainName1), Config: testAccServiceV1S3LoggingConfig_env(name, domainName1),
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service), testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
@ -118,6 +121,45 @@ func TestAccFastlyServiceV1_s3logging_s3_env(t *testing.T) {
}) })
} }
func TestAccFastlyServiceV1_s3logging_formatVersion(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))
log1 := gofastly.S3{
Version: "1",
Name: "somebucketlog",
BucketName: "fastlytestlogging",
Domain: "s3-us-west-2.amazonaws.com",
AccessKey: "somekey",
SecretKey: "somesecret",
Period: uint(3600),
GzipLevel: uint(0),
Format: "%a %l %u %t %m %U%q %H %>s %b %T",
FormatVersion: 2,
TimestampFormat: "%Y-%m-%dT%H:%M:%S.000",
}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckServiceV1Destroy,
Steps: []resource.TestStep{
{
Config: testAccServiceV1S3LoggingConfig_formatVersion(name, domainName1),
Check: resource.ComposeTestCheckFunc(
testAccCheckServiceV1Exists("fastly_service_v1.foo", &service),
testAccCheckFastlyServiceV1S3LoggingAttributes(&service, []*gofastly.S3{&log1}),
resource.TestCheckResourceAttr(
"fastly_service_v1.foo", "name", name),
resource.TestCheckResourceAttr(
"fastly_service_v1.foo", "s3logging.#", "1"),
),
},
},
})
}
func testAccCheckFastlyServiceV1S3LoggingAttributes(service *gofastly.ServiceDetail, s3s []*gofastly.S3) resource.TestCheckFunc { func testAccCheckFastlyServiceV1S3LoggingAttributes(service *gofastly.ServiceDetail, s3s []*gofastly.S3) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
@ -179,9 +221,9 @@ resource "fastly_service_v1" "foo" {
s3logging { s3logging {
name = "somebucketlog" name = "somebucketlog"
bucket_name = "fastlytestlogging" bucket_name = "fastlytestlogging"
domain = "s3-us-west-2.amazonaws.com" domain = "s3-us-west-2.amazonaws.com"
s3_access_key = "somekey" s3_access_key = "somekey"
s3_secret_key = "somesecret" s3_secret_key = "somesecret"
} }
@ -251,6 +293,35 @@ resource "fastly_service_v1" "foo" {
}`, name, domain) }`, name, domain)
} }
func testAccServiceV1S3LoggingConfig_formatVersion(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"
}
s3logging {
name = "somebucketlog"
bucket_name = "fastlytestlogging"
domain = "s3-us-west-2.amazonaws.com"
s3_access_key = "somekey"
s3_secret_key = "somesecret"
format = "%%a %%l %%u %%t %%m %%U%%q %%H %%>s %%b %%T"
format_version = 2
}
force_destroy = true
}`, name, domain)
}
func setEnv(s string, t *testing.T) func() { func setEnv(s string, t *testing.T) func() {
e := getEnv() e := getEnv()
// Set all the envs to a dummy value // Set all the envs to a dummy value

View File

@ -0,0 +1,17 @@
package fastly
import "fmt"
func validateS3FormatVersion(v interface{}, k string) (ws []string, errors []error) {
value := uint(v.(int))
validVersions := map[uint]struct{}{
1: {},
2: {},
}
if _, ok := validVersions[value]; !ok {
errors = append(errors, fmt.Errorf(
"%q must be one of ['1', '2']", k))
}
return
}

View File

@ -0,0 +1,29 @@
package fastly
import "testing"
func TestValidateS3FormatVersion(t *testing.T) {
validVersions := []uint{
1,
2,
}
for _, v := range validVersions {
_, errors := validateS3FormatVersion(v, "format_version")
if len(errors) != 0 {
t.Fatalf("%q should be a valid format version: %q", v, errors)
}
}
invalidVersions := []uint{
0,
3,
4,
5,
}
for _, v := range invalidVersions {
_, errors := validateS3FormatVersion(v, "format_version")
if len(errors) != 1 {
t.Fatalf("%q should not be a valid format version", v)
}
}
}

View File

@ -26,6 +26,9 @@ type Backend struct {
Shield string `mapstructure:"shield"` Shield string `mapstructure:"shield"`
UseSSL bool `mapstructure:"use_ssl"` UseSSL bool `mapstructure:"use_ssl"`
SSLCheckCert bool `mapstructure:"ssl_check_cert"` SSLCheckCert bool `mapstructure:"ssl_check_cert"`
SSLCACert string `mapstructure:"ssl_ca_cert"`
SSLClientCert string `mapstructure:"ssl_client_cert"`
SSLClientKey string `mapstructure:"ssl_client_key"`
SSLHostname string `mapstructure:"ssl_hostname"` SSLHostname string `mapstructure:"ssl_hostname"`
SSLCertHostname string `mapstructure:"ssl_cert_hostname"` SSLCertHostname string `mapstructure:"ssl_cert_hostname"`
SSLSNIHostname string `mapstructure:"ssl_sni_hostname"` SSLSNIHostname string `mapstructure:"ssl_sni_hostname"`
@ -99,6 +102,9 @@ type CreateBackendInput struct {
Shield string `form:"shield,omitempty"` Shield string `form:"shield,omitempty"`
UseSSL *Compatibool `form:"use_ssl,omitempty"` UseSSL *Compatibool `form:"use_ssl,omitempty"`
SSLCheckCert *Compatibool `form:"ssl_check_cert,omitempty"` SSLCheckCert *Compatibool `form:"ssl_check_cert,omitempty"`
SSLCACert string `form:"ssl_ca_cert,omitempty"`
SSLClientCert string `form:"ssl_client_cert,omitempty"`
SSLClientKey string `form:"ssl_client_key,omitempty"`
SSLHostname string `form:"ssl_hostname,omitempty"` SSLHostname string `form:"ssl_hostname,omitempty"`
SSLCertHostname string `form:"ssl_cert_hostname,omitempty"` SSLCertHostname string `form:"ssl_cert_hostname,omitempty"`
SSLSNIHostname string `form:"ssl_sni_hostname,omitempty"` SSLSNIHostname string `form:"ssl_sni_hostname,omitempty"`
@ -193,6 +199,9 @@ type UpdateBackendInput struct {
Shield string `form:"shield,omitempty"` Shield string `form:"shield,omitempty"`
UseSSL *Compatibool `form:"use_ssl,omitempty"` UseSSL *Compatibool `form:"use_ssl,omitempty"`
SSLCheckCert *Compatibool `form:"ssl_check_cert,omitempty"` SSLCheckCert *Compatibool `form:"ssl_check_cert,omitempty"`
SSLCACert string `form:"ssl_ca_cert,omitempty"`
SSLClientCert string `form:"ssl_client_cert,omitempty"`
SSLClientKey string `form:"ssl_client_key,omitempty"`
SSLHostname string `form:"ssl_hostname,omitempty"` SSLHostname string `form:"ssl_hostname,omitempty"`
SSLCertHostname string `form:"ssl_cert_hostname,omitempty"` SSLCertHostname string `form:"ssl_cert_hostname,omitempty"`
SSLSNIHostname string `form:"ssl_sni_hostname,omitempty"` SSLSNIHostname string `form:"ssl_sni_hostname,omitempty"`

View File

@ -27,6 +27,7 @@ type S3 struct {
Period uint `mapstructure:"period"` Period uint `mapstructure:"period"`
GzipLevel uint `mapstructure:"gzip_level"` GzipLevel uint `mapstructure:"gzip_level"`
Format string `mapstructure:"format"` Format string `mapstructure:"format"`
FormatVersion uint `mapstructure:"format_version"`
ResponseCondition string `mapstructure:"response_condition"` ResponseCondition string `mapstructure:"response_condition"`
TimestampFormat string `mapstructure:"timestamp_format"` TimestampFormat string `mapstructure:"timestamp_format"`
Redundancy S3Redundancy `mapstructure:"redundancy"` Redundancy S3Redundancy `mapstructure:"redundancy"`
@ -94,6 +95,7 @@ type CreateS3Input struct {
Period uint `form:"period,omitempty"` Period uint `form:"period,omitempty"`
GzipLevel uint `form:"gzip_level,omitempty"` GzipLevel uint `form:"gzip_level,omitempty"`
Format string `form:"format,omitempty"` Format string `form:"format,omitempty"`
FormatVersion uint `form:"format_version,omitempty"`
ResponseCondition string `form:"response_condition,omitempty"` ResponseCondition string `form:"response_condition,omitempty"`
TimestampFormat string `form:"timestamp_format,omitempty"` TimestampFormat string `form:"timestamp_format,omitempty"`
Redundancy S3Redundancy `form:"redundancy,omitempty"` Redundancy S3Redundancy `form:"redundancy,omitempty"`
@ -179,6 +181,7 @@ type UpdateS3Input struct {
Period uint `form:"period,omitempty"` Period uint `form:"period,omitempty"`
GzipLevel uint `form:"gzip_level,omitempty"` GzipLevel uint `form:"gzip_level,omitempty"`
Format string `form:"format,omitempty"` Format string `form:"format,omitempty"`
FormatVersion uint `form:"format_version,omitempty"`
ResponseCondition string `form:"response_condition,omitempty"` ResponseCondition string `form:"response_condition,omitempty"`
TimestampFormat string `form:"timestamp_format,omitempty"` TimestampFormat string `form:"timestamp_format,omitempty"`
Redundancy S3Redundancy `form:"redundancy,omitempty"` Redundancy S3Redundancy `form:"redundancy,omitempty"`

6
vendor/vendor.json vendored
View File

@ -2441,10 +2441,10 @@
"revisionTime": "2016-12-25T12:04:19Z" "revisionTime": "2016-12-25T12:04:19Z"
}, },
{ {
"checksumSHA1": "BqtlwAjgFuHsVVdnw+dGSe+CKLM=", "checksumSHA1": "ySSmShoczI/i/5PzurH8Uhi/dbA=",
"path": "github.com/sethvargo/go-fastly", "path": "github.com/sethvargo/go-fastly",
"revision": "2f6c4b7ec89b1e3ece8e770af7b2b546c5a048de", "revision": "247f42f7ecc6677aa1b6e30978d06fcc38f5f769",
"revisionTime": "2016-10-26T14:57:03Z" "revisionTime": "2017-02-06T18:56:52Z"
}, },
{ {
"checksumSHA1": "8tEiK6vhVXuUbnWME5XNWLgvtSo=", "checksumSHA1": "8tEiK6vhVXuUbnWME5XNWLgvtSo=",