github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/google/resource_compute_autoscaler.go (about)

     1  package google
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  	"google.golang.org/api/compute/v1"
    10  )
    11  
    12  func resourceComputeAutoscaler() *schema.Resource {
    13  	return &schema.Resource{
    14  		Create: resourceComputeAutoscalerCreate,
    15  		Read:   resourceComputeAutoscalerRead,
    16  		Update: resourceComputeAutoscalerUpdate,
    17  		Delete: resourceComputeAutoscalerDelete,
    18  		Importer: &schema.ResourceImporter{
    19  			State: schema.ImportStatePassthrough,
    20  		},
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"name": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				ForceNew: true,
    26  				Required: true,
    27  			},
    28  
    29  			"target": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  			},
    33  
    34  			"zone": &schema.Schema{
    35  				Type:     schema.TypeString,
    36  				Required: true,
    37  				ForceNew: true,
    38  			},
    39  
    40  			"autoscaling_policy": &schema.Schema{
    41  				Type:     schema.TypeList,
    42  				Optional: true,
    43  				Elem: &schema.Resource{
    44  					Schema: map[string]*schema.Schema{
    45  						"min_replicas": &schema.Schema{
    46  							Type:     schema.TypeInt,
    47  							Required: true,
    48  						},
    49  
    50  						"max_replicas": &schema.Schema{
    51  							Type:     schema.TypeInt,
    52  							Required: true,
    53  						},
    54  
    55  						"cooldown_period": &schema.Schema{
    56  							Type:     schema.TypeInt,
    57  							Optional: true,
    58  							Default:  60,
    59  						},
    60  
    61  						"cpu_utilization": &schema.Schema{
    62  							Type:     schema.TypeList,
    63  							Optional: true,
    64  							Elem: &schema.Resource{
    65  								Schema: map[string]*schema.Schema{
    66  									"target": &schema.Schema{
    67  										Type:     schema.TypeFloat,
    68  										Required: true,
    69  									},
    70  								},
    71  							},
    72  						},
    73  
    74  						"metric": &schema.Schema{
    75  							Type:     schema.TypeList,
    76  							Optional: true,
    77  							Elem: &schema.Resource{
    78  								Schema: map[string]*schema.Schema{
    79  									"name": &schema.Schema{
    80  										Type:     schema.TypeString,
    81  										Required: true,
    82  									},
    83  									"target": &schema.Schema{
    84  										Type:     schema.TypeFloat,
    85  										Required: true,
    86  									},
    87  
    88  									"type": &schema.Schema{
    89  										Type:     schema.TypeString,
    90  										Required: true,
    91  									},
    92  								},
    93  							},
    94  						},
    95  
    96  						"load_balancing_utilization": &schema.Schema{
    97  							Type:     schema.TypeList,
    98  							Optional: true,
    99  							Elem: &schema.Resource{
   100  								Schema: map[string]*schema.Schema{
   101  									"target": &schema.Schema{
   102  										Type:     schema.TypeFloat,
   103  										Required: true,
   104  									},
   105  								},
   106  							},
   107  						},
   108  					},
   109  				},
   110  			},
   111  
   112  			"description": &schema.Schema{
   113  				Type:     schema.TypeString,
   114  				Optional: true,
   115  			},
   116  
   117  			"project": &schema.Schema{
   118  				Type:     schema.TypeString,
   119  				Optional: true,
   120  				ForceNew: true,
   121  			},
   122  
   123  			"self_link": &schema.Schema{
   124  				Type:     schema.TypeString,
   125  				Computed: true,
   126  			},
   127  		},
   128  	}
   129  }
   130  
   131  func buildAutoscaler(d *schema.ResourceData) (*compute.Autoscaler, error) {
   132  	// Build the parameter
   133  	scaler := &compute.Autoscaler{
   134  		Name:   d.Get("name").(string),
   135  		Target: d.Get("target").(string),
   136  	}
   137  
   138  	// Optional fields
   139  	if v, ok := d.GetOk("description"); ok {
   140  		scaler.Description = v.(string)
   141  	}
   142  
   143  	aspCount := d.Get("autoscaling_policy.#").(int)
   144  	if aspCount != 1 {
   145  		return nil, fmt.Errorf("The autoscaler must have exactly one autoscaling_policy, found %d.", aspCount)
   146  	}
   147  
   148  	prefix := "autoscaling_policy.0."
   149  
   150  	scaler.AutoscalingPolicy = &compute.AutoscalingPolicy{
   151  		MaxNumReplicas:    int64(d.Get(prefix + "max_replicas").(int)),
   152  		MinNumReplicas:    int64(d.Get(prefix + "min_replicas").(int)),
   153  		CoolDownPeriodSec: int64(d.Get(prefix + "cooldown_period").(int)),
   154  	}
   155  
   156  	// Check that only one autoscaling policy is defined
   157  
   158  	policyCounter := 0
   159  	if _, ok := d.GetOk(prefix + "cpu_utilization"); ok {
   160  		if d.Get(prefix+"cpu_utilization.0.target").(float64) != 0 {
   161  			cpuUtilCount := d.Get(prefix + "cpu_utilization.#").(int)
   162  			if cpuUtilCount != 1 {
   163  				return nil, fmt.Errorf("The autoscaling_policy must have exactly one cpu_utilization, found %d.", cpuUtilCount)
   164  			}
   165  			policyCounter++
   166  			scaler.AutoscalingPolicy.CpuUtilization = &compute.AutoscalingPolicyCpuUtilization{
   167  				UtilizationTarget: d.Get(prefix + "cpu_utilization.0.target").(float64),
   168  			}
   169  		}
   170  	}
   171  	if _, ok := d.GetOk("autoscaling_policy.0.metric"); ok {
   172  		if d.Get(prefix+"metric.0.name") != "" {
   173  			policyCounter++
   174  			metricCount := d.Get(prefix + "metric.#").(int)
   175  			if metricCount != 1 {
   176  				return nil, fmt.Errorf("The autoscaling_policy must have exactly one metric, found %d.", metricCount)
   177  			}
   178  			scaler.AutoscalingPolicy.CustomMetricUtilizations = []*compute.AutoscalingPolicyCustomMetricUtilization{
   179  				{
   180  					Metric:                d.Get(prefix + "metric.0.name").(string),
   181  					UtilizationTarget:     d.Get(prefix + "metric.0.target").(float64),
   182  					UtilizationTargetType: d.Get(prefix + "metric.0.type").(string),
   183  				},
   184  			}
   185  		}
   186  
   187  	}
   188  	if _, ok := d.GetOk("autoscaling_policy.0.load_balancing_utilization"); ok {
   189  		if d.Get(prefix+"load_balancing_utilization.0.target").(float64) != 0 {
   190  			policyCounter++
   191  			lbuCount := d.Get(prefix + "load_balancing_utilization.#").(int)
   192  			if lbuCount != 1 {
   193  				return nil, fmt.Errorf("The autoscaling_policy must have exactly one load_balancing_utilization, found %d.", lbuCount)
   194  			}
   195  			scaler.AutoscalingPolicy.LoadBalancingUtilization = &compute.AutoscalingPolicyLoadBalancingUtilization{
   196  				UtilizationTarget: d.Get(prefix + "load_balancing_utilization.0.target").(float64),
   197  			}
   198  		}
   199  	}
   200  
   201  	if policyCounter != 1 {
   202  		return nil, fmt.Errorf("One policy must be defined for an autoscaler.")
   203  	}
   204  
   205  	return scaler, nil
   206  }
   207  
   208  func resourceComputeAutoscalerCreate(d *schema.ResourceData, meta interface{}) error {
   209  	config := meta.(*Config)
   210  
   211  	project, err := getProject(d, config)
   212  	if err != nil {
   213  		return err
   214  	}
   215  
   216  	// Get the zone
   217  	log.Printf("[DEBUG] Loading zone: %s", d.Get("zone").(string))
   218  	zone, err := config.clientCompute.Zones.Get(
   219  		project, d.Get("zone").(string)).Do()
   220  	if err != nil {
   221  		return fmt.Errorf(
   222  			"Error loading zone '%s': %s", d.Get("zone").(string), err)
   223  	}
   224  
   225  	scaler, err := buildAutoscaler(d)
   226  	if err != nil {
   227  		return err
   228  	}
   229  
   230  	op, err := config.clientCompute.Autoscalers.Insert(
   231  		project, zone.Name, scaler).Do()
   232  	if err != nil {
   233  		return fmt.Errorf("Error creating Autoscaler: %s", err)
   234  	}
   235  
   236  	// It probably maybe worked, so store the ID now
   237  	d.SetId(scaler.Name)
   238  
   239  	err = computeOperationWaitZone(config, op, project, zone.Name, "Creating Autoscaler")
   240  	if err != nil {
   241  		return err
   242  	}
   243  
   244  	return resourceComputeAutoscalerRead(d, meta)
   245  }
   246  
   247  func flattenAutoscalingPolicy(policy *compute.AutoscalingPolicy) []map[string]interface{} {
   248  	result := make([]map[string]interface{}, 0, 1)
   249  	policyMap := make(map[string]interface{})
   250  	policyMap["max_replicas"] = policy.MaxNumReplicas
   251  	policyMap["min_replicas"] = policy.MinNumReplicas
   252  	policyMap["cooldown_period"] = policy.CoolDownPeriodSec
   253  	if policy.CpuUtilization != nil {
   254  		cpuUtils := make([]map[string]interface{}, 0, 1)
   255  		cpuUtil := make(map[string]interface{})
   256  		cpuUtil["target"] = policy.CpuUtilization.UtilizationTarget
   257  		cpuUtils = append(cpuUtils, cpuUtil)
   258  		policyMap["cpu_utilization"] = cpuUtils
   259  	}
   260  	if policy.LoadBalancingUtilization != nil {
   261  		loadBalancingUtils := make([]map[string]interface{}, 0, 1)
   262  		loadBalancingUtil := make(map[string]interface{})
   263  		loadBalancingUtil["target"] = policy.LoadBalancingUtilization.UtilizationTarget
   264  		loadBalancingUtils = append(loadBalancingUtils, loadBalancingUtil)
   265  		policyMap["load_balancing_utilization"] = loadBalancingUtils
   266  	}
   267  	if policy.CustomMetricUtilizations != nil {
   268  		metricUtils := make([]map[string]interface{}, 0, len(policy.CustomMetricUtilizations))
   269  		for _, customMetricUtilization := range policy.CustomMetricUtilizations {
   270  			metricUtil := make(map[string]interface{})
   271  			metricUtil["target"] = customMetricUtilization.UtilizationTarget
   272  
   273  			metricUtils = append(metricUtils, metricUtil)
   274  		}
   275  		policyMap["metric"] = metricUtils
   276  	}
   277  	result = append(result, policyMap)
   278  	return result
   279  }
   280  
   281  func resourceComputeAutoscalerRead(d *schema.ResourceData, meta interface{}) error {
   282  	config := meta.(*Config)
   283  
   284  	project, err := getProject(d, config)
   285  	if err != nil {
   286  		return err
   287  	}
   288  
   289  	region, err := getRegion(d, config)
   290  	if err != nil {
   291  		return err
   292  	}
   293  	var getAutoscaler = func(zone string) (interface{}, error) {
   294  		return config.clientCompute.Autoscalers.Get(project, zone, d.Id()).Do()
   295  	}
   296  
   297  	resource, err := getZonalResourceFromRegion(getAutoscaler, region, config.clientCompute, project)
   298  	if err != nil {
   299  		return err
   300  	}
   301  	if resource == nil {
   302  		log.Printf("[WARN] Removing Autoscalar %q because it's gone", d.Get("name").(string))
   303  		d.SetId("")
   304  		return nil
   305  	}
   306  	scaler := resource.(*compute.Autoscaler)
   307  	zoneUrl := strings.Split(scaler.Zone, "/")
   308  	d.Set("self_link", scaler.SelfLink)
   309  	d.Set("name", scaler.Name)
   310  	d.Set("target", scaler.Target)
   311  	d.Set("zone", zoneUrl[len(zoneUrl)-1])
   312  	d.Set("description", scaler.Description)
   313  	if scaler.AutoscalingPolicy != nil {
   314  		d.Set("autoscaling_policy", flattenAutoscalingPolicy(scaler.AutoscalingPolicy))
   315  	}
   316  
   317  	return nil
   318  }
   319  
   320  func resourceComputeAutoscalerUpdate(d *schema.ResourceData, meta interface{}) error {
   321  	config := meta.(*Config)
   322  
   323  	project, err := getProject(d, config)
   324  	if err != nil {
   325  		return err
   326  	}
   327  
   328  	zone := d.Get("zone").(string)
   329  
   330  	scaler, err := buildAutoscaler(d)
   331  	if err != nil {
   332  		return err
   333  	}
   334  
   335  	op, err := config.clientCompute.Autoscalers.Patch(
   336  		project, zone, d.Id(), scaler).Do()
   337  	if err != nil {
   338  		return fmt.Errorf("Error updating Autoscaler: %s", err)
   339  	}
   340  
   341  	// It probably maybe worked, so store the ID now
   342  	d.SetId(scaler.Name)
   343  
   344  	err = computeOperationWaitZone(config, op, project, zone, "Updating Autoscaler")
   345  	if err != nil {
   346  		return err
   347  	}
   348  
   349  	return resourceComputeAutoscalerRead(d, meta)
   350  }
   351  
   352  func resourceComputeAutoscalerDelete(d *schema.ResourceData, meta interface{}) error {
   353  	config := meta.(*Config)
   354  
   355  	project, err := getProject(d, config)
   356  	if err != nil {
   357  		return err
   358  	}
   359  
   360  	zone := d.Get("zone").(string)
   361  	op, err := config.clientCompute.Autoscalers.Delete(
   362  		project, zone, d.Id()).Do()
   363  	if err != nil {
   364  		return fmt.Errorf("Error deleting autoscaler: %s", err)
   365  	}
   366  
   367  	err = computeOperationWaitZone(config, op, project, zone, "Deleting Autoscaler")
   368  	if err != nil {
   369  		return err
   370  	}
   371  
   372  	d.SetId("")
   373  	return nil
   374  }