Merge pull request #7852 from gaker/google-provider-backend-cdn

google_compute_backend_service "enable_cdn"
This commit is contained in:
Evan Brown 2016-08-03 20:11:54 -07:00 committed by GitHub
commit 89df636163
12 changed files with 6008 additions and 2525 deletions

View File

@ -88,6 +88,12 @@ func resourceComputeBackendService() *schema.Resource {
Optional: true, Optional: true,
}, },
"enable_cdn": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"fingerprint": &schema.Schema{ "fingerprint": &schema.Schema{
Type: schema.TypeString, Type: schema.TypeString,
Computed: true, Computed: true,
@ -165,6 +171,10 @@ func resourceComputeBackendServiceCreate(d *schema.ResourceData, meta interface{
service.TimeoutSec = int64(v.(int)) service.TimeoutSec = int64(v.(int))
} }
if v, ok := d.GetOk("enable_cdn"); ok {
service.EnableCDN = v.(bool)
}
project, err := getProject(d, config) project, err := getProject(d, config)
if err != nil { if err != nil {
return err return err
@ -212,6 +222,7 @@ func resourceComputeBackendServiceRead(d *schema.ResourceData, meta interface{})
} }
d.Set("description", service.Description) d.Set("description", service.Description)
d.Set("enable_cdn", service.EnableCDN)
d.Set("port_name", service.PortName) d.Set("port_name", service.PortName)
d.Set("protocol", service.Protocol) d.Set("protocol", service.Protocol)
d.Set("timeout_sec", service.TimeoutSec) d.Set("timeout_sec", service.TimeoutSec)
@ -260,6 +271,10 @@ func resourceComputeBackendServiceUpdate(d *schema.ResourceData, meta interface{
service.TimeoutSec = int64(d.Get("timeout_sec").(int)) service.TimeoutSec = int64(d.Get("timeout_sec").(int))
} }
if d.HasChange("enable_cdn") {
service.EnableCDN = d.Get("enable_cdn").(bool)
}
log.Printf("[DEBUG] Updating existing Backend Service %q: %#v", d.Id(), service) log.Printf("[DEBUG] Updating existing Backend Service %q: %#v", d.Id(), service)
op, err := config.clientCompute.BackendServices.Update( op, err := config.clientCompute.BackendServices.Update(
project, d.Id(), &service).Do() project, d.Id(), &service).Do()

View File

@ -121,6 +121,32 @@ func testAccCheckComputeBackendServiceExists(n string, svc *compute.BackendServi
} }
} }
func TestAccComputeBackendService_withCDNEnabled(t *testing.T) {
serviceName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
checkName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var svc compute.BackendService
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeBackendServiceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeBackendService_withCDNEnabled(
serviceName, checkName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeBackendServiceExists(
"google_compute_backend_service.foobar", &svc),
),
},
},
})
if svc.EnableCDN != true {
t.Errorf("Expected EnableCDN == true, got %t", svc.EnableCDN)
}
}
func testAccComputeBackendService_basic(serviceName, checkName string) string { func testAccComputeBackendService_basic(serviceName, checkName string) string {
return fmt.Sprintf(` return fmt.Sprintf(`
resource "google_compute_backend_service" "foobar" { resource "google_compute_backend_service" "foobar" {
@ -137,6 +163,23 @@ resource "google_compute_http_health_check" "zero" {
`, serviceName, checkName) `, serviceName, checkName)
} }
func testAccComputeBackendService_withCDNEnabled(serviceName, checkName string) string {
return fmt.Sprintf(`
resource "google_compute_backend_service" "foobar" {
name = "%s"
health_checks = ["${google_compute_http_health_check.zero.self_link}"]
enable_cdn = true
}
resource "google_compute_http_health_check" "zero" {
name = "%s"
request_path = "/"
check_interval_sec = 1
timeout_sec = 1
}
`, serviceName, checkName)
}
func testAccComputeBackendService_basicModified(serviceName, checkOne, checkTwo string) string { func testAccComputeBackendService_basicModified(serviceName, checkOne, checkTwo string) string {
return fmt.Sprintf(` return fmt.Sprintf(`
resource "google_compute_backend_service" "foobar" { resource "google_compute_backend_service" "foobar" {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,8 +11,8 @@ import (
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
) )
// ResumableBuffer buffers data from an io.Reader to support uploading media in retryable chunks. // MediaBuffer buffers data from an io.Reader to support uploading media in retryable chunks.
type ResumableBuffer struct { type MediaBuffer struct {
media io.Reader media io.Reader
chunk []byte // The current chunk which is pending upload. The capacity is the chunk size. chunk []byte // The current chunk which is pending upload. The capacity is the chunk size.
@ -22,42 +22,42 @@ type ResumableBuffer struct {
off int64 off int64
} }
func NewResumableBuffer(media io.Reader, chunkSize int) *ResumableBuffer { func NewMediaBuffer(media io.Reader, chunkSize int) *MediaBuffer {
return &ResumableBuffer{media: media, chunk: make([]byte, 0, chunkSize)} return &MediaBuffer{media: media, chunk: make([]byte, 0, chunkSize)}
} }
// Chunk returns the current buffered chunk, the offset in the underlying media // Chunk returns the current buffered chunk, the offset in the underlying media
// from which the chunk is drawn, and the size of the chunk. // from which the chunk is drawn, and the size of the chunk.
// Successive calls to Chunk return the same chunk between calls to Next. // Successive calls to Chunk return the same chunk between calls to Next.
func (rb *ResumableBuffer) Chunk() (chunk io.Reader, off int64, size int, err error) { func (mb *MediaBuffer) Chunk() (chunk io.Reader, off int64, size int, err error) {
// There may already be data in chunk if Next has not been called since the previous call to Chunk. // There may already be data in chunk if Next has not been called since the previous call to Chunk.
if rb.err == nil && len(rb.chunk) == 0 { if mb.err == nil && len(mb.chunk) == 0 {
rb.err = rb.loadChunk() mb.err = mb.loadChunk()
} }
return bytes.NewReader(rb.chunk), rb.off, len(rb.chunk), rb.err return bytes.NewReader(mb.chunk), mb.off, len(mb.chunk), mb.err
} }
// loadChunk will read from media into chunk, up to the capacity of chunk. // loadChunk will read from media into chunk, up to the capacity of chunk.
func (rb *ResumableBuffer) loadChunk() error { func (mb *MediaBuffer) loadChunk() error {
bufSize := cap(rb.chunk) bufSize := cap(mb.chunk)
rb.chunk = rb.chunk[:bufSize] mb.chunk = mb.chunk[:bufSize]
read := 0 read := 0
var err error var err error
for err == nil && read < bufSize { for err == nil && read < bufSize {
var n int var n int
n, err = rb.media.Read(rb.chunk[read:]) n, err = mb.media.Read(mb.chunk[read:])
read += n read += n
} }
rb.chunk = rb.chunk[:read] mb.chunk = mb.chunk[:read]
return err return err
} }
// Next advances to the next chunk, which will be returned by the next call to Chunk. // Next advances to the next chunk, which will be returned by the next call to Chunk.
// Calls to Next without a corresponding prior call to Chunk will have no effect. // Calls to Next without a corresponding prior call to Chunk will have no effect.
func (rb *ResumableBuffer) Next() { func (mb *MediaBuffer) Next() {
rb.off += int64(len(rb.chunk)) mb.off += int64(len(mb.chunk))
rb.chunk = rb.chunk[0:0] mb.chunk = mb.chunk[0:0]
} }
type readerTyper struct { type readerTyper struct {

View File

@ -176,25 +176,24 @@ func typeHeader(contentType string) textproto.MIMEHeader {
// chunkSize is the size of the chunk that media should be split into. // chunkSize is the size of the chunk that media should be split into.
// If chunkSize is non-zero and the contents of media do not fit in a single // If chunkSize is non-zero and the contents of media do not fit in a single
// chunk (or there is an error reading media), then media will be returned as a // chunk (or there is an error reading media), then media will be returned as a
// ResumableBuffer. Otherwise, media will be returned as a Reader. // MediaBuffer. Otherwise, media will be returned as a Reader.
// //
// After PrepareUpload has been called, media should no longer be used: the // After PrepareUpload has been called, media should no longer be used: the
// media content should be accessed via one of the return values. // media content should be accessed via one of the return values.
func PrepareUpload(media io.Reader, chunkSize int) (io.Reader, func PrepareUpload(media io.Reader, chunkSize int) (io.Reader, *MediaBuffer) {
*ResumableBuffer) {
if chunkSize == 0 { // do not chunk if chunkSize == 0 { // do not chunk
return media, nil return media, nil
} }
rb := NewResumableBuffer(media, chunkSize) mb := NewMediaBuffer(media, chunkSize)
rdr, _, _, err := rb.Chunk() rdr, _, _, err := mb.Chunk()
if err == io.EOF { // we can upload this in a single request if err == io.EOF { // we can upload this in a single request
return rdr, nil return rdr, nil
} }
// err might be a non-EOF error. If it is, the next call to rb.Chunk will // err might be a non-EOF error. If it is, the next call to mb.Chunk will
// return the same error. Returning a ResumableBuffer ensures that this error // return the same error. Returning a MediaBuffer ensures that this error
// will be handled at some point. // will be handled at some point.
return nil, rb return nil, mb
} }

View File

@ -35,7 +35,7 @@ type ResumableUpload struct {
URI string URI string
UserAgent string // User-Agent for header of the request UserAgent string // User-Agent for header of the request
// Media is the object being uploaded. // Media is the object being uploaded.
Media *ResumableBuffer Media *MediaBuffer
// MediaType defines the media type, e.g. "image/jpeg". // MediaType defines the media type, e.g. "image/jpeg".
MediaType string MediaType string
@ -80,7 +80,10 @@ func (rx *ResumableUpload) doUploadRequest(ctx context.Context, data io.Reader,
req.Header.Set("Content-Range", contentRange) req.Header.Set("Content-Range", contentRange)
req.Header.Set("Content-Type", rx.MediaType) req.Header.Set("Content-Type", rx.MediaType)
req.Header.Set("User-Agent", rx.UserAgent) req.Header.Set("User-Agent", rx.UserAgent)
return ctxhttp.Do(ctx, rx.Client, req) fn := Hook(ctx, req)
resp, err := ctxhttp.Do(ctx, rx.Client, req)
fn(resp)
return resp, err
} }
@ -135,6 +138,8 @@ func contextDone(ctx context.Context) bool {
// It retries using the provided back off strategy until cancelled or the // It retries using the provided back off strategy until cancelled or the
// strategy indicates to stop retrying. // strategy indicates to stop retrying.
// It is called from the auto-generated API code and is not visible to the user. // It is called from the auto-generated API code and is not visible to the user.
// Before sending an HTTP request, Upload calls Hook to obtain a function which
// it subsequently calls with the HTTP response.
// rx is private to the auto-generated API code. // rx is private to the auto-generated API code.
// Exactly one of resp or err will be nil. If resp is non-nil, the caller must call resp.Body.Close. // Exactly one of resp or err will be nil. If resp is non-nil, the caller must call resp.Body.Close.
func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err error) { func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err error) {

35
vendor/google.golang.org/api/gensupport/send.go generated vendored Normal file
View File

@ -0,0 +1,35 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gensupport
import (
"net/http"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
)
// Hook is a function that is called once before each HTTP request that is sent
// by a generated API. It returns a function that is called after the request
// returns.
// Hook is never called if the context is nil.
var Hook func(ctx context.Context, req *http.Request) func(resp *http.Response) = defaultHook
func defaultHook(ctx context.Context, req *http.Request) func(resp *http.Response) {
return func(resp *http.Response) {}
}
// SendRequest sends a single HTTP request using the given client.
// If ctx is non-nil, uses ctxhttp.Do, and calls Hook beforehand. The function
// returned by Hook is called after the request returns.
func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
if ctx != nil {
fn := Hook(ctx, req)
resp, err := ctxhttp.Do(ctx, client, req)
fn(resp)
return resp, err
}
return client.Do(req)
}

View File

@ -1,11 +1,11 @@
{ {
"kind": "discovery#restDescription", "kind": "discovery#restDescription",
"etag": "\"bRFOOrZKfO9LweMbPqu0kcu6De8/KVPQfwGxQTBtH0g1kuij0C9i4uc\"", "etag": "\"C5oy1hgQsABtYOYIOXWcR3BgYqU/cPnwg2U9hg8m8Y6wHWcvqIF8qSM\"",
"discoveryVersion": "v1", "discoveryVersion": "v1",
"id": "storage:v1", "id": "storage:v1",
"name": "storage", "name": "storage",
"version": "v1", "version": "v1",
"revision": "20160304", "revision": "20160609",
"title": "Cloud Storage JSON API", "title": "Cloud Storage JSON API",
"description": "Stores and retrieves potentially large, immutable data objects.", "description": "Stores and retrieves potentially large, immutable data objects.",
"ownerDomain": "google.com", "ownerDomain": "google.com",
@ -294,15 +294,15 @@
}, },
"website": { "website": {
"type": "object", "type": "object",
"description": "The bucket's website configuration.", "description": "The bucket's website configuration, controlling how the service behaves when accessing bucket contents as a web site. See the Static Website Examples for more information.",
"properties": { "properties": {
"mainPageSuffix": { "mainPageSuffix": {
"type": "string", "type": "string",
"description": "Behaves as the bucket's directory index where missing objects are treated as potential directories." "description": "If the requested object path is missing, the service will ensure the path has a trailing '/', append this suffix, and attempt to retrieve the resulting object. This allows the creation of index.html objects to represent directory pages."
}, },
"notFoundPage": { "notFoundPage": {
"type": "string", "type": "string",
"description": "The custom object to return when a requested resource is not found." "description": "If the requested object path is missing, and any mainPageSuffix object is missing, if applicable, the service will return the named object from this bucket as the content for a 404 Not Found result."
} }
} }
} }
@ -574,7 +574,7 @@
}, },
"contentType": { "contentType": {
"type": "string", "type": "string",
"description": "Content-Type of the object data." "description": "Content-Type of the object data. If contentType is not specified, object downloads will be served as application/octet-stream."
}, },
"crc32c": { "crc32c": {
"type": "string", "type": "string",
@ -1088,7 +1088,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit acl and defaultObjectAcl properties." "Omit owner, acl and defaultObjectAcl properties."
], ],
"location": "query" "location": "query"
} }
@ -1168,7 +1168,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit acl and defaultObjectAcl properties." "Omit owner, acl and defaultObjectAcl properties."
], ],
"location": "query" "location": "query"
} }
@ -1226,7 +1226,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit acl and defaultObjectAcl properties." "Omit owner, acl and defaultObjectAcl properties."
], ],
"location": "query" "location": "query"
} }
@ -1318,7 +1318,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit acl and defaultObjectAcl properties." "Omit owner, acl and defaultObjectAcl properties."
], ],
"location": "query" "location": "query"
} }
@ -1334,8 +1334,7 @@
}, },
"scopes": [ "scopes": [
"https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/devstorage.full_control"
"https://www.googleapis.com/auth/devstorage.read_write"
] ]
}, },
"update": { "update": {
@ -1411,7 +1410,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit acl and defaultObjectAcl properties." "Omit owner, acl and defaultObjectAcl properties."
], ],
"location": "query" "location": "query"
} }
@ -1427,8 +1426,7 @@
}, },
"scopes": [ "scopes": [
"https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/devstorage.full_control"
"https://www.googleapis.com/auth/devstorage.read_write"
] ]
} }
} }
@ -2076,7 +2074,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit the acl property." "Omit the owner, acl property."
], ],
"location": "query" "location": "query"
}, },
@ -2235,7 +2233,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit the acl property." "Omit the owner, acl property."
], ],
"location": "query" "location": "query"
} }
@ -2333,7 +2331,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit the acl property." "Omit the owner, acl property."
], ],
"location": "query" "location": "query"
} }
@ -2414,7 +2412,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit the acl property." "Omit the owner, acl property."
], ],
"location": "query" "location": "query"
}, },
@ -2517,7 +2515,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit the acl property." "Omit the owner, acl property."
], ],
"location": "query" "location": "query"
} }
@ -2534,8 +2532,7 @@
}, },
"scopes": [ "scopes": [
"https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/devstorage.full_control"
"https://www.googleapis.com/auth/devstorage.read_write"
] ]
}, },
"rewrite": { "rewrite": {
@ -2640,7 +2637,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit the acl property." "Omit the owner, acl property."
], ],
"location": "query" "location": "query"
}, },
@ -2764,7 +2761,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit the acl property." "Omit the owner, acl property."
], ],
"location": "query" "location": "query"
} }
@ -2781,8 +2778,7 @@
}, },
"scopes": [ "scopes": [
"https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/devstorage.full_control"
"https://www.googleapis.com/auth/devstorage.read_write"
], ],
"supportsMediaDownload": true, "supportsMediaDownload": true,
"useMediaDownloadService": true "useMediaDownloadService": true
@ -2830,7 +2826,7 @@
], ],
"enumDescriptions": [ "enumDescriptions": [
"Include all properties.", "Include all properties.",
"Omit the acl property." "Omit the owner, acl property."
], ],
"location": "query" "location": "query"
}, },

File diff suppressed because it is too large Load Diff

12
vendor/vendor.json vendored
View File

@ -1927,8 +1927,10 @@
"revision": "5eaf0df67e70d6997a9fe0ed24383fa1b01638d3" "revision": "5eaf0df67e70d6997a9fe0ed24383fa1b01638d3"
}, },
{ {
"checksumSHA1": "SjcL6w27LsP7xLQe9V068FO3qWI=",
"path": "google.golang.org/api/compute/v1", "path": "google.golang.org/api/compute/v1",
"revision": "43c645d4bcf9251ced36c823a93b6d198764aae4" "revision": "fa0566afd4c8fdae644725fdf9b57b5851a20742",
"revisionTime": "2016-07-18T05:58:24Z"
}, },
{ {
"path": "google.golang.org/api/container/v1", "path": "google.golang.org/api/container/v1",
@ -1939,8 +1941,10 @@
"revision": "43c645d4bcf9251ced36c823a93b6d198764aae4" "revision": "43c645d4bcf9251ced36c823a93b6d198764aae4"
}, },
{ {
"checksumSHA1": "SLzHstPylt3EcBt9yEBJV+JqGp4=",
"path": "google.golang.org/api/gensupport", "path": "google.golang.org/api/gensupport",
"revision": "43c645d4bcf9251ced36c823a93b6d198764aae4" "revision": "fa0566afd4c8fdae644725fdf9b57b5851a20742",
"revisionTime": "2016-07-18T05:58:24Z"
}, },
{ {
"path": "google.golang.org/api/googleapi", "path": "google.golang.org/api/googleapi",
@ -1959,8 +1963,10 @@
"revision": "43c645d4bcf9251ced36c823a93b6d198764aae4" "revision": "43c645d4bcf9251ced36c823a93b6d198764aae4"
}, },
{ {
"checksumSHA1": "xIEDa8ZDicVplvLtQUHc9eVZays=",
"path": "google.golang.org/api/storage/v1", "path": "google.golang.org/api/storage/v1",
"revision": "43c645d4bcf9251ced36c823a93b6d198764aae4" "revision": "fa0566afd4c8fdae644725fdf9b57b5851a20742",
"revisionTime": "2016-07-18T05:58:24Z"
}, },
{ {
"path": "google.golang.org/appengine", "path": "google.golang.org/appengine",

View File

@ -19,6 +19,7 @@ resource "google_compute_backend_service" "foobar" {
port_name = "http" port_name = "http"
protocol = "HTTP" protocol = "HTTP"
timeout_sec = 10 timeout_sec = 10
enable_cdn = false
backend { backend {
group = "${google_compute_instance_group_manager.foo.instance_group}" group = "${google_compute_instance_group_manager.foo.instance_group}"
@ -74,6 +75,8 @@ The following arguments are supported:
* `description` - (Optional) The textual description for the backend service. * `description` - (Optional) The textual description for the backend service.
* `enable_cdn` - (Optional) Whether or not to enable the Cloud CDN on the backend service.
* `port_name` - (Optional) The name of a service that has been added to an * `port_name` - (Optional) The name of a service that has been added to an
instance group in this backend. See [related docs](https://cloud.google.com/compute/docs/instance-groups/#specifying_service_endpoints) for details. Defaults to http. instance group in this backend. See [related docs](https://cloud.google.com/compute/docs/instance-groups/#specifying_service_endpoints) for details. Defaults to http.