From bc3839d8da64e82c1a89716d2b2bef23be76f9b7 Mon Sep 17 00:00:00 2001 From: Scott Stevenson Date: Fri, 6 Oct 2017 12:14:00 -0400 Subject: [PATCH 1/2] Add resource_compute_region_autoscaler --- google/provider.go | 1 + google/resource_compute_region_autoscaler.go | 372 ++++++++++++++++++ ...resource_compute_region_autoscaler_test.go | 262 ++++++++++++ 3 files changed, 635 insertions(+) create mode 100644 google/resource_compute_region_autoscaler.go create mode 100644 google/resource_compute_region_autoscaler_test.go diff --git a/google/provider.go b/google/provider.go index bec824725b0..066b261786f 100644 --- a/google/provider.go +++ b/google/provider.go @@ -87,6 +87,7 @@ func Provider() terraform.ResourceProvider { "google_compute_network_peering": resourceComputeNetworkPeering(), "google_compute_project_metadata": resourceComputeProjectMetadata(), "google_compute_project_metadata_item": resourceComputeProjectMetadataItem(), + "google_compute_region_autoscaler": resourceComputeRegionAutoscaler(), "google_compute_region_backend_service": resourceComputeRegionBackendService(), "google_compute_region_instance_group_manager": resourceComputeRegionInstanceGroupManager(), "google_compute_route": resourceComputeRoute(), diff --git a/google/resource_compute_region_autoscaler.go b/google/resource_compute_region_autoscaler.go new file mode 100644 index 00000000000..398d531dba2 --- /dev/null +++ b/google/resource_compute_region_autoscaler.go @@ -0,0 +1,372 @@ +package google + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/compute/v1" +) + +func resourceComputeRegionAutoscaler() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeRegionAutoscalerCreate, + Read: resourceComputeRegionAutoscalerRead, + Update: resourceComputeRegionAutoscalerUpdate, + Delete: resourceComputeRegionAutoscalerDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + + "target": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: 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, + }, + }, + }, + }, + }, + }, + }, + + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "project": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "self_link": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func buildRegionAutoscaler(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 resourceComputeRegionAutoscalerCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + // Get the region + log.Printf("[DEBUG] Loading region: %s", d.Get("region").(string)) + region, err := config.clientCompute.Regions.Get( + project, d.Get("region").(string)).Do() + if err != nil { + return fmt.Errorf( + "Error loading region '%s': %s", d.Get("region").(string), err) + } + + scaler, err := buildAutoscaler(d) + if err != nil { + return err + } + + op, err := config.clientCompute.RegionAutoscalers.Insert( + project, region.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) + + err = computeOperationWait(config, op, project, "Creating Autoscaler") + if err != nil { + return err + } + + return resourceComputeRegionAutoscalerRead(d, meta) +} + +func flattenRegionAutoscalingPolicy(policy *compute.AutoscalingPolicy) []map[string]interface{} { + result := make([]map[string]interface{}, 0, 1) + policyMap := make(map[string]interface{}) + policyMap["max_replicas"] = policy.MaxNumReplicas + policyMap["min_replicas"] = policy.MinNumReplicas + policyMap["cooldown_period"] = policy.CoolDownPeriodSec + if policy.CpuUtilization != nil { + cpuUtils := make([]map[string]interface{}, 0, 1) + cpuUtil := make(map[string]interface{}) + cpuUtil["target"] = policy.CpuUtilization.UtilizationTarget + cpuUtils = append(cpuUtils, cpuUtil) + policyMap["cpu_utilization"] = cpuUtils + } + if policy.LoadBalancingUtilization != nil { + loadBalancingUtils := make([]map[string]interface{}, 0, 1) + loadBalancingUtil := make(map[string]interface{}) + loadBalancingUtil["target"] = policy.LoadBalancingUtilization.UtilizationTarget + loadBalancingUtils = append(loadBalancingUtils, loadBalancingUtil) + policyMap["load_balancing_utilization"] = loadBalancingUtils + } + if policy.CustomMetricUtilizations != nil { + metricUtils := make([]map[string]interface{}, 0, len(policy.CustomMetricUtilizations)) + for _, customMetricUtilization := range policy.CustomMetricUtilizations { + metricUtil := make(map[string]interface{}) + metricUtil["target"] = customMetricUtilization.UtilizationTarget + metricUtils = append(metricUtils, metricUtil) + } + policyMap["metric"] = metricUtils + } + result = append(result, policyMap) + return result +} + +func resourceComputeRegionAutoscalerRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + region, err := getRegion(d, config) + if err != nil { + return err + } + + scaler, err := config.clientCompute.RegionAutoscalers.Get( + project, region, d.Id()).Do() + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("Autoscaler %q", d.Id())) + } + + if scaler == nil { + log.Printf("[WARN] Removing Autoscaler %q because it's gone", d.Get("name").(string)) + d.SetId("") + return nil + } + + regionUrl := strings.Split(scaler.Region, "/") + d.Set("self_link", scaler.SelfLink) + d.Set("name", scaler.Name) + d.Set("target", scaler.Target) + d.Set("region", regionUrl[len(regionUrl)-1]) + d.Set("description", scaler.Description) + if scaler.AutoscalingPolicy != nil { + d.Set("autoscaling_policy", flattenRegionAutoscalingPolicy(scaler.AutoscalingPolicy)) + } + + return nil +} + +func resourceComputeRegionAutoscalerUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + region := d.Get("region").(string) + + scaler, err := buildAutoscaler(d) + if err != nil { + return err + } + + op, err := config.clientCompute.RegionAutoscalers.Update( + project, region, 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) + + err = computeOperationWait(config, op, project, "Updating Autoscaler") + if err != nil { + return err + } + + return resourceComputeRegionAutoscalerRead(d, meta) +} + +func resourceComputeRegionAutoscalerDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + region := d.Get("region").(string) + op, err := config.clientCompute.RegionAutoscalers.Delete( + project, region, d.Id()).Do() + if err != nil { + return fmt.Errorf("Error deleting autoscaler: %s", err) + } + + err = computeOperationWait(config, op, project, "Deleting Autoscaler") + if err != nil { + return err + } + + d.SetId("") + return nil +} diff --git a/google/resource_compute_region_autoscaler_test.go b/google/resource_compute_region_autoscaler_test.go new file mode 100644 index 00000000000..755d96a4c0f --- /dev/null +++ b/google/resource_compute_region_autoscaler_test.go @@ -0,0 +1,262 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "google.golang.org/api/compute/v1" +) + +func TestAccComputeRegionAutoscaler_basic(t *testing.T) { + var ascaler compute.Autoscaler + + var it_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var tp_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var igm_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var autoscaler_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeRegionAutoscalerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeRegionAutoscaler_basic(it_name, tp_name, igm_name, autoscaler_name), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionAutoscalerExists( + "google_compute_region_autoscaler.foobar", &ascaler), + ), + }, + }, + }) +} + +func TestAccComputeRegionAutoscaler_update(t *testing.T) { + var ascaler compute.Autoscaler + + var it_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var tp_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var igm_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var autoscaler_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeRegionAutoscalerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeRegionAutoscaler_basic(it_name, tp_name, igm_name, autoscaler_name), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionAutoscalerExists( + "google_compute_region_autoscaler.foobar", &ascaler), + ), + }, + resource.TestStep{ + Config: testAccComputeRegionAutoscaler_update(it_name, tp_name, igm_name, autoscaler_name), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionAutoscalerExists( + "google_compute_region_autoscaler.foobar", &ascaler), + testAccCheckComputeRegionAutoscalerUpdated( + "google_compute_region_autoscaler.foobar", 10), + ), + }, + }, + }) +} + +func testAccCheckComputeRegionAutoscalerDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_compute_region_autoscaler" { + continue + } + + _, err := config.clientCompute.RegionAutoscalers.Get( + config.Project, rs.Primary.Attributes["region"], rs.Primary.ID).Do() + if err == nil { + return fmt.Errorf("Autoscaler still exists") + } + } + + return nil +} + +func testAccCheckComputeRegionAutoscalerExists(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.RegionAutoscalers.Get( + config.Project, rs.Primary.Attributes["region"], 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 testAccCheckComputeRegionAutoscalerUpdated(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.RegionAutoscalers.Get( + config.Project, rs.Primary.Attributes["region"], rs.Primary.ID).Do() + if err != nil { + return err + } + + if ascaler.AutoscalingPolicy.MaxNumReplicas != max { + return fmt.Errorf("maximum replicas incorrect") + } + + return nil + } +} + +func testAccComputeRegionAutoscaler_basic(it_name, tp_name, igm_name, autoscaler_name string) string { + return fmt.Sprintf(` +resource "google_compute_instance_template" "foobar" { + name = "%s" + machine_type = "n1-standard-1" + can_ip_forward = false + tags = ["foo", "bar"] + + disk { + source_image = "debian-cloud/debian-8-jessie-v20160803" + 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 = "%s" + session_affinity = "CLIENT_IP_PROTO" +} + +resource "google_compute_region_instance_group_manager" "foobar" { + description = "Terraform test instance group manager" + name = "%s" + instance_template = "${google_compute_instance_template.foobar.self_link}" + target_pools = ["${google_compute_target_pool.foobar.self_link}"] + base_instance_name = "foobar" + region = "us-central1" +} + +resource "google_compute_region_autoscaler" "foobar" { + description = "Resource created for Terraform acceptance testing" + name = "%s" + region = "us-central1" + target = "${google_compute_region_instance_group_manager.foobar.self_link}" + autoscaling_policy = { + max_replicas = 5 + min_replicas = 1 + cooldown_period = 60 + cpu_utilization = { + target = 0.5 + } + } + +} +`, it_name, tp_name, igm_name, autoscaler_name) +} + +func testAccComputeRegionAutoscaler_update(it_name, tp_name, igm_name, autoscaler_name string) string { + return fmt.Sprintf(` +resource "google_compute_instance_template" "foobar" { + name = "%s" + machine_type = "n1-standard-1" + can_ip_forward = false + tags = ["foo", "bar"] + + disk { + source_image = "debian-cloud/debian-8-jessie-v20160803" + 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 = "%s" + session_affinity = "CLIENT_IP_PROTO" +} + +resource "google_compute_region_instance_group_manager" "foobar" { + description = "Terraform test instance group manager" + name = "%s" + instance_template = "${google_compute_instance_template.foobar.self_link}" + target_pools = ["${google_compute_target_pool.foobar.self_link}"] + base_instance_name = "foobar" + region = "us-central1" +} + +resource "google_compute_region_autoscaler" "foobar" { + description = "Resource created for Terraform acceptance testing" + name = "%s" + region = "us-central1" + target = "${google_compute_region_instance_group_manager.foobar.self_link}" + autoscaling_policy = { + max_replicas = 10 + min_replicas = 1 + cooldown_period = 60 + cpu_utilization = { + target = 0.5 + } + } + +} +`, it_name, tp_name, igm_name, autoscaler_name) +} From 9209324658f4d9da6819b3e02ebbfad93efd0a49 Mon Sep 17 00:00:00 2001 From: Scott Stevenson Date: Fri, 6 Oct 2017 21:54:23 -0400 Subject: [PATCH 2/2] Add import acceptance tests, reuse zonal autoscaler code - Enforce single autoscaling policy requirement at terraform plan time --- .../import_compute_region_autoscaler_test.go | 36 ++++ google/resource_compute_autoscaler.go | 159 +++++++-------- google/resource_compute_region_autoscaler.go | 189 +----------------- 3 files changed, 116 insertions(+), 268 deletions(-) create mode 100644 google/import_compute_region_autoscaler_test.go diff --git a/google/import_compute_region_autoscaler_test.go b/google/import_compute_region_autoscaler_test.go new file mode 100644 index 00000000000..bd3c896b914 --- /dev/null +++ b/google/import_compute_region_autoscaler_test.go @@ -0,0 +1,36 @@ +package google + +import ( + "testing" + + "fmt" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccComputeRegionAutoscaler_importBasic(t *testing.T) { + resourceName := "google_compute_region_autoscaler.foobar" + + var it_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var tp_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var igm_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + var autoscaler_name = fmt.Sprintf("region-autoscaler-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeRegionAutoscalerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeRegionAutoscaler_basic(it_name, tp_name, igm_name, autoscaler_name), + }, + + resource.TestStep{ + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/google/resource_compute_autoscaler.go b/google/resource_compute_autoscaler.go index d4cf49d6cc5..71844572ce9 100644 --- a/google/resource_compute_autoscaler.go +++ b/google/resource_compute_autoscaler.go @@ -3,12 +3,85 @@ package google import ( "fmt" "log" - "strings" + + compute "google.golang.org/api/compute/v1" "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" ) +var autoscalingPolicy *schema.Schema = &schema.Schema{ + Type: schema.TypeList, + Required: true, + MaxItems: 1, + 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, + }, + }, + }, + }, + }, + }, +} + func resourceComputeAutoscaler() *schema.Resource { return &schema.Resource{ Create: resourceComputeAutoscalerCreate, @@ -37,77 +110,7 @@ func resourceComputeAutoscaler() *schema.Resource { ForceNew: 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, - }, - }, - }, - }, - }, - }, - }, + "autoscaling_policy": autoscalingPolicy, "description": &schema.Schema{ Type: schema.TypeString, @@ -140,11 +143,6 @@ func buildAutoscaler(d *schema.ResourceData) (*compute.Autoscaler, error) { 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{ @@ -154,7 +152,6 @@ func buildAutoscaler(d *schema.ResourceData) (*compute.Autoscaler, error) { } // 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 { @@ -183,7 +180,6 @@ func buildAutoscaler(d *schema.ResourceData) (*compute.Autoscaler, error) { }, } } - } if _, ok := d.GetOk("autoscaling_policy.0.load_balancing_utilization"); ok { if d.Get(prefix+"load_balancing_utilization.0.target").(float64) != 0 { @@ -320,11 +316,10 @@ func resourceComputeAutoscalerRead(d *schema.ResourceData, meta interface{}) err return nil } - zoneUrl := strings.Split(scaler.Zone, "/") d.Set("self_link", scaler.SelfLink) d.Set("name", scaler.Name) d.Set("target", scaler.Target) - d.Set("zone", zoneUrl[len(zoneUrl)-1]) + d.Set("zone", GetResourceNameFromSelfLink(scaler.Zone)) d.Set("description", scaler.Description) if scaler.AutoscalingPolicy != nil { d.Set("autoscaling_policy", flattenAutoscalingPolicy(scaler.AutoscalingPolicy)) diff --git a/google/resource_compute_region_autoscaler.go b/google/resource_compute_region_autoscaler.go index 398d531dba2..407f365a8f4 100644 --- a/google/resource_compute_region_autoscaler.go +++ b/google/resource_compute_region_autoscaler.go @@ -3,10 +3,8 @@ package google import ( "fmt" "log" - "strings" "github.com/hashicorp/terraform/helper/schema" - "google.golang.org/api/compute/v1" ) func resourceComputeRegionAutoscaler() *schema.Resource { @@ -37,77 +35,7 @@ func resourceComputeRegionAutoscaler() *schema.Resource { ForceNew: 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, - }, - }, - }, - }, - }, - }, - }, + "autoscaling_policy": autoscalingPolicy, "description": &schema.Schema{ Type: schema.TypeString, @@ -128,83 +56,6 @@ func resourceComputeRegionAutoscaler() *schema.Resource { } } -func buildRegionAutoscaler(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 resourceComputeRegionAutoscalerCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -244,39 +95,6 @@ func resourceComputeRegionAutoscalerCreate(d *schema.ResourceData, meta interfac return resourceComputeRegionAutoscalerRead(d, meta) } -func flattenRegionAutoscalingPolicy(policy *compute.AutoscalingPolicy) []map[string]interface{} { - result := make([]map[string]interface{}, 0, 1) - policyMap := make(map[string]interface{}) - policyMap["max_replicas"] = policy.MaxNumReplicas - policyMap["min_replicas"] = policy.MinNumReplicas - policyMap["cooldown_period"] = policy.CoolDownPeriodSec - if policy.CpuUtilization != nil { - cpuUtils := make([]map[string]interface{}, 0, 1) - cpuUtil := make(map[string]interface{}) - cpuUtil["target"] = policy.CpuUtilization.UtilizationTarget - cpuUtils = append(cpuUtils, cpuUtil) - policyMap["cpu_utilization"] = cpuUtils - } - if policy.LoadBalancingUtilization != nil { - loadBalancingUtils := make([]map[string]interface{}, 0, 1) - loadBalancingUtil := make(map[string]interface{}) - loadBalancingUtil["target"] = policy.LoadBalancingUtilization.UtilizationTarget - loadBalancingUtils = append(loadBalancingUtils, loadBalancingUtil) - policyMap["load_balancing_utilization"] = loadBalancingUtils - } - if policy.CustomMetricUtilizations != nil { - metricUtils := make([]map[string]interface{}, 0, len(policy.CustomMetricUtilizations)) - for _, customMetricUtilization := range policy.CustomMetricUtilizations { - metricUtil := make(map[string]interface{}) - metricUtil["target"] = customMetricUtilization.UtilizationTarget - metricUtils = append(metricUtils, metricUtil) - } - policyMap["metric"] = metricUtils - } - result = append(result, policyMap) - return result -} - func resourceComputeRegionAutoscalerRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -302,14 +120,13 @@ func resourceComputeRegionAutoscalerRead(d *schema.ResourceData, meta interface{ return nil } - regionUrl := strings.Split(scaler.Region, "/") d.Set("self_link", scaler.SelfLink) d.Set("name", scaler.Name) d.Set("target", scaler.Target) - d.Set("region", regionUrl[len(regionUrl)-1]) + d.Set("region", GetResourceNameFromSelfLink(scaler.Region)) d.Set("description", scaler.Description) if scaler.AutoscalingPolicy != nil { - d.Set("autoscaling_policy", flattenRegionAutoscalingPolicy(scaler.AutoscalingPolicy)) + d.Set("autoscaling_policy", flattenAutoscalingPolicy(scaler.AutoscalingPolicy)) } return nil