Multiple gcp improvements and new resources
This commit is contained in:
parent
6947ba2518
commit
6046647f38
|
@ -15,3 +15,5 @@ website/node_modules
|
||||||
*.tfstate
|
*.tfstate
|
||||||
*.log
|
*.log
|
||||||
*.bak
|
*.bak
|
||||||
|
*~
|
||||||
|
.*.swp
|
||||||
|
|
|
@ -29,12 +29,15 @@ func Provider() terraform.ResourceProvider {
|
||||||
},
|
},
|
||||||
|
|
||||||
ResourcesMap: map[string]*schema.Resource{
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
"google_compute_address": resourceComputeAddress(),
|
"google_compute_address": resourceComputeAddress(),
|
||||||
"google_compute_disk": resourceComputeDisk(),
|
"google_compute_disk": resourceComputeDisk(),
|
||||||
"google_compute_firewall": resourceComputeFirewall(),
|
"google_compute_firewall": resourceComputeFirewall(),
|
||||||
"google_compute_instance": resourceComputeInstance(),
|
"google_compute_forwarding_rule": resourceComputeForwardingRule(),
|
||||||
"google_compute_network": resourceComputeNetwork(),
|
"google_compute_http_health_check": resourceComputeHttpHealthCheck(),
|
||||||
"google_compute_route": resourceComputeRoute(),
|
"google_compute_instance": resourceComputeInstance(),
|
||||||
|
"google_compute_network": resourceComputeNetwork(),
|
||||||
|
"google_compute_route": resourceComputeRoute(),
|
||||||
|
"google_compute_target_pool": resourceComputeTargetPool(),
|
||||||
},
|
},
|
||||||
|
|
||||||
ConfigureFunc: providerConfigure,
|
ConfigureFunc: providerConfigure,
|
||||||
|
|
|
@ -27,6 +27,12 @@ func resourceComputeAddress() *schema.Resource {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"self_link": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +96,7 @@ func resourceComputeAddressRead(d *schema.ResourceData, meta interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Set("address", addr.Address)
|
d.Set("address", addr.Address)
|
||||||
|
d.Set("self_link", addr.SelfLink)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -98,6 +105,7 @@ func resourceComputeAddressDelete(d *schema.ResourceData, meta interface{}) erro
|
||||||
config := meta.(*Config)
|
config := meta.(*Config)
|
||||||
|
|
||||||
// Delete the address
|
// Delete the address
|
||||||
|
log.Printf("[DEBUG] address delete request")
|
||||||
op, err := config.clientCompute.Addresses.Delete(
|
op, err := config.clientCompute.Addresses.Delete(
|
||||||
config.Project, config.Region, d.Id()).Do()
|
config.Project, config.Region, d.Id()).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.google.com/p/google-api-go-client/compute/v1"
|
||||||
|
"code.google.com/p/google-api-go-client/googleapi"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceComputeForwardingRule() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceComputeForwardingRuleCreate,
|
||||||
|
Read: resourceComputeForwardingRuleRead,
|
||||||
|
Delete: resourceComputeForwardingRuleDelete,
|
||||||
|
Update: resourceComputeForwardingRuleUpdate,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"ip_address": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"ip_protocol": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"port_range": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"self_link": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"target": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeForwardingRuleCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
frule := &compute.ForwardingRule{
|
||||||
|
IPAddress: d.Get("ip_address").(string),
|
||||||
|
IPProtocol: d.Get("ip_protocol").(string),
|
||||||
|
Description: d.Get("description").(string),
|
||||||
|
Name: d.Get("name").(string),
|
||||||
|
PortRange: d.Get("port_range").(string),
|
||||||
|
Target: d.Get("target").(string),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] ForwardingRule insert request: %#v", frule)
|
||||||
|
op, err := config.clientCompute.ForwardingRules.Insert(
|
||||||
|
config.Project, config.Region, frule).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error creating ForwardingRule: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// It probably maybe worked, so store the ID now
|
||||||
|
d.SetId(frule.Name)
|
||||||
|
|
||||||
|
// Wait for the operation to complete
|
||||||
|
w := &OperationWaiter{
|
||||||
|
Service: config.clientCompute,
|
||||||
|
Op: op,
|
||||||
|
Region: config.Region,
|
||||||
|
Project: config.Project,
|
||||||
|
Type: OperationWaitRegion,
|
||||||
|
}
|
||||||
|
state := w.Conf()
|
||||||
|
state.Timeout = 2 * time.Minute
|
||||||
|
state.MinTimeout = 1 * time.Second
|
||||||
|
opRaw, err := state.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error waiting for ForwardingRule to create: %s", err)
|
||||||
|
}
|
||||||
|
op = opRaw.(*compute.Operation)
|
||||||
|
if op.Error != nil {
|
||||||
|
// The resource didn't actually create
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
// Return the error
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceComputeForwardingRuleRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeForwardingRuleUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
d.Partial(true)
|
||||||
|
|
||||||
|
if d.HasChange("target") {
|
||||||
|
target_name := d.Get("target").(string)
|
||||||
|
target_ref := &compute.TargetReference{Target: target_name}
|
||||||
|
op, err := config.clientCompute.ForwardingRules.SetTarget(
|
||||||
|
config.Project, config.Region, d.Id(), target_ref).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating target: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the operation to complete
|
||||||
|
w := &OperationWaiter{
|
||||||
|
Service: config.clientCompute,
|
||||||
|
Op: op,
|
||||||
|
Region: config.Region,
|
||||||
|
Project: config.Project,
|
||||||
|
Type: OperationWaitRegion,
|
||||||
|
}
|
||||||
|
state := w.Conf()
|
||||||
|
state.Timeout = 2 * time.Minute
|
||||||
|
state.MinTimeout = 1 * time.Second
|
||||||
|
opRaw, err := state.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error waiting for ForwardingRule to update target: %s", err)
|
||||||
|
}
|
||||||
|
op = opRaw.(*compute.Operation)
|
||||||
|
if op.Error != nil {
|
||||||
|
// The resource didn't actually create
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
// Return the error
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
d.SetPartial("target")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Partial(false)
|
||||||
|
|
||||||
|
return resourceComputeForwardingRuleRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeForwardingRuleRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
frule, err := config.clientCompute.ForwardingRules.Get(
|
||||||
|
config.Project, config.Region, d.Id()).Do()
|
||||||
|
if err != nil {
|
||||||
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||||
|
// The resource doesn't exist anymore
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Error reading ForwardingRule: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("ip_address", frule.IPAddress)
|
||||||
|
d.Set("ip_protocol", frule.IPProtocol)
|
||||||
|
d.Set("self_link", frule.SelfLink)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeForwardingRuleDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
// Delete the ForwardingRule
|
||||||
|
log.Printf("[DEBUG] ForwardingRule delete request")
|
||||||
|
op, err := config.clientCompute.ForwardingRules.Delete(
|
||||||
|
config.Project, config.Region, d.Id()).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting ForwardingRule: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the operation to complete
|
||||||
|
w := &OperationWaiter{
|
||||||
|
Service: config.clientCompute,
|
||||||
|
Op: op,
|
||||||
|
Region: config.Region,
|
||||||
|
Project: config.Project,
|
||||||
|
Type: OperationWaitRegion,
|
||||||
|
}
|
||||||
|
state := w.Conf()
|
||||||
|
state.Timeout = 2 * time.Minute
|
||||||
|
state.MinTimeout = 1 * time.Second
|
||||||
|
opRaw, err := state.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error waiting for ForwardingRule to delete: %s", err)
|
||||||
|
}
|
||||||
|
op = opRaw.(*compute.Operation)
|
||||||
|
if op.Error != nil {
|
||||||
|
// Return the error
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccComputeForwardingRule_basic(t *testing.T) {
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckComputeForwardingRuleDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccComputeForwardingRule_basic,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckComputeForwardingRuleExists(
|
||||||
|
"google_compute_forwarding_rule.foobar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccComputeForwardingRule_ip(t *testing.T) {
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckComputeForwardingRuleDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccComputeForwardingRule_ip,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckComputeForwardingRuleExists(
|
||||||
|
"google_compute_forwarding_rule.foobar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckComputeForwardingRuleDestroy(s *terraform.State) error {
|
||||||
|
config := testAccProvider.Meta().(*Config)
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "google_compute_forwarding_rule" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := config.clientCompute.ForwardingRules.Get(
|
||||||
|
config.Project, config.Region, rs.Primary.ID).Do()
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("ForwardingRule still exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckComputeForwardingRuleExists(n string) 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.ForwardingRules.Get(
|
||||||
|
config.Project, config.Region, rs.Primary.ID).Do()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if found.Name != rs.Primary.ID {
|
||||||
|
return fmt.Errorf("ForwardingRule not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccComputeForwardingRule_basic = `
|
||||||
|
resource "google_compute_target_pool" "foobar-tp" {
|
||||||
|
description = "Resource created for Terraform acceptance testing"
|
||||||
|
instances = ["us-central1-a/foo", "us-central1-b/bar"]
|
||||||
|
name = "terraform-test"
|
||||||
|
}
|
||||||
|
resource "google_compute_forwarding_rule" "foobar" {
|
||||||
|
description = "Resource created for Terraform acceptance testing"
|
||||||
|
ip_protocol = "UDP"
|
||||||
|
name = "terraform-test"
|
||||||
|
port_range = "80-81"
|
||||||
|
target = "${google_compute_target_pool.foobar-tp.self_link}"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const testAccComputeForwardingRule_ip = `
|
||||||
|
resource "google_compute_address" "foo" {
|
||||||
|
name = "foo"
|
||||||
|
}
|
||||||
|
resource "google_compute_target_pool" "foobar-tp" {
|
||||||
|
description = "Resource created for Terraform acceptance testing"
|
||||||
|
instances = ["us-central1-a/foo", "us-central1-b/bar"]
|
||||||
|
name = "terraform-test"
|
||||||
|
}
|
||||||
|
resource "google_compute_forwarding_rule" "foobar" {
|
||||||
|
description = "Resource created for Terraform acceptance testing"
|
||||||
|
ip_address = "${google_compute_address.foo.address}"
|
||||||
|
ip_protocol = "TCP"
|
||||||
|
name = "terraform-test"
|
||||||
|
port_range = "80-81"
|
||||||
|
target = "${google_compute_target_pool.foobar-tp.self_link}"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.google.com/p/google-api-go-client/compute/v1"
|
||||||
|
"code.google.com/p/google-api-go-client/googleapi"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceComputeHttpHealthCheck() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceComputeHttpHealthCheckCreate,
|
||||||
|
Read: resourceComputeHttpHealthCheckRead,
|
||||||
|
Delete: resourceComputeHttpHealthCheckDelete,
|
||||||
|
Update: resourceComputeHttpHealthCheckUpdate,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"check_interval_sec": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"healthy_threshold": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"host": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"port": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"request_path": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"self_link": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"timeout_sec": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"unhealthy_threshold": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeHttpHealthCheckCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
// Build the parameter
|
||||||
|
hchk := &compute.HttpHealthCheck{
|
||||||
|
Description: d.Get("description").(string),
|
||||||
|
Host: d.Get("host").(string),
|
||||||
|
Name: d.Get("name").(string),
|
||||||
|
RequestPath: d.Get("request_path").(string),
|
||||||
|
}
|
||||||
|
if d.Get("check_interval_sec") != nil {
|
||||||
|
hchk.CheckIntervalSec = int64(d.Get("check_interval_sec").(int))
|
||||||
|
}
|
||||||
|
if d.Get("health_threshold") != nil {
|
||||||
|
hchk.HealthyThreshold = int64(d.Get("healthy_threshold").(int))
|
||||||
|
}
|
||||||
|
if d.Get("port") != nil {
|
||||||
|
hchk.Port = int64(d.Get("port").(int))
|
||||||
|
}
|
||||||
|
if d.Get("timeout") != nil {
|
||||||
|
hchk.TimeoutSec = int64(d.Get("timeout_sec").(int))
|
||||||
|
}
|
||||||
|
if d.Get("unhealthy_threshold") != nil {
|
||||||
|
hchk.UnhealthyThreshold = int64(d.Get("unhealthy_threshold").(int))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] HttpHealthCheck insert request: %#v", hchk)
|
||||||
|
op, err := config.clientCompute.HttpHealthChecks.Insert(
|
||||||
|
config.Project, hchk).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error creating HttpHealthCheck: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// It probably maybe worked, so store the ID now
|
||||||
|
d.SetId(hchk.Name)
|
||||||
|
|
||||||
|
// Wait for the operation to complete
|
||||||
|
w := &OperationWaiter{
|
||||||
|
Service: config.clientCompute,
|
||||||
|
Op: op,
|
||||||
|
Project: config.Project,
|
||||||
|
Type: OperationWaitGlobal,
|
||||||
|
}
|
||||||
|
state := w.Conf()
|
||||||
|
state.Timeout = 2 * time.Minute
|
||||||
|
state.MinTimeout = 1 * time.Second
|
||||||
|
opRaw, err := state.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error waiting for HttpHealthCheck to create: %s", err)
|
||||||
|
}
|
||||||
|
op = opRaw.(*compute.Operation)
|
||||||
|
if op.Error != nil {
|
||||||
|
// The resource didn't actually create
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
// Return the error
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceComputeHttpHealthCheckRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeHttpHealthCheckUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
// Build the parameter
|
||||||
|
hchk := &compute.HttpHealthCheck{
|
||||||
|
Description: d.Get("description").(string),
|
||||||
|
Host: d.Get("host").(string),
|
||||||
|
Name: d.Get("name").(string),
|
||||||
|
RequestPath: d.Get("request_path").(string),
|
||||||
|
}
|
||||||
|
if d.Get("check_interval_sec") != nil {
|
||||||
|
hchk.CheckIntervalSec = int64(d.Get("check_interval_sec").(int))
|
||||||
|
}
|
||||||
|
if d.Get("health_threshold") != nil {
|
||||||
|
hchk.HealthyThreshold = int64(d.Get("healthy_threshold").(int))
|
||||||
|
}
|
||||||
|
if d.Get("port") != nil {
|
||||||
|
hchk.Port = int64(d.Get("port").(int))
|
||||||
|
}
|
||||||
|
if d.Get("timeout") != nil {
|
||||||
|
hchk.TimeoutSec = int64(d.Get("timeout_sec").(int))
|
||||||
|
}
|
||||||
|
if d.Get("unhealthy_threshold") != nil {
|
||||||
|
hchk.UnhealthyThreshold = int64(d.Get("unhealthy_threshold").(int))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] HttpHealthCheck patch request: %#v", hchk)
|
||||||
|
op, err := config.clientCompute.HttpHealthChecks.Patch(
|
||||||
|
config.Project, hchk.Name, hchk).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error patching HttpHealthCheck: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// It probably maybe worked, so store the ID now
|
||||||
|
d.SetId(hchk.Name)
|
||||||
|
|
||||||
|
// Wait for the operation to complete
|
||||||
|
w := &OperationWaiter{
|
||||||
|
Service: config.clientCompute,
|
||||||
|
Op: op,
|
||||||
|
Project: config.Project,
|
||||||
|
Type: OperationWaitGlobal,
|
||||||
|
}
|
||||||
|
state := w.Conf()
|
||||||
|
state.Timeout = 2 * time.Minute
|
||||||
|
state.MinTimeout = 1 * time.Second
|
||||||
|
opRaw, err := state.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error waiting for HttpHealthCheck to patch: %s", err)
|
||||||
|
}
|
||||||
|
op = opRaw.(*compute.Operation)
|
||||||
|
if op.Error != nil {
|
||||||
|
// The resource didn't actually create
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
// Return the error
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceComputeHttpHealthCheckRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeHttpHealthCheckRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
hchk, err := config.clientCompute.HttpHealthChecks.Get(
|
||||||
|
config.Project, d.Id()).Do()
|
||||||
|
if err != nil {
|
||||||
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||||
|
// The resource doesn't exist anymore
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Error reading HttpHealthCheck: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("self_link", hchk.SelfLink)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeHttpHealthCheckDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
// Delete the HttpHealthCheck
|
||||||
|
op, err := config.clientCompute.HttpHealthChecks.Delete(
|
||||||
|
config.Project, d.Id()).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting HttpHealthCheck: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the operation to complete
|
||||||
|
w := &OperationWaiter{
|
||||||
|
Service: config.clientCompute,
|
||||||
|
Op: op,
|
||||||
|
Project: config.Project,
|
||||||
|
Type: OperationWaitGlobal,
|
||||||
|
}
|
||||||
|
state := w.Conf()
|
||||||
|
state.Timeout = 2 * time.Minute
|
||||||
|
state.MinTimeout = 1 * time.Second
|
||||||
|
opRaw, err := state.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error waiting for HttpHealthCheck to delete: %s", err)
|
||||||
|
}
|
||||||
|
op = opRaw.(*compute.Operation)
|
||||||
|
if op.Error != nil {
|
||||||
|
// Return the error
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccComputeHttpHealthCheck_basic(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckComputeHttpHealthCheckDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccComputeHttpHealthCheck_basic,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckComputeHttpHealthCheckExists(
|
||||||
|
"google_compute_http_health_check.foobar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckComputeHttpHealthCheckDestroy(s *terraform.State) error {
|
||||||
|
config := testAccProvider.Meta().(*Config)
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "google_compute_http_health_check" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := config.clientCompute.HttpHealthChecks.Get(
|
||||||
|
config.Project, rs.Primary.ID).Do()
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("HttpHealthCheck still exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckComputeHttpHealthCheckExists(n string) 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.HttpHealthChecks.Get(
|
||||||
|
config.Project, rs.Primary.ID).Do()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if found.Name != rs.Primary.ID {
|
||||||
|
return fmt.Errorf("HttpHealthCheck not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccComputeHttpHealthCheck_basic = `
|
||||||
|
resource "google_compute_http_health_check" "foobar" {
|
||||||
|
check_interval_sec = 1
|
||||||
|
description = "Resource created for Terraform acceptance testing"
|
||||||
|
healthy_threshold = 3
|
||||||
|
host = "foobar"
|
||||||
|
name = "terraform-test"
|
||||||
|
port = "80"
|
||||||
|
request_path = "/health_check"
|
||||||
|
timeout_sec = 2
|
||||||
|
unhealthy_threshold = 3
|
||||||
|
}
|
||||||
|
`
|
|
@ -109,6 +109,30 @@ func resourceComputeInstance() *schema.Resource {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"service_accounts": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"email": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"scopes": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
"can_ip_forward": &schema.Schema{
|
"can_ip_forward": &schema.Schema{
|
||||||
Type: schema.TypeBool,
|
Type: schema.TypeBool,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
|
|
@ -0,0 +1,404 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.google.com/p/google-api-go-client/compute/v1"
|
||||||
|
"code.google.com/p/google-api-go-client/googleapi"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceComputeTargetPool() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceComputeTargetPoolCreate,
|
||||||
|
Read: resourceComputeTargetPoolRead,
|
||||||
|
Delete: resourceComputeTargetPoolDelete,
|
||||||
|
Update: resourceComputeTargetPoolUpdate,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"backup_pool": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"failover_ratio": &schema.Schema{
|
||||||
|
Type: schema.TypeFloat,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"health_checks": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
},
|
||||||
|
|
||||||
|
"instances": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
},
|
||||||
|
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"self_link": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"session_affinity": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertStringArr(ifaceArr []interface{}) []string {
|
||||||
|
arr := make([]string, len(ifaceArr))
|
||||||
|
for i, v := range ifaceArr {
|
||||||
|
arr[i] = v.(string)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitOp(config *Config, op *compute.Operation,
|
||||||
|
resource string, action string) (*compute.Operation, error) {
|
||||||
|
|
||||||
|
w := &OperationWaiter{
|
||||||
|
Service: config.clientCompute,
|
||||||
|
Op: op,
|
||||||
|
Region: config.Region,
|
||||||
|
Project: config.Project,
|
||||||
|
Type: OperationWaitRegion,
|
||||||
|
}
|
||||||
|
state := w.Conf()
|
||||||
|
state.Timeout = 2 * time.Minute
|
||||||
|
state.MinTimeout = 1 * time.Second
|
||||||
|
opRaw, err := state.WaitForState()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error waiting for %s to %s: %s", resource, action, err)
|
||||||
|
}
|
||||||
|
return opRaw.(*compute.Operation), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Healthchecks need to exist before being referred to from the target pool.
|
||||||
|
func convertHealthChecks(config *Config, names []string) ([]string, error) {
|
||||||
|
urls := make([]string, len(names))
|
||||||
|
for i, name := range names {
|
||||||
|
// Look up the healthcheck
|
||||||
|
res, err := config.clientCompute.HttpHealthChecks.Get(config.Project, name).Do()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error reading HealthCheck: %s", err)
|
||||||
|
}
|
||||||
|
urls[i] = res.SelfLink
|
||||||
|
}
|
||||||
|
return urls, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instances do not need to exist yet, so we simply generate URLs.
|
||||||
|
// Instances can be full URLS or zone/name
|
||||||
|
func convertInstances(config *Config, names []string) ([]string, error) {
|
||||||
|
urls := make([]string, len(names))
|
||||||
|
for i, name := range names {
|
||||||
|
if strings.HasPrefix(name, "https://www.googleapis.com/compute/v1/") {
|
||||||
|
urls[i] = name
|
||||||
|
} else {
|
||||||
|
splitName := strings.Split(name, "/")
|
||||||
|
if len(splitName) != 2 {
|
||||||
|
return nil, fmt.Errorf("Invalid instance name, require URL or zone/name: %s", name)
|
||||||
|
} else {
|
||||||
|
urls[i] = fmt.Sprintf(
|
||||||
|
"https://www.googleapis.com/compute/v1/projects/%s/zones/%s/instances/%s",
|
||||||
|
config.Project, splitName[0], splitName[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return urls, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeTargetPoolCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
hchkUrls, err := convertHealthChecks(
|
||||||
|
config, convertStringArr(d.Get("health_checks").([]interface{})))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceUrls, err := convertInstances(
|
||||||
|
config, convertStringArr(d.Get("instances").([]interface{})))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the parameter
|
||||||
|
tpool := &compute.TargetPool{
|
||||||
|
BackupPool: d.Get("backup_pool").(string),
|
||||||
|
Description: d.Get("description").(string),
|
||||||
|
HealthChecks: hchkUrls,
|
||||||
|
Instances: instanceUrls,
|
||||||
|
Name: d.Get("name").(string),
|
||||||
|
SessionAffinity: d.Get("session_affinity").(string),
|
||||||
|
}
|
||||||
|
if d.Get("failover_ratio") != nil {
|
||||||
|
tpool.FailoverRatio = d.Get("failover_ratio").(float64)
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] TargetPool insert request: %#v", tpool)
|
||||||
|
op, err := config.clientCompute.TargetPools.Insert(
|
||||||
|
config.Project, config.Region, tpool).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error creating TargetPool: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// It probably maybe worked, so store the ID now
|
||||||
|
d.SetId(tpool.Name)
|
||||||
|
|
||||||
|
op, err = waitOp(config, op, "TargetPool", "create")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if op.Error != nil {
|
||||||
|
// The resource didn't actually create
|
||||||
|
d.SetId("")
|
||||||
|
// Return the error
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceComputeTargetPoolRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcAddRemove(from []string, to []string) ([]string, []string) {
|
||||||
|
add := make([]string, 0)
|
||||||
|
remove := make([]string, 0)
|
||||||
|
for _, u := range to {
|
||||||
|
found := false
|
||||||
|
for _, v := range from {
|
||||||
|
if u == v {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
add = append(add, u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, u := range from {
|
||||||
|
found := false
|
||||||
|
for _, v := range to {
|
||||||
|
if u == v {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
remove = append(remove, u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return add, remove
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func resourceComputeTargetPoolUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
d.Partial(true)
|
||||||
|
|
||||||
|
if d.HasChange("health_checks") {
|
||||||
|
|
||||||
|
from_, to_ := d.GetChange("health_checks")
|
||||||
|
from := convertStringArr(from_.([]interface{}))
|
||||||
|
to := convertStringArr(to_.([]interface{}))
|
||||||
|
fromUrls, err := convertHealthChecks(config, from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
toUrls, err := convertHealthChecks(config, to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
add, remove := calcAddRemove(fromUrls, toUrls)
|
||||||
|
|
||||||
|
removeReq := &compute.TargetPoolsRemoveHealthCheckRequest{
|
||||||
|
HealthChecks: make([]*compute.HealthCheckReference, len(remove)),
|
||||||
|
}
|
||||||
|
for i, v := range remove {
|
||||||
|
removeReq.HealthChecks[i] = &compute.HealthCheckReference{HealthCheck: v}
|
||||||
|
}
|
||||||
|
op, err := config.clientCompute.TargetPools.RemoveHealthCheck(
|
||||||
|
config.Project, config.Region, d.Id(), removeReq).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating health_check: %s", err)
|
||||||
|
}
|
||||||
|
op, err = waitOp(config, op, "TargetPool", "removing HealthChecks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if op.Error != nil {
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
addReq := &compute.TargetPoolsAddHealthCheckRequest{
|
||||||
|
HealthChecks: make([]*compute.HealthCheckReference, len(add)),
|
||||||
|
}
|
||||||
|
for i, v := range add {
|
||||||
|
addReq.HealthChecks[i] = &compute.HealthCheckReference{HealthCheck: v}
|
||||||
|
}
|
||||||
|
op, err = config.clientCompute.TargetPools.AddHealthCheck(
|
||||||
|
config.Project, config.Region, d.Id(), addReq).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating health_check: %s", err)
|
||||||
|
}
|
||||||
|
op, err = waitOp(config, op, "TargetPool", "adding HealthChecks")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if op.Error != nil {
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetPartial("health_checks")
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("instances") {
|
||||||
|
|
||||||
|
from_, to_ := d.GetChange("instances")
|
||||||
|
from := convertStringArr(from_.([]interface{}))
|
||||||
|
to := convertStringArr(to_.([]interface{}))
|
||||||
|
fromUrls, err := convertInstances(config, from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
toUrls, err := convertInstances(config, to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
add, remove := calcAddRemove(fromUrls, toUrls)
|
||||||
|
|
||||||
|
addReq := &compute.TargetPoolsAddInstanceRequest{
|
||||||
|
Instances: make([]*compute.InstanceReference, len(add)),
|
||||||
|
}
|
||||||
|
for i, v := range add {
|
||||||
|
addReq.Instances[i] = &compute.InstanceReference{Instance: v}
|
||||||
|
}
|
||||||
|
op, err := config.clientCompute.TargetPools.AddInstance(
|
||||||
|
config.Project, config.Region, d.Id(), addReq).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating instances: %s", err)
|
||||||
|
}
|
||||||
|
op, err = waitOp(config, op, "TargetPool", "adding instances")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if op.Error != nil {
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
removeReq := &compute.TargetPoolsRemoveInstanceRequest{
|
||||||
|
Instances: make([]*compute.InstanceReference, len(remove)),
|
||||||
|
}
|
||||||
|
for i, v := range remove {
|
||||||
|
removeReq.Instances[i] = &compute.InstanceReference{Instance: v}
|
||||||
|
}
|
||||||
|
op, err = config.clientCompute.TargetPools.RemoveInstance(
|
||||||
|
config.Project, config.Region, d.Id(), removeReq).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating instances: %s", err)
|
||||||
|
}
|
||||||
|
op, err = waitOp(config, op, "TargetPool", "removing instances")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if op.Error != nil {
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetPartial("instances")
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("backup_pool") {
|
||||||
|
bpool_name := d.Get("backup_pool").(string)
|
||||||
|
tref := &compute.TargetReference{
|
||||||
|
Target: bpool_name,
|
||||||
|
}
|
||||||
|
op, err := config.clientCompute.TargetPools.SetBackup(
|
||||||
|
config.Project, config.Region, d.Id(), tref).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error updating backup_pool: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
op, err = waitOp(config, op, "TargetPool", "updating backup_pool")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if op.Error != nil {
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetPartial("backup_pool")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Partial(false)
|
||||||
|
|
||||||
|
return resourceComputeTargetPoolRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeTargetPoolRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
tpool, err := config.clientCompute.TargetPools.Get(
|
||||||
|
config.Project, config.Region, d.Id()).Do()
|
||||||
|
if err != nil {
|
||||||
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||||
|
// The resource doesn't exist anymore
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("Error reading TargetPool: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("self_link", tpool.SelfLink)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceComputeTargetPoolDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
// Delete the TargetPool
|
||||||
|
op, err := config.clientCompute.TargetPools.Delete(
|
||||||
|
config.Project, config.Region, d.Id()).Do()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting TargetPool: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
op, err = waitOp(config, op, "TargetPool", "delete")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if op.Error != nil {
|
||||||
|
return OperationError(*op.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccComputeTargetPool_basic(t *testing.T) {
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckComputeTargetPoolDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccComputeTargetPool_basic,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckComputeTargetPoolExists(
|
||||||
|
"google_compute_target_pool.foobar"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckComputeTargetPoolDestroy(s *terraform.State) error {
|
||||||
|
config := testAccProvider.Meta().(*Config)
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "google_compute_target_pool" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := config.clientCompute.TargetPools.Get(
|
||||||
|
config.Project, config.Region, rs.Primary.ID).Do()
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("TargetPool still exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckComputeTargetPoolExists(n string) 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.TargetPools.Get(
|
||||||
|
config.Project, config.Region, rs.Primary.ID).Do()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if found.Name != rs.Primary.ID {
|
||||||
|
return fmt.Errorf("TargetPool not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccComputeTargetPool_basic = `
|
||||||
|
resource "google_compute_target_pool" "foobar" {
|
||||||
|
description = "Resource created for Terraform acceptance testing"
|
||||||
|
instances = ["us-central1-a/foo", "us-central1-b/bar"]
|
||||||
|
name = "terraform-test"
|
||||||
|
session_affinity = "CLIENT_IP_PROTO"
|
||||||
|
}`
|
|
@ -8,7 +8,10 @@ description: |-
|
||||||
|
|
||||||
# google\_compute\_address
|
# google\_compute\_address
|
||||||
|
|
||||||
Creates a static IP address resource for Google Compute Engine.
|
Creates a static IP address resource for Google Compute Engine. For more information see
|
||||||
|
[the official documentation](https://cloud.google.com/compute/docs/instances-and-network) and
|
||||||
|
[API](https://cloud.google.com/compute/docs/reference/latest/addresses).
|
||||||
|
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
|
@ -31,3 +34,4 @@ The following attributes are exported:
|
||||||
|
|
||||||
* `name` - The name of the resource.
|
* `name` - The name of the resource.
|
||||||
* `address` - The IP address that was allocated.
|
* `address` - The IP address that was allocated.
|
||||||
|
* `self_link` - The URI of the created resource.
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
layout: "google"
|
||||||
|
page_title: "Google: google_compute_forwarding_rule"
|
||||||
|
sidebar_current: "docs-google-resource-forwarding_rule"
|
||||||
|
description: |-
|
||||||
|
Manages a Target Pool within GCE.
|
||||||
|
---
|
||||||
|
|
||||||
|
# google\_compute\_forwarding\_rule
|
||||||
|
|
||||||
|
Manages a Forwarding Rule within GCE. This binds an ip and port range to a target pool. For more
|
||||||
|
information see [the official
|
||||||
|
documentation](https://cloud.google.com/compute/docs/load-balancing/network/forwarding-rules) and
|
||||||
|
[API](https://cloud.google.com/compute/docs/reference/latest/forwardingRules).
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "google_compute_forwarding_rule" "default" {
|
||||||
|
name = "test"
|
||||||
|
target = "${google_compute_target_pool.default.self_link}"
|
||||||
|
port_range = "80"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `description` - (Optional) Textual description field.
|
||||||
|
|
||||||
|
* `ip_address` - (Optional) The static IP. (if not set, an ephemeral IP is
|
||||||
|
used).
|
||||||
|
|
||||||
|
* `ip_protocol` - (Optional) The IP protocol to route, one of "TCP" "UDP" "AH" "ESP" or "SCTP". (default "TCP").
|
||||||
|
|
||||||
|
* `name` - (Required) A unique name for the resource, required by GCE. Changing
|
||||||
|
this forces a new resource to be created.
|
||||||
|
|
||||||
|
* `port_range` - (Optional) A range e.g. "1024-2048" or a single port "1024"
|
||||||
|
(defaults to all ports!).
|
||||||
|
|
||||||
|
* `target` - URL of target pool.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `self_link` - The URL of the created resource.
|
||||||
|
|
||||||
|
* `ip_address` - The IP address that was chosen (or specified).
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
layout: "google"
|
||||||
|
page_title: "Google: google_compute_http_health_check"
|
||||||
|
sidebar_current: "docs-google-resource-http_health_check"
|
||||||
|
description: |-
|
||||||
|
Manages an HTTP Health Check within GCE.
|
||||||
|
---
|
||||||
|
|
||||||
|
# google\_compute\_http\_health\_check
|
||||||
|
|
||||||
|
Manages an HTTP health check within GCE. This is used to monitor instances
|
||||||
|
behind load balancers. Timeouts or HTTP errors cause the instance to be
|
||||||
|
removed from the pool. For more information, see [the official
|
||||||
|
documentation](https://cloud.google.com/compute/docs/load-balancing/health-checks)
|
||||||
|
and
|
||||||
|
[API](https://cloud.google.com/compute/docs/reference/latest/httpHealthChecks).
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "google_compute_http_health_check" "default" {
|
||||||
|
name = "test"
|
||||||
|
request_path = "/health_check"
|
||||||
|
check_interval_sec = 1
|
||||||
|
timeout_sec = 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `check_interval_sec` - (Optional) How often to poll each instance (default 5).
|
||||||
|
|
||||||
|
* `description` - (Optional) Textual description field.
|
||||||
|
|
||||||
|
* `healthy_threshold` - (Optional) Consecutive successes required (default 2).
|
||||||
|
|
||||||
|
* `host` - (Optional) HTTP host header field (default instance's public ip).
|
||||||
|
|
||||||
|
* `name` - (Required) A unique name for the resource, required by GCE.
|
||||||
|
Changing this forces a new resource to be created.
|
||||||
|
|
||||||
|
* `port` - (Optional) TCP port to connect to (default 80).
|
||||||
|
|
||||||
|
* `request_path` - (Optional) URL path to query (default /).
|
||||||
|
|
||||||
|
* `timeout_sec` - (Optional) How long before declaring failure (default 5).
|
||||||
|
|
||||||
|
* `unhealthy_threshold` - (Optional) Consecutive failures required (default 2).
|
||||||
|
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `self_link` - The URL of the created resource.
|
|
@ -8,7 +8,11 @@ description: |-
|
||||||
|
|
||||||
# google\_compute\_instance
|
# google\_compute\_instance
|
||||||
|
|
||||||
Manages a VM instance resource within GCE.
|
Manages a VM instance resource within GCE. For more information see
|
||||||
|
[the official documentation](https://cloud.google.com/compute/docs/instances)
|
||||||
|
and
|
||||||
|
[API](https://cloud.google.com/compute/docs/reference/latest/instances).
|
||||||
|
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
---
|
||||||
|
layout: "google"
|
||||||
|
page_title: "Google: google_compute_target_pool"
|
||||||
|
sidebar_current: "docs-google-resource-target_pool"
|
||||||
|
description: |-
|
||||||
|
Manages a Target Pool within GCE.
|
||||||
|
---
|
||||||
|
|
||||||
|
# google\_compute\_target\_pool
|
||||||
|
|
||||||
|
Manages a Target Pool within GCE. This is a collection of instances used as
|
||||||
|
target of a network load balancer (Forwarding Rule). For more information see
|
||||||
|
[the official
|
||||||
|
documentation](https://cloud.google.com/compute/docs/load-balancing/network/target-pools)
|
||||||
|
and [API](https://cloud.google.com/compute/docs/reference/latest/targetPools).
|
||||||
|
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "google_compute_target_pool" "default" {
|
||||||
|
name = "test"
|
||||||
|
instances = [ "us-central1-a/myinstance1", "us-central1-b/myinstance2" ]
|
||||||
|
health_checks = [ "${google_compute_http_health_check.default.name}" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `backup_pool` - (Optional) URL to the backup target pool. Must also set
|
||||||
|
failover\_ratio.
|
||||||
|
|
||||||
|
* `description` - (Optional) Textual description field.
|
||||||
|
|
||||||
|
* `failover_ratio` - (Optional) Ratio (0 to 1) of failed nodes before using the
|
||||||
|
backup pool (which must also be set).
|
||||||
|
|
||||||
|
* `health_checks` - (Optional) List of zero or one healthcheck names.
|
||||||
|
|
||||||
|
* `instances` - (Optional) List of instances in the pool. They can be given as
|
||||||
|
URLs, or in the form of "zone/name". Note that the instances need not exist
|
||||||
|
at the time of target pool creation, so there is no need to use the Terraform
|
||||||
|
interpolators to create a dependency on the instances from the target pool.
|
||||||
|
|
||||||
|
* `name` - (Required) A unique name for the resource, required by GCE. Changing
|
||||||
|
this forces a new resource to be created.
|
||||||
|
|
||||||
|
* `session_affinity` - (Optional) How to distribute load. Options are "NONE" (no affinity). "CLIENT\_IP" (hash of the source/dest addresses / ports), and "CLIENT\_IP\_PROTO" also includes the protocol (default "NONE").
|
||||||
|
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `self_link` - The URL of the created resource.
|
||||||
|
|
Loading…
Reference in New Issue