Merge pull request #14015 from ctavan/add-google-backend-buckets

provider/google/compute: Add google backend buckets
This commit is contained in:
Dana Hoffman 2017-05-02 16:30:22 -07:00 committed by GitHub
commit 50387772ad
11 changed files with 3165 additions and 551 deletions

View File

@ -58,6 +58,7 @@ func Provider() terraform.ResourceProvider {
"google_bigquery_dataset": resourceBigQueryDataset(), "google_bigquery_dataset": resourceBigQueryDataset(),
"google_compute_autoscaler": resourceComputeAutoscaler(), "google_compute_autoscaler": resourceComputeAutoscaler(),
"google_compute_address": resourceComputeAddress(), "google_compute_address": resourceComputeAddress(),
"google_compute_backend_bucket": resourceComputeBackendBucket(),
"google_compute_backend_service": resourceComputeBackendService(), "google_compute_backend_service": resourceComputeBackendService(),
"google_compute_disk": resourceComputeDisk(), "google_compute_disk": resourceComputeDisk(),
"google_compute_firewall": resourceComputeFirewall(), "google_compute_firewall": resourceComputeFirewall(),

View File

@ -333,7 +333,7 @@ func resourceComputeAutoscalerUpdate(d *schema.ResourceData, meta interface{}) e
} }
op, err := config.clientCompute.Autoscalers.Patch( op, err := config.clientCompute.Autoscalers.Patch(
project, zone, d.Id(), scaler).Do() project, zone, scaler).Do()
if err != nil { if err != nil {
return fmt.Errorf("Error updating Autoscaler: %s", err) return fmt.Errorf("Error updating Autoscaler: %s", err)
} }

View File

@ -0,0 +1,201 @@
package google
import (
"fmt"
"log"
"regexp"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/compute/v1"
"google.golang.org/api/googleapi"
)
func resourceComputeBackendBucket() *schema.Resource {
return &schema.Resource{
Create: resourceComputeBackendBucketCreate,
Read: resourceComputeBackendBucketRead,
Update: resourceComputeBackendBucketUpdate,
Delete: resourceComputeBackendBucketDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
re := `^(?:[a-z](?:[-a-z0-9]{0,61}[a-z0-9])?)$`
if !regexp.MustCompile(re).MatchString(value) {
errors = append(errors, fmt.Errorf(
"%q (%q) doesn't match regexp %q", k, value, re))
}
return
},
},
"bucket_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"description": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"enable_cdn": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"project": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"self_link": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}
func resourceComputeBackendBucketCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
bucket := compute.BackendBucket{
Name: d.Get("name").(string),
BucketName: d.Get("bucket_name").(string),
}
if v, ok := d.GetOk("description"); ok {
bucket.Description = v.(string)
}
if v, ok := d.GetOk("enable_cdn"); ok {
bucket.EnableCdn = v.(bool)
}
project, err := getProject(d, config)
if err != nil {
return err
}
log.Printf("[DEBUG] Creating new Backend Bucket: %#v", bucket)
op, err := config.clientCompute.BackendBuckets.Insert(
project, &bucket).Do()
if err != nil {
return fmt.Errorf("Error creating backend bucket: %s", err)
}
log.Printf("[DEBUG] Waiting for new backend bucket, operation: %#v", op)
// Store the ID now
d.SetId(bucket.Name)
// Wait for the operation to complete
waitErr := computeOperationWaitGlobal(config, op, project, "Creating Backend Bucket")
if waitErr != nil {
// The resource didn't actually create
d.SetId("")
return waitErr
}
return resourceComputeBackendBucketRead(d, meta)
}
func resourceComputeBackendBucketRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
project, err := getProject(d, config)
if err != nil {
return err
}
bucket, err := config.clientCompute.BackendBuckets.Get(
project, d.Id()).Do()
if err != nil {
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
// The resource doesn't exist anymore
log.Printf("[WARN] Removing Backend Bucket %q because it's gone", d.Get("name").(string))
d.SetId("")
return nil
}
return fmt.Errorf("Error reading bucket: %s", err)
}
d.Set("bucket_name", bucket.BucketName)
d.Set("description", bucket.Description)
d.Set("enable_cdn", bucket.EnableCdn)
d.Set("self_link", bucket.SelfLink)
return nil
}
func resourceComputeBackendBucketUpdate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
project, err := getProject(d, config)
if err != nil {
return err
}
bucket := compute.BackendBucket{
Name: d.Get("name").(string),
BucketName: d.Get("bucket_name").(string),
}
// Optional things
if v, ok := d.GetOk("description"); ok {
bucket.Description = v.(string)
}
if v, ok := d.GetOk("enable_cdn"); ok {
bucket.EnableCdn = v.(bool)
}
log.Printf("[DEBUG] Updating existing Backend Bucket %q: %#v", d.Id(), bucket)
op, err := config.clientCompute.BackendBuckets.Update(
project, d.Id(), &bucket).Do()
if err != nil {
return fmt.Errorf("Error updating backend bucket: %s", err)
}
d.SetId(bucket.Name)
err = computeOperationWaitGlobal(config, op, project, "Updating Backend Bucket")
if err != nil {
return err
}
return resourceComputeBackendBucketRead(d, meta)
}
func resourceComputeBackendBucketDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
project, err := getProject(d, config)
if err != nil {
return err
}
log.Printf("[DEBUG] Deleting backend bucket %s", d.Id())
op, err := config.clientCompute.BackendBuckets.Delete(
project, d.Id()).Do()
if err != nil {
return fmt.Errorf("Error deleting backend bucket: %s", err)
}
err = computeOperationWaitGlobal(config, op, project, "Deleting Backend Bucket")
if err != nil {
return err
}
d.SetId("")
return nil
}

View File

@ -0,0 +1,191 @@
package google
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"google.golang.org/api/compute/v1"
)
func TestAccComputeBackendBucket_basic(t *testing.T) {
backendName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
storageName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var svc compute.BackendBucket
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeBackendBucketDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeBackendBucket_basic(backendName, storageName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeBackendBucketExists(
"google_compute_backend_bucket.foobar", &svc),
),
},
},
})
if svc.BucketName != storageName {
t.Errorf("Expected BucketName to be %q, got %q", storageName, svc.BucketName)
}
}
func TestAccComputeBackendBucket_basicModified(t *testing.T) {
backendName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
storageName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
secondStorageName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var svc compute.BackendBucket
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeBackendBucketDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeBackendBucket_basic(backendName, storageName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeBackendBucketExists(
"google_compute_backend_bucket.foobar", &svc),
),
},
resource.TestStep{
Config: testAccComputeBackendBucket_basicModified(
backendName, storageName, secondStorageName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeBackendBucketExists(
"google_compute_backend_bucket.foobar", &svc),
),
},
},
})
if svc.BucketName != secondStorageName {
t.Errorf("Expected BucketName to be %q, got %q", secondStorageName, svc.BucketName)
}
}
func testAccCheckComputeBackendBucketDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_compute_backend_bucket" {
continue
}
_, err := config.clientCompute.BackendBuckets.Get(
config.Project, rs.Primary.ID).Do()
if err == nil {
return fmt.Errorf("Backend bucket %s still exists", rs.Primary.ID)
}
}
return nil
}
func testAccCheckComputeBackendBucketExists(n string, svc *compute.BackendBucket) 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 ID is set")
}
config := testAccProvider.Meta().(*Config)
found, err := config.clientCompute.BackendBuckets.Get(
config.Project, rs.Primary.ID).Do()
if err != nil {
return err
}
if found.Name != rs.Primary.ID {
return fmt.Errorf("Backend bucket %s not found", rs.Primary.ID)
}
*svc = *found
return nil
}
}
func TestAccComputeBackendBucket_withCdnEnabled(t *testing.T) {
backendName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
storageName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
var svc compute.BackendBucket
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeBackendBucketDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeBackendBucket_withCdnEnabled(
backendName, storageName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeBackendBucketExists(
"google_compute_backend_bucket.foobar", &svc),
),
},
},
})
if svc.EnableCdn != true {
t.Errorf("Expected EnableCdn == true, got %t", svc.EnableCdn)
}
}
func testAccComputeBackendBucket_basic(backendName, storageName string) string {
return fmt.Sprintf(`
resource "google_compute_backend_bucket" "foobar" {
name = "%s"
bucket_name = "${google_storage_bucket.bucket_one.name}"
}
resource "google_storage_bucket" "bucket_one" {
name = "%s"
location = "EU"
}
`, backendName, storageName)
}
func testAccComputeBackendBucket_basicModified(backendName, bucketOne, bucketTwo string) string {
return fmt.Sprintf(`
resource "google_compute_backend_bucket" "foobar" {
name = "%s"
bucket_name = "${google_storage_bucket.bucket_two.name}"
}
resource "google_storage_bucket" "bucket_one" {
name = "%s"
location = "EU"
}
resource "google_storage_bucket" "bucket_two" {
name = "%s"
location = "EU"
}
`, backendName, bucketOne, bucketTwo)
}
func testAccComputeBackendBucket_withCdnEnabled(backendName, storageName string) string {
return fmt.Sprintf(`
resource "google_compute_backend_bucket" "foobar" {
name = "%s"
bucket_name = "${google_storage_bucket.bucket.name}"
enable_cdn = true
}
resource "google_storage_bucket" "bucket" {
name = "%s"
location = "EU"
}
`, backendName, storageName)
}

View File

@ -200,11 +200,15 @@ func resourceComputeBackendServiceCreate(d *schema.ResourceData, meta interface{
log.Printf("[DEBUG] Waiting for new backend service, operation: %#v", op) log.Printf("[DEBUG] Waiting for new backend service, operation: %#v", op)
// Store the ID now
d.SetId(service.Name) d.SetId(service.Name)
err = computeOperationWaitGlobal(config, op, project, "Creating Backend Service") // Wait for the operation to complete
if err != nil { waitErr := computeOperationWaitGlobal(config, op, project, "Creating Backend Service")
return err if waitErr != nil {
// The resource didn't actually create
d.SetId("")
return waitErr
} }
return resourceComputeBackendServiceRead(d, meta) return resourceComputeBackendServiceRead(d, meta)

View File

@ -125,7 +125,7 @@ func testAccCheckComputeBackendServiceDestroy(s *terraform.State) error {
_, err := config.clientCompute.BackendServices.Get( _, err := config.clientCompute.BackendServices.Get(
config.Project, rs.Primary.ID).Do() config.Project, rs.Primary.ID).Do()
if err == nil { if err == nil {
return fmt.Errorf("Backend service still exists") return fmt.Errorf("Backend service %s still exists", rs.Primary.ID)
} }
} }
@ -152,7 +152,7 @@ func testAccCheckComputeBackendServiceExists(n string, svc *compute.BackendServi
} }
if found.Name != rs.Primary.ID { if found.Name != rs.Primary.ID {
return fmt.Errorf("Backend service not found") return fmt.Errorf("Backend service %s not found", rs.Primary.ID)
} }
*svc = *found *svc = *found

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6
vendor/vendor.json vendored
View File

@ -3315,10 +3315,10 @@
"revisionTime": "2016-11-27T23:54:21Z" "revisionTime": "2016-11-27T23:54:21Z"
}, },
{ {
"checksumSHA1": "a3xBCGUHttHW7+VrTk8bqxU6pOY=", "checksumSHA1": "tD5kobeqw1b4V20UQsM2zTTDRHY=",
"path": "google.golang.org/api/compute/v1", "path": "google.golang.org/api/compute/v1",
"revision": "8840436417f044055c16fc7e4018f08484f52839", "revision": "fbbaff1827317122a8a0e1b24de25df8417ce87b",
"revisionTime": "2017-01-13T00:03:17Z" "revisionTime": "2017-04-21T05:17:54Z"
}, },
{ {
"checksumSHA1": "lAMqZyc46cU5WaRuw4mVHFXpvps=", "checksumSHA1": "lAMqZyc46cU5WaRuw4mVHFXpvps=",

View File

@ -0,0 +1,52 @@
---
layout: "google"
page_title: "Google: google_compute_backend_bucket"
sidebar_current: "docs-google-compute-backend-bucket"
description: |-
Creates a Backend Bucket resource for Google Compute Engine.
---
# google\_compute\_backend\_bucket
A Backend Bucket defines a Google Cloud Storage bucket that will serve traffic through Google Cloud
Load Balancer.
## Example Usage
```hcl
resource "google_compute_backend_bucket" "foobar" {
name = "image-backend-bucket"
description = "Contains beautiful images"
bucket_name = "${google_storage_bucket.image_bucket.name}"
enable_cdn = true
}
resource "google_storage_bucket" "image_bucket" {
name = "image-store-bucket"
location = "EU"
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) The name of the backend bucket.
* `bucket_name` - (Required) The name of the Google Cloud Storage bucket to be used as a backend
bucket.
- - -
* `description` - (Optional) The textual description for the backend bucket.
* `enable_cdn` - (Optional) Whether or not to enable the Cloud CDN on the backend bucket.
* `project` - (Optional) The project in which the resource belongs. If it is not provided, the
provider project is used.
## Attributes Reference
In addition to the arguments listed above, the following computed attributes are exported:
* `self_link` - The URI of the created resource.

View File

@ -41,6 +41,11 @@ resource "google_compute_url_map" "foobar" {
paths = ["/login"] paths = ["/login"]
service = "${google_compute_backend_service.login.self_link}" service = "${google_compute_backend_service.login.self_link}"
} }
path_rule {
paths = ["/static"]
service = "${google_compute_backend_bucket.static.self_link}"
}
} }
test { test {
@ -55,7 +60,6 @@ resource "google_compute_backend_service" "login" {
port_name = "http" port_name = "http"
protocol = "HTTP" protocol = "HTTP"
timeout_sec = 10 timeout_sec = 10
region = "us-central1"
health_checks = ["${google_compute_http_health_check.default.self_link}"] health_checks = ["${google_compute_http_health_check.default.self_link}"]
} }
@ -65,7 +69,6 @@ resource "google_compute_backend_service" "home" {
port_name = "http" port_name = "http"
protocol = "HTTP" protocol = "HTTP"
timeout_sec = 10 timeout_sec = 10
region = "us-central1"
health_checks = ["${google_compute_http_health_check.default.self_link}"] health_checks = ["${google_compute_http_health_check.default.self_link}"]
} }
@ -76,14 +79,25 @@ resource "google_compute_http_health_check" "default" {
check_interval_sec = 1 check_interval_sec = 1
timeout_sec = 1 timeout_sec = 1
} }
resource "google_compute_backend_bucket" "static" {
name = "static-asset-backend-bucket"
bucket_name = "${google_storage_bucket.static.name}"
enable_cdn = true
}
resource "google_storage_bucket" "static" {
name = "static-asset-bucket"
location = "US"
}
``` ```
## Argument Reference ## Argument Reference
The following arguments are supported: The following arguments are supported:
* `default_service` - (Required) The URL of the backend service to use when none * `default_service` - (Required) The URL of the backend service or backend bucket to use when none
of the given rules match. See the documentation for formatting the service of the given rules match. See the documentation for formatting the service/bucket
URL URL
[here](https://cloud.google.com/compute/docs/reference/latest/urlMaps#defaultService) [here](https://cloud.google.com/compute/docs/reference/latest/urlMaps#defaultService)
@ -118,8 +132,8 @@ The `host_rule` block supports: (This block can be defined multiple times).
The `path_matcher` block supports: (This block can be defined multiple times) The `path_matcher` block supports: (This block can be defined multiple times)
* `default_service` - (Required) The URL for the backend service to use if none * `default_service` - (Required) The URL for the backend service or backend bucket to use if none
of the given paths match. See the documentation for formatting the service of the given paths match. See the documentation for formatting the service/bucket
URL [here](https://cloud.google.com/compute/docs/reference/latest/urlMaps#pathMatcher.defaultService) URL [here](https://cloud.google.com/compute/docs/reference/latest/urlMaps#pathMatcher.defaultService)
* `name` - (Required) The name of the `path_matcher` resource. Used by the * `name` - (Required) The name of the `path_matcher` resource. Used by the
@ -133,13 +147,13 @@ multiple times)
* `paths` - (Required) The list of paths to match against. See the * `paths` - (Required) The list of paths to match against. See the
documentation for formatting these [here](https://cloud.google.com/compute/docs/reference/latest/urlMaps#pathMatchers.pathRules.paths) documentation for formatting these [here](https://cloud.google.com/compute/docs/reference/latest/urlMaps#pathMatchers.pathRules.paths)
* `default_service` - (Required) The URL for the backend service to use if any * `service` - (Required) The URL for the backend service or backend bucket to use if any
of the given paths match. See the documentation for formatting the service of the given paths match. See the documentation for formatting the service/bucket
URL [here](https://cloud.google.com/compute/docs/reference/latest/urlMaps#pathMatcher.defaultService) URL [here](https://cloud.google.com/compute/docs/reference/latest/urlMaps#pathMatcher.defaultService)
The optional `test` block supports: (This block can be defined multiple times) The optional `test` block supports: (This block can be defined multiple times)
* `service` - (Required) The service that should be matched by this test. * `service` - (Required) The backend service or backend bucket that should be matched by this test.
* `host` - (Required) The host component of the URL being tested. * `host` - (Required) The host component of the URL being tested.