Merge pull request #2868 from sparkprime/gce_autoscaling
Gce autoscaling
This commit is contained in:
commit
4fa68716c2
|
@ -8,6 +8,7 @@ import (
|
|||
"os"
|
||||
"runtime"
|
||||
|
||||
|
||||
// TODO(dcunnin): Use version code from version.go
|
||||
// "github.com/hashicorp/terraform"
|
||||
"golang.org/x/oauth2"
|
||||
|
@ -26,10 +27,10 @@ type Config struct {
|
|||
Project string
|
||||
Region string
|
||||
|
||||
clientCompute *compute.Service
|
||||
clientCompute *compute.Service
|
||||
clientContainer *container.Service
|
||||
clientDns *dns.Service
|
||||
clientStorage *storage.Service
|
||||
clientDns *dns.Service
|
||||
clientStorage *storage.Service
|
||||
}
|
||||
|
||||
func (c *Config) loadAndValidate() error {
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"google.golang.org/api/compute/v1"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
|
@ -25,8 +24,8 @@ type OperationWaiter struct {
|
|||
Op *compute.Operation
|
||||
Project string
|
||||
Region string
|
||||
Zone string
|
||||
Type OperationWaitType
|
||||
Zone string
|
||||
}
|
||||
|
||||
func (w *OperationWaiter) RefreshFunc() resource.StateRefreshFunc {
|
||||
|
@ -78,3 +77,4 @@ func (e OperationError) Error() string {
|
|||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
|
|
|
@ -29,20 +29,22 @@ func Provider() terraform.ResourceProvider {
|
|||
},
|
||||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"google_compute_address": resourceComputeAddress(),
|
||||
"google_compute_disk": resourceComputeDisk(),
|
||||
"google_compute_firewall": resourceComputeFirewall(),
|
||||
"google_compute_forwarding_rule": resourceComputeForwardingRule(),
|
||||
"google_compute_autoscaler": resourceComputeAutoscaler(),
|
||||
"google_compute_address": resourceComputeAddress(),
|
||||
"google_compute_disk": resourceComputeDisk(),
|
||||
"google_compute_firewall": resourceComputeFirewall(),
|
||||
"google_compute_forwarding_rule": resourceComputeForwardingRule(),
|
||||
"google_compute_http_health_check": resourceComputeHttpHealthCheck(),
|
||||
"google_compute_instance": resourceComputeInstance(),
|
||||
"google_compute_instance": resourceComputeInstance(),
|
||||
"google_compute_instance_template": resourceComputeInstanceTemplate(),
|
||||
"google_compute_network": resourceComputeNetwork(),
|
||||
"google_compute_route": resourceComputeRoute(),
|
||||
"google_compute_target_pool": resourceComputeTargetPool(),
|
||||
"google_container_cluster": resourceContainerCluster(),
|
||||
"google_dns_managed_zone": resourceDnsManagedZone(),
|
||||
"google_dns_record_set": resourceDnsRecordSet(),
|
||||
"google_storage_bucket": resourceStorageBucket(),
|
||||
"google_compute_network": resourceComputeNetwork(),
|
||||
"google_compute_route": resourceComputeRoute(),
|
||||
"google_compute_target_pool": resourceComputeTargetPool(),
|
||||
"google_container_cluster": resourceContainerCluster(),
|
||||
"google_dns_managed_zone": resourceDnsManagedZone(),
|
||||
"google_dns_record_set": resourceDnsRecordSet(),
|
||||
"google_compute_instance_group_manager": resourceComputeInstanceGroupManager(),
|
||||
"google_storage_bucket": resourceStorageBucket(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceComputeAutoscaler() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeAutoscalerCreate,
|
||||
Read: resourceComputeAutoscalerRead,
|
||||
Update: resourceComputeAutoscalerUpdate,
|
||||
Delete: resourceComputeAutoscalerDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
ForceNew: true,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"target": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"autoscaling_policy": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"min_replicas": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"max_replicas": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"cooldown_period": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 60,
|
||||
},
|
||||
|
||||
"cpu_utilization": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"target": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"metric": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"target": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"load_balancing_utilization": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"target": &schema.Schema{
|
||||
Type: schema.TypeFloat,
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"zone": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func buildAutoscaler(d *schema.ResourceData) (*compute.Autoscaler, error) {
|
||||
|
||||
// Build the parameter
|
||||
scaler := &compute.Autoscaler{
|
||||
Name: d.Get("name").(string),
|
||||
Target: d.Get("target").(string),
|
||||
}
|
||||
|
||||
// Optional fields
|
||||
if v, ok := d.GetOk("description"); ok {
|
||||
scaler.Description = v.(string)
|
||||
}
|
||||
|
||||
aspCount := d.Get("autoscaling_policy.#").(int)
|
||||
if aspCount != 1 {
|
||||
return nil, fmt.Errorf("The autoscaler must have exactly one autoscaling_policy, found %d.", aspCount)
|
||||
}
|
||||
|
||||
prefix := "autoscaling_policy.0."
|
||||
|
||||
scaler.AutoscalingPolicy = &compute.AutoscalingPolicy{
|
||||
MaxNumReplicas: int64(d.Get(prefix + "max_replicas").(int)),
|
||||
MinNumReplicas: int64(d.Get(prefix + "min_replicas").(int)),
|
||||
CoolDownPeriodSec: int64(d.Get(prefix + "cooldown_period").(int)),
|
||||
}
|
||||
|
||||
// Check that only one autoscaling policy is defined
|
||||
|
||||
policyCounter := 0
|
||||
if _, ok := d.GetOk(prefix + "cpu_utilization"); ok {
|
||||
if d.Get(prefix+"cpu_utilization.0.target").(float64) != 0 {
|
||||
cpuUtilCount := d.Get(prefix + "cpu_utilization.#").(int)
|
||||
if cpuUtilCount != 1 {
|
||||
return nil, fmt.Errorf("The autoscaling_policy must have exactly one cpu_utilization, found %d.", cpuUtilCount)
|
||||
}
|
||||
policyCounter++
|
||||
scaler.AutoscalingPolicy.CpuUtilization = &compute.AutoscalingPolicyCpuUtilization{
|
||||
UtilizationTarget: d.Get(prefix + "cpu_utilization.0.target").(float64),
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, ok := d.GetOk("autoscaling_policy.0.metric"); ok {
|
||||
if d.Get(prefix+"metric.0.name") != "" {
|
||||
policyCounter++
|
||||
metricCount := d.Get(prefix + "metric.#").(int)
|
||||
if metricCount != 1 {
|
||||
return nil, fmt.Errorf("The autoscaling_policy must have exactly one metric, found %d.", metricCount)
|
||||
}
|
||||
scaler.AutoscalingPolicy.CustomMetricUtilizations = []*compute.AutoscalingPolicyCustomMetricUtilization{
|
||||
{
|
||||
Metric: d.Get(prefix + "metric.0.name").(string),
|
||||
UtilizationTarget: d.Get(prefix + "metric.0.target").(float64),
|
||||
UtilizationTargetType: d.Get(prefix + "metric.0.type").(string),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if _, ok := d.GetOk("autoscaling_policy.0.load_balancing_utilization"); ok {
|
||||
if d.Get(prefix+"load_balancing_utilization.0.target").(float64) != 0 {
|
||||
policyCounter++
|
||||
lbuCount := d.Get(prefix + "load_balancing_utilization.#").(int)
|
||||
if lbuCount != 1 {
|
||||
return nil, fmt.Errorf("The autoscaling_policy must have exactly one load_balancing_utilization, found %d.", lbuCount)
|
||||
}
|
||||
scaler.AutoscalingPolicy.LoadBalancingUtilization = &compute.AutoscalingPolicyLoadBalancingUtilization{
|
||||
UtilizationTarget: d.Get(prefix + "load_balancing_utilization.0.target").(float64),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if policyCounter != 1 {
|
||||
return nil, fmt.Errorf("One policy must be defined for an autoscaler.")
|
||||
}
|
||||
|
||||
return scaler, nil
|
||||
}
|
||||
|
||||
func resourceComputeAutoscalerCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
// Get the zone
|
||||
log.Printf("[DEBUG] Loading zone: %s", d.Get("zone").(string))
|
||||
zone, err := config.clientCompute.Zones.Get(
|
||||
config.Project, d.Get("zone").(string)).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error loading zone '%s': %s", d.Get("zone").(string), err)
|
||||
}
|
||||
|
||||
scaler, err := buildAutoscaler(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err := config.clientCompute.Autoscalers.Insert(
|
||||
config.Project, zone.Name, scaler).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating Autoscaler: %s", err)
|
||||
}
|
||||
|
||||
// It probably maybe worked, so store the ID now
|
||||
d.SetId(scaler.Name)
|
||||
|
||||
// Wait for the operation to complete
|
||||
w := &OperationWaiter{
|
||||
Service: config.clientCompute,
|
||||
Op: op,
|
||||
Project: config.Project,
|
||||
Type: OperationWaitZone,
|
||||
Zone: zone.Name,
|
||||
}
|
||||
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 Autoscaler 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 resourceComputeAutoscalerRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceComputeAutoscalerRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
zone := d.Get("zone").(string)
|
||||
scaler, err := config.clientCompute.Autoscalers.Get(
|
||||
config.Project, zone, 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 Autoscaler: %s", err)
|
||||
}
|
||||
|
||||
d.Set("self_link", scaler.SelfLink)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceComputeAutoscalerUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
zone := d.Get("zone").(string)
|
||||
|
||||
scaler, err := buildAutoscaler(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
op, err := config.clientCompute.Autoscalers.Patch(
|
||||
config.Project, zone, d.Id(), scaler).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating Autoscaler: %s", err)
|
||||
}
|
||||
|
||||
// It probably maybe worked, so store the ID now
|
||||
d.SetId(scaler.Name)
|
||||
|
||||
// Wait for the operation to complete
|
||||
w := &OperationWaiter{
|
||||
Service: config.clientCompute,
|
||||
Op: op,
|
||||
Project: config.Project,
|
||||
Type: OperationWaitZone,
|
||||
Zone: zone,
|
||||
}
|
||||
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 Autoscaler to update: %s", err)
|
||||
}
|
||||
op = opRaw.(*compute.Operation)
|
||||
if op.Error != nil {
|
||||
// Return the error
|
||||
return OperationError(*op.Error)
|
||||
}
|
||||
|
||||
return resourceComputeAutoscalerRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceComputeAutoscalerDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
zone := d.Get("zone").(string)
|
||||
op, err := config.clientCompute.Autoscalers.Delete(
|
||||
config.Project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting autoscaler: %s", err)
|
||||
}
|
||||
|
||||
// Wait for the operation to complete
|
||||
w := &OperationWaiter{
|
||||
Service: config.clientCompute,
|
||||
Op: op,
|
||||
Project: config.Project,
|
||||
Type: OperationWaitZone,
|
||||
Zone: zone,
|
||||
}
|
||||
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 Autoscaler 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,245 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/api/compute/v1"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAutoscaler_basic(t *testing.T) {
|
||||
var ascaler compute.Autoscaler
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAutoscalerDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAutoscaler_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAutoscalerExists(
|
||||
"google_compute_autoscaler.foobar", &ascaler),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAutoscaler_update(t *testing.T) {
|
||||
var ascaler compute.Autoscaler
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAutoscalerDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccAutoscaler_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAutoscalerExists(
|
||||
"google_compute_autoscaler.foobar", &ascaler),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccAutoscaler_update,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAutoscalerExists(
|
||||
"google_compute_autoscaler.foobar", &ascaler),
|
||||
testAccCheckAutoscalerUpdated(
|
||||
"google_compute_autoscaler.foobar", 10),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAutoscalerDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_compute_autoscaler" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := config.clientCompute.Autoscalers.Get(
|
||||
config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do()
|
||||
if err == nil {
|
||||
return fmt.Errorf("Autoscaler still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckAutoscalerExists(n string, ascaler *compute.Autoscaler) 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.Autoscalers.Get(
|
||||
config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found.Name != rs.Primary.ID {
|
||||
return fmt.Errorf("Autoscaler not found")
|
||||
}
|
||||
|
||||
*ascaler = *found
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckAutoscalerUpdated(n string, max int64) 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)
|
||||
|
||||
ascaler, err := config.clientCompute.Autoscalers.Get(
|
||||
config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ascaler.AutoscalingPolicy.MaxNumReplicas != max {
|
||||
return fmt.Errorf("maximum replicas incorrect")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccAutoscaler_basic = `
|
||||
resource "google_compute_instance_template" "foobar" {
|
||||
name = "terraform-test-template-foobar"
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-7-wheezy-v20140814"
|
||||
auto_delete = true
|
||||
boot = true
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
service_account {
|
||||
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_target_pool" "foobar" {
|
||||
description = "Resource created for Terraform acceptance testing"
|
||||
name = "terraform-test-tpool-foobar"
|
||||
session_affinity = "CLIENT_IP_PROTO"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_group_manager" "foobar" {
|
||||
description = "Terraform test instance group manager"
|
||||
name = "terraform-test-groupmanager"
|
||||
instance_template = "${google_compute_instance_template.foobar.self_link}"
|
||||
target_pools = ["${google_compute_target_pool.foobar.self_link}"]
|
||||
base_instance_name = "foobar"
|
||||
zone = "us-central1-a"
|
||||
}
|
||||
|
||||
resource "google_compute_autoscaler" "foobar" {
|
||||
description = "Resource created for Terraform acceptance testing"
|
||||
name = "terraform-test-ascaler"
|
||||
zone = "us-central1-a"
|
||||
target = "${google_compute_instance_group_manager.foobar.self_link}"
|
||||
autoscaling_policy = {
|
||||
max_replicas = 5
|
||||
min_replicas = 0
|
||||
cooldown_period = 60
|
||||
cpu_utilization = {
|
||||
target = 0.5
|
||||
}
|
||||
}
|
||||
|
||||
}`
|
||||
|
||||
const testAccAutoscaler_update = `
|
||||
resource "google_compute_instance_template" "foobar" {
|
||||
name = "terraform-test-template-foobar"
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-7-wheezy-v20140814"
|
||||
auto_delete = true
|
||||
boot = true
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
service_account {
|
||||
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_target_pool" "foobar" {
|
||||
description = "Resource created for Terraform acceptance testing"
|
||||
name = "terraform-test-tpool-foobar"
|
||||
session_affinity = "CLIENT_IP_PROTO"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_group_manager" "foobar" {
|
||||
description = "Terraform test instance group manager"
|
||||
name = "terraform-test-groupmanager"
|
||||
instance_template = "${google_compute_instance_template.foobar.self_link}"
|
||||
target_pools = ["${google_compute_target_pool.foobar.self_link}"]
|
||||
base_instance_name = "foobar"
|
||||
zone = "us-central1-a"
|
||||
}
|
||||
|
||||
resource "google_compute_autoscaler" "foobar" {
|
||||
description = "Resource created for Terraform acceptance testing"
|
||||
name = "terraform-test-ascaler"
|
||||
zone = "us-central1-a"
|
||||
target = "${google_compute_instance_group_manager.foobar.self_link}"
|
||||
autoscaling_policy = {
|
||||
max_replicas = 10
|
||||
min_replicas = 0
|
||||
cooldown_period = 60
|
||||
cpu_utilization = {
|
||||
target = 0.5
|
||||
}
|
||||
}
|
||||
|
||||
}`
|
|
@ -0,0 +1,301 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/compute/v1"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceComputeInstanceGroupManager() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceComputeInstanceGroupManagerCreate,
|
||||
Read: resourceComputeInstanceGroupManagerRead,
|
||||
Update: resourceComputeInstanceGroupManagerUpdate,
|
||||
Delete: resourceComputeInstanceGroupManagerDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"base_instance_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"fingerprint": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"instance_group": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"instance_template": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"target_pools": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Required: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: func(v interface{}) int {
|
||||
return hashcode.String(v.(string))
|
||||
},
|
||||
},
|
||||
|
||||
"target_size": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"zone": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"self_link": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func waitOpZone(config *Config, op *compute.Operation, zone string,
|
||||
resource string, action string) (*compute.Operation, error) {
|
||||
|
||||
w := &OperationWaiter{
|
||||
Service: config.clientCompute,
|
||||
Op: op,
|
||||
Project: config.Project,
|
||||
Zone: zone,
|
||||
Type: OperationWaitZone,
|
||||
}
|
||||
state := w.Conf()
|
||||
state.Timeout = 8 * 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
|
||||
}
|
||||
|
||||
func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
// Get group size, default to 1 if not given
|
||||
var target_size int64 = 1
|
||||
if v, ok := d.GetOk("target_size"); ok {
|
||||
target_size = int64(v.(int))
|
||||
}
|
||||
|
||||
// Build the parameter
|
||||
manager := &compute.InstanceGroupManager{
|
||||
Name: d.Get("name").(string),
|
||||
BaseInstanceName: d.Get("base_instance_name").(string),
|
||||
InstanceTemplate: d.Get("instance_template").(string),
|
||||
TargetSize: target_size,
|
||||
}
|
||||
|
||||
// Set optional fields
|
||||
if v, ok := d.GetOk("description"); ok {
|
||||
manager.Description = v.(string)
|
||||
}
|
||||
|
||||
if attr := d.Get("target_pools").(*schema.Set); attr.Len() > 0 {
|
||||
var s []string
|
||||
for _, v := range attr.List() {
|
||||
s = append(s, v.(string))
|
||||
}
|
||||
manager.TargetPools = s
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] InstanceGroupManager insert request: %#v", manager)
|
||||
op, err := config.clientCompute.InstanceGroupManagers.Insert(
|
||||
config.Project, d.Get("zone").(string), manager).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating InstanceGroupManager: %s", err)
|
||||
}
|
||||
|
||||
// It probably maybe worked, so store the ID now
|
||||
d.SetId(manager.Name)
|
||||
|
||||
// Wait for the operation to complete
|
||||
op, err = waitOpZone(config, op, d.Get("zone").(string), "InstanceGroupManager", "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 resourceComputeInstanceGroupManagerRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
manager, err := config.clientCompute.InstanceGroupManagers.Get(
|
||||
config.Project, d.Get("zone").(string), 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 instance group manager: %s", err)
|
||||
}
|
||||
|
||||
// Set computed fields
|
||||
d.Set("fingerprint", manager.Fingerprint)
|
||||
d.Set("instance_group", manager.InstanceGroup)
|
||||
d.Set("target_size", manager.TargetSize)
|
||||
d.Set("self_link", manager.SelfLink)
|
||||
|
||||
return nil
|
||||
}
|
||||
func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
d.Partial(true)
|
||||
|
||||
// If target_pools changes then update
|
||||
if d.HasChange("target_pools") {
|
||||
var targetPools []string
|
||||
if attr := d.Get("target_pools").(*schema.Set); attr.Len() > 0 {
|
||||
for _, v := range attr.List() {
|
||||
targetPools = append(targetPools, v.(string))
|
||||
}
|
||||
}
|
||||
|
||||
// Build the parameter
|
||||
setTargetPools := &compute.InstanceGroupManagersSetTargetPoolsRequest{
|
||||
Fingerprint: d.Get("fingerprint").(string),
|
||||
TargetPools: targetPools,
|
||||
}
|
||||
|
||||
op, err := config.clientCompute.InstanceGroupManagers.SetTargetPools(
|
||||
config.Project, d.Get("zone").(string), d.Id(), setTargetPools).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
|
||||
}
|
||||
|
||||
// Wait for the operation to complete
|
||||
op, err = waitOpZone(config, op, d.Get("zone").(string), "InstanceGroupManager", "update TargetPools")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if op.Error != nil {
|
||||
return OperationError(*op.Error)
|
||||
}
|
||||
|
||||
d.SetPartial("target_pools")
|
||||
}
|
||||
|
||||
// If instance_template changes then update
|
||||
if d.HasChange("instance_template") {
|
||||
// Build the parameter
|
||||
setInstanceTemplate := &compute.InstanceGroupManagersSetInstanceTemplateRequest{
|
||||
InstanceTemplate: d.Get("instance_template").(string),
|
||||
}
|
||||
|
||||
op, err := config.clientCompute.InstanceGroupManagers.SetInstanceTemplate(
|
||||
config.Project, d.Get("zone").(string), d.Id(), setInstanceTemplate).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
|
||||
}
|
||||
|
||||
// Wait for the operation to complete
|
||||
op, err = waitOpZone(config, op, d.Get("zone").(string), "InstanceGroupManager", "update instance template")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if op.Error != nil {
|
||||
return OperationError(*op.Error)
|
||||
}
|
||||
|
||||
d.SetPartial("instance_template")
|
||||
}
|
||||
|
||||
// If size changes trigger a resize
|
||||
if d.HasChange("target_size") {
|
||||
if v, ok := d.GetOk("target_size"); ok {
|
||||
// Only do anything if the new size is set
|
||||
target_size := int64(v.(int))
|
||||
|
||||
op, err := config.clientCompute.InstanceGroupManagers.Resize(
|
||||
config.Project, d.Get("zone").(string), d.Id(), target_size).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating InstanceGroupManager: %s", err)
|
||||
}
|
||||
|
||||
// Wait for the operation to complete
|
||||
op, err = waitOpZone(config, op, d.Get("zone").(string), "InstanceGroupManager", "update target_size")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if op.Error != nil {
|
||||
return OperationError(*op.Error)
|
||||
}
|
||||
}
|
||||
|
||||
d.SetPartial("target_size")
|
||||
}
|
||||
|
||||
d.Partial(false)
|
||||
|
||||
return resourceComputeInstanceGroupManagerRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
zone := d.Get("zone").(string)
|
||||
op, err := config.clientCompute.InstanceGroupManagers.Delete(config.Project, zone, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting instance group manager: %s", err)
|
||||
}
|
||||
|
||||
// Wait for the operation to complete
|
||||
op, err = waitOpZone(config, op, d.Get("zone").(string), "InstanceGroupManager", "delete")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if op.Error != nil {
|
||||
// The resource didn't actually create
|
||||
d.SetId("")
|
||||
|
||||
// Return the error
|
||||
return OperationError(*op.Error)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/api/compute/v1"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccInstanceGroupManager_basic(t *testing.T) {
|
||||
var manager compute.InstanceGroupManager
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckInstanceGroupManagerDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccInstanceGroupManager_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckInstanceGroupManagerExists(
|
||||
"google_compute_instance_group_manager.igm-basic", &manager),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccInstanceGroupManager_update(t *testing.T) {
|
||||
var manager compute.InstanceGroupManager
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckInstanceGroupManagerDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccInstanceGroupManager_update,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckInstanceGroupManagerExists(
|
||||
"google_compute_instance_group_manager.igm-update", &manager),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
Config: testAccInstanceGroupManager_update2,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckInstanceGroupManagerExists(
|
||||
"google_compute_instance_group_manager.igm-update", &manager),
|
||||
testAccCheckInstanceGroupManagerUpdated(
|
||||
"google_compute_instance_group_manager.igm-update", 3,
|
||||
"google_compute_target_pool.igm-update", "terraform-test-igm-update2"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckInstanceGroupManagerDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_compute_instance_group_manager" {
|
||||
continue
|
||||
}
|
||||
_, err := config.clientCompute.InstanceGroupManagers.Get(
|
||||
config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("InstanceGroupManager still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckInstanceGroupManagerExists(n string, manager *compute.InstanceGroupManager) 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.InstanceGroupManagers.Get(
|
||||
config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found.Name != rs.Primary.ID {
|
||||
return fmt.Errorf("InstanceGroupManager not found")
|
||||
}
|
||||
|
||||
*manager = *found
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckInstanceGroupManagerUpdated(n string, size int64, targetPool string, template 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)
|
||||
|
||||
manager, err := config.clientCompute.InstanceGroupManagers.Get(
|
||||
config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Cannot check the target pool as the instance creation is asynchronous. However, can
|
||||
// check the target_size.
|
||||
if manager.TargetSize != size {
|
||||
return fmt.Errorf("instance count incorrect")
|
||||
}
|
||||
|
||||
// check that the instance template updated
|
||||
instanceTemplate, err := config.clientCompute.InstanceTemplates.Get(
|
||||
config.Project, template).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading instance template: %s", err)
|
||||
}
|
||||
|
||||
if instanceTemplate.Name != template {
|
||||
return fmt.Errorf("instance template not updated")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccInstanceGroupManager_basic = `
|
||||
resource "google_compute_instance_template" "igm-basic" {
|
||||
name = "terraform-test-igm-basic"
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-7-wheezy-v20140814"
|
||||
auto_delete = true
|
||||
boot = true
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
service_account {
|
||||
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_target_pool" "igm-basic" {
|
||||
description = "Resource created for Terraform acceptance testing"
|
||||
name = "terraform-test-igm-basic"
|
||||
session_affinity = "CLIENT_IP_PROTO"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_group_manager" "igm-basic" {
|
||||
description = "Terraform test instance group manager"
|
||||
name = "terraform-test-igm-basic"
|
||||
instance_template = "${google_compute_instance_template.igm-basic.self_link}"
|
||||
target_pools = ["${google_compute_target_pool.igm-basic.self_link}"]
|
||||
base_instance_name = "igm-basic"
|
||||
zone = "us-central1-c"
|
||||
target_size = 2
|
||||
}`
|
||||
|
||||
const testAccInstanceGroupManager_update = `
|
||||
resource "google_compute_instance_template" "igm-update" {
|
||||
name = "terraform-test-igm-update"
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-7-wheezy-v20140814"
|
||||
auto_delete = true
|
||||
boot = true
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
service_account {
|
||||
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_target_pool" "igm-update" {
|
||||
description = "Resource created for Terraform acceptance testing"
|
||||
name = "terraform-test-igm-update"
|
||||
session_affinity = "CLIENT_IP_PROTO"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_group_manager" "igm-update" {
|
||||
description = "Terraform test instance group manager"
|
||||
name = "terraform-test-igm-update"
|
||||
instance_template = "${google_compute_instance_template.igm-update.self_link}"
|
||||
target_pools = ["${google_compute_target_pool.igm-update.self_link}"]
|
||||
base_instance_name = "igm-update"
|
||||
zone = "us-central1-c"
|
||||
target_size = 2
|
||||
}`
|
||||
|
||||
// Change IGM's instance template and target size
|
||||
const testAccInstanceGroupManager_update2 = `
|
||||
resource "google_compute_instance_template" "igm-update" {
|
||||
name = "terraform-test-igm-update"
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-7-wheezy-v20140814"
|
||||
auto_delete = true
|
||||
boot = true
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
service_account {
|
||||
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_target_pool" "igm-update" {
|
||||
description = "Resource created for Terraform acceptance testing"
|
||||
name = "terraform-test-igm-update"
|
||||
session_affinity = "CLIENT_IP_PROTO"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_template" "igm-update2" {
|
||||
name = "terraform-test-igm-update2"
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-7-wheezy-v20140814"
|
||||
auto_delete = true
|
||||
boot = true
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
service_account {
|
||||
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_instance_group_manager" "igm-update" {
|
||||
description = "Terraform test instance group manager"
|
||||
name = "terraform-test-igm-update"
|
||||
instance_template = "${google_compute_instance_template.igm-update2.self_link}"
|
||||
target_pools = ["${google_compute_target_pool.igm-update.self_link}"]
|
||||
base_instance_name = "igm-update"
|
||||
zone = "us-central1-c"
|
||||
target_size = 3
|
||||
}`
|
||||
|
|
@ -227,7 +227,9 @@ func resourceComputeInstanceTemplate() *schema.Resource {
|
|||
}
|
||||
}
|
||||
|
||||
func buildDisks(d *schema.ResourceData, meta interface{}) []*compute.AttachedDisk {
|
||||
func buildDisks(d *schema.ResourceData, meta interface{}) ([]*compute.AttachedDisk, error) {
|
||||
config := meta.(*Config)
|
||||
|
||||
disksCount := d.Get("disk.#").(int)
|
||||
|
||||
disks := make([]*compute.AttachedDisk, 0, disksCount)
|
||||
|
@ -267,7 +269,14 @@ func buildDisks(d *schema.ResourceData, meta interface{}) []*compute.AttachedDis
|
|||
}
|
||||
|
||||
if v, ok := d.GetOk(prefix + ".source_image"); ok {
|
||||
disk.InitializeParams.SourceImage = v.(string)
|
||||
imageName := v.(string)
|
||||
imageUrl, err := resolveImage(config, imageName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error resolving image name '%s': %s",
|
||||
imageName, err)
|
||||
}
|
||||
disk.InitializeParams.SourceImage = imageUrl
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,7 +295,7 @@ func buildDisks(d *schema.ResourceData, meta interface{}) []*compute.AttachedDis
|
|||
disks = append(disks, &disk)
|
||||
}
|
||||
|
||||
return disks
|
||||
return disks, nil
|
||||
}
|
||||
|
||||
func buildNetworks(d *schema.ResourceData, meta interface{}) (error, []*compute.NetworkInterface) {
|
||||
|
@ -330,7 +339,11 @@ func resourceComputeInstanceTemplateCreate(d *schema.ResourceData, meta interfac
|
|||
instanceProperties.CanIpForward = d.Get("can_ip_forward").(bool)
|
||||
instanceProperties.Description = d.Get("instance_description").(string)
|
||||
instanceProperties.MachineType = d.Get("machine_type").(string)
|
||||
instanceProperties.Disks = buildDisks(d, meta)
|
||||
disks, err := buildDisks(d, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
instanceProperties.Disks = disks
|
||||
metadata, err := resourceInstanceMetadata(d)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -24,7 +24,7 @@ func TestAccComputeInstanceTemplate_basic(t *testing.T) {
|
|||
"google_compute_instance_template.foobar", &instanceTemplate),
|
||||
testAccCheckComputeInstanceTemplateTag(&instanceTemplate, "foo"),
|
||||
testAccCheckComputeInstanceTemplateMetadata(&instanceTemplate, "foo", "bar"),
|
||||
testAccCheckComputeInstanceTemplateDisk(&instanceTemplate, "debian-7-wheezy-v20140814", true, true),
|
||||
testAccCheckComputeInstanceTemplateDisk(&instanceTemplate, "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140814", true, true),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -64,7 +64,7 @@ func TestAccComputeInstanceTemplate_disks(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckComputeInstanceTemplateExists(
|
||||
"google_compute_instance_template.foobar", &instanceTemplate),
|
||||
testAccCheckComputeInstanceTemplateDisk(&instanceTemplate, "debian-7-wheezy-v20140814", true, true),
|
||||
testAccCheckComputeInstanceTemplateDisk(&instanceTemplate, "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140814", true, true),
|
||||
testAccCheckComputeInstanceTemplateDisk(&instanceTemplate, "terraform-test-foobar", false, false),
|
||||
),
|
||||
},
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_compute_autoscaler"
|
||||
sidebar_current: "docs-google-resource-compute-autoscaler"
|
||||
description: |-
|
||||
Manages an Autoscaler within GCE.
|
||||
---
|
||||
|
||||
# google\_compute\_autoscaler
|
||||
|
||||
A Compute Engine Autoscaler automatically adds or removes virtual machines from
|
||||
a managed instance group based on increases or decreases in load. This allows
|
||||
your applications to gracefully handle increases in traffic and reduces cost
|
||||
when the need for resources is lower. You just define the autoscaling policy and
|
||||
the autoscaler performs automatic scaling based on the measured load. For more
|
||||
information, see [the official
|
||||
documentation](https://cloud.google.com/compute/docs/autoscaler/) and
|
||||
[API](https://cloud.google.com/compute/docs/autoscaler/v1beta2/autoscalers)
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "google_compute_instance_template" "foobar" {
|
||||
name = "foobar"
|
||||
machine_type = "n1-standard-1"
|
||||
can_ip_forward = false
|
||||
tags = ["foo", "bar"]
|
||||
|
||||
disk {
|
||||
source_image = "debian-cloud/debian-7-wheezy-v20140814"
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
}
|
||||
|
||||
metadata {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
service_account {
|
||||
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_target_pool" "foobar" {
|
||||
name = "foobar"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_group_manager" "foobar" {
|
||||
name = "foobar"
|
||||
instance_template = "${google_compute_instance_template.foobar.self_link}"
|
||||
target_pools = ["${google_compute_target_pool.foobar.self_link}"]
|
||||
base_instance_name = "foobar"
|
||||
zone = "us-central1-f"
|
||||
}
|
||||
|
||||
resource "google_compute_autoscaler" "foobar" {
|
||||
name = "foobar"
|
||||
zone = "us-central1-f"
|
||||
target = "${google_compute_instance_group_manager.foobar.self_link}"
|
||||
autoscaling_policy = {
|
||||
max_replicas = 5
|
||||
min_replicas = 1
|
||||
cooldown_period = 60
|
||||
cpu_utilization = {
|
||||
target = 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Refernce
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `description` - (Optional) An optional textual description of the instance
|
||||
group manager.
|
||||
|
||||
* `target` - (Required) The full URL to the instance group manager whose size we
|
||||
control.
|
||||
|
||||
* `autoscaling_policy.` - (Required) The parameters of the autoscaling
|
||||
algorithm. Structure is documented below.
|
||||
|
||||
* `zone` - (Required) The zone of the target.
|
||||
|
||||
The `autoscaling_policy` block contains:
|
||||
|
||||
* `max_replicas` - (Required) The group will never be larger than this.
|
||||
|
||||
* `min_replicas` - (Required) The group will never be smaller than this.
|
||||
|
||||
* `cooldown_period` - (Optional) Period to wait between changes. This should be
|
||||
at least double the time your instances take to start up.
|
||||
|
||||
* `cpu_utilization` - (Optional) A policy that scales when the cluster's average
|
||||
CPU is above or below a given threshold. Structure is documented below.
|
||||
|
||||
* `metric` - (Optional) A policy that scales according to Google Cloud
|
||||
Monitoring metrics Structure is documented below.
|
||||
|
||||
* `load_balancing_utilization` - (Optional) A policy that scales when the load
|
||||
reaches a proportion of a limit defined in the HTTP load balancer. Structure
|
||||
is documented below.
|
||||
|
||||
The `cpu_utilization` block contains:
|
||||
|
||||
* `target` - The floating point threshold where CPU utilization should be. E.g.
|
||||
for 50% one would specify 0.5.
|
||||
|
||||
The `metric` block contains (more documentation
|
||||
[here](https://cloud.google.com/monitoring/api/metrics)):
|
||||
|
||||
* `name` - The name of the Google Cloud Monitoring metric to follow, e.g.
|
||||
compute.googleapis.com/instance/network/received_bytes_count
|
||||
|
||||
* `type` - Either "cumulative", "delta", or "gauge".
|
||||
|
||||
* `target` - The desired metric value per instance. Must be a positive value.
|
||||
|
||||
The `load_balancing_utilization` block contains:
|
||||
|
||||
* `target` - The floating point threshold where load balancing utilization
|
||||
should be. E.g. if the load balancer's `maxRatePerInstance` is 10 requests
|
||||
per second (RPS) then setting this to 0.5 would cause the group to be scaled
|
||||
such that each instance receives 5 RPS.
|
||||
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `self_link` - The URL of the created resource.
|
|
@ -0,0 +1,65 @@
|
|||
---
|
||||
layout: "google"
|
||||
page_title: "Google: google_compute_instance_group_manager"
|
||||
sidebar_current: "docs-google-resource-compute-instance_group_manager"
|
||||
description: |-
|
||||
Manages an Instance Group within GCE.
|
||||
---
|
||||
|
||||
# google\_compute\_instance\_group\_manager
|
||||
|
||||
The Google Compute Engine Instance Group Manager API creates and manages pools
|
||||
of homogeneous Compute Engine virtual machine instances from a common instance
|
||||
template. For more information, see [the official documentation](https://cloud.google.com/compute/docs/instance-groups/manager
|
||||
and [API](https://cloud.google.com/compute/docs/instance-groups/manager/v1beta2/instanceGroupManagers)
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "google_compute_instance_group_manager" "foobar" {
|
||||
description = "Terraform test instance group manager"
|
||||
name = "terraform-test"
|
||||
instance_template = "${google_compute_instance_template.foobar.self_link}"
|
||||
target_pools = ["${google_compute_target_pool.foobar.self_link}"]
|
||||
base_instance_name = "foobar"
|
||||
zone = "us-central1-a"
|
||||
target_size = 2
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Refernce
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `base_instance_name` - (Required) The base instance name to use for
|
||||
instances in this group. The value must be a valid [RFC1035](https://www.ietf.org/rfc/rfc1035.txt) name.
|
||||
Supported characters are lowercase letters, numbers, and hyphens (-). Instances
|
||||
are named by appending a hyphen and a random four-character string to the base
|
||||
instance name.
|
||||
|
||||
* `description` - (Optional) An optional textual description of the instance
|
||||
group manager.
|
||||
|
||||
* `instance_template` - (Required) The full URL to an instance template from
|
||||
which all new instances will be created.
|
||||
|
||||
* `name` - (Required) The name of the instance group manager. Must be 1-63
|
||||
characters long and comply with [RFC1035](https://www.ietf.org/rfc/rfc1035.txt).
|
||||
Supported characters include lowercase letters, numbers, and hyphens.
|
||||
|
||||
* `target_size` - (Optional) If not given at creation time, this defaults to 1. Do not specify this
|
||||
if you are managing the group with an autoscaler, as this will cause fighting.
|
||||
|
||||
* `target_pools` - (Required) The full URL of all target pools to which new
|
||||
instances in the group are added. Updating the target pool values does not
|
||||
affect existing instances.
|
||||
|
||||
* `zone` - (Required) The zone that instances in this group should be created in.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `instance_group` - The full URL of the instance group created by the manager.
|
||||
|
||||
* `self_link` - The URL of the created resource.
|
|
@ -64,6 +64,15 @@
|
|||
<li<%= sidebar_current("docs-google-resource-dns-record-set") %>>
|
||||
<a href="/docs/providers/google/r/dns_record_set.html">google_dns_record_set</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-resource--compute-instance-group-manager") %>>
|
||||
<a href="/docs/providers/google/r/compute_instance_group_manager.html">google_compute_instance_group_manager</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-resource-compute-autoscaler") %>>
|
||||
<a href="/docs/providers/google/r/compute_autoscaler.html">google_compute_autoscaler</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-google-resource-storage-bucket") %>>
|
||||
<a href="/docs/providers/google/r/storage_bucket.html">google_storage_bucket</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue