github.com/atsaki/terraform@v0.4.3-0.20150919165407-25bba5967654/builtin/providers/google/resource_compute_autoscaler.go (about)

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