github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/aws/resource_aws_autoscaling_group_waiting.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/hashicorp/terraform/helper/resource" 10 "github.com/hashicorp/terraform/helper/schema" 11 ) 12 13 // waitForASGCapacityTimeout gathers the current numbers of healthy instances 14 // in the ASG and its attached ELBs and yields these numbers to a 15 // capacitySatifiedFunction. Loops for up to wait_for_capacity_timeout until 16 // the capacitySatisfiedFunc returns true. 17 // 18 // See "Waiting for Capacity" in docs for more discussion of the feature. 19 func waitForASGCapacity( 20 d *schema.ResourceData, 21 meta interface{}, 22 satisfiedFunc capacitySatisfiedFunc) error { 23 wait, err := time.ParseDuration(d.Get("wait_for_capacity_timeout").(string)) 24 if err != nil { 25 return err 26 } 27 28 if wait == 0 { 29 log.Printf("[DEBUG] Capacity timeout set to 0, skipping capacity waiting.") 30 return nil 31 } 32 33 log.Printf("[DEBUG] Waiting on %s for capacity...", d.Id()) 34 35 return resource.Retry(wait, func() *resource.RetryError { 36 g, err := getAwsAutoscalingGroup(d.Id(), meta.(*AWSClient).autoscalingconn) 37 if err != nil { 38 return resource.NonRetryableError(err) 39 } 40 if g == nil { 41 log.Printf("[INFO] Autoscaling Group %q not found", d.Id()) 42 d.SetId("") 43 return nil 44 } 45 lbis, err := getLBInstanceStates(g, meta) 46 if err != nil { 47 return resource.NonRetryableError(err) 48 } 49 50 haveASG := 0 51 haveELB := 0 52 53 for _, i := range g.Instances { 54 if i.HealthStatus == nil || i.InstanceId == nil || i.LifecycleState == nil { 55 continue 56 } 57 58 if !strings.EqualFold(*i.HealthStatus, "Healthy") { 59 continue 60 } 61 62 if !strings.EqualFold(*i.LifecycleState, "InService") { 63 continue 64 } 65 66 haveASG++ 67 68 inAllLbs := true 69 for _, states := range lbis { 70 state, ok := states[*i.InstanceId] 71 if !ok || !strings.EqualFold(state, "InService") { 72 inAllLbs = false 73 } 74 } 75 if inAllLbs { 76 haveELB++ 77 } 78 } 79 80 satisfied, reason := satisfiedFunc(d, haveASG, haveELB) 81 82 log.Printf("[DEBUG] %q Capacity: %d ASG, %d ELB, satisfied: %t, reason: %q", 83 d.Id(), haveASG, haveELB, satisfied, reason) 84 85 if satisfied { 86 return nil 87 } 88 89 return resource.RetryableError( 90 fmt.Errorf("%q: Waiting up to %s: %s", d.Id(), wait, reason)) 91 }) 92 } 93 94 type capacitySatisfiedFunc func(*schema.ResourceData, int, int) (bool, string) 95 96 // capacitySatisfiedCreate treats all targets as minimums 97 func capacitySatisfiedCreate(d *schema.ResourceData, haveASG, haveELB int) (bool, string) { 98 minASG := d.Get("min_size").(int) 99 if wantASG := d.Get("desired_capacity").(int); wantASG > 0 { 100 minASG = wantASG 101 } 102 if haveASG < minASG { 103 return false, fmt.Sprintf( 104 "Need at least %d healthy instances in ASG, have %d", minASG, haveASG) 105 } 106 minELB := d.Get("min_elb_capacity").(int) 107 if wantELB := d.Get("wait_for_elb_capacity").(int); wantELB > 0 { 108 minELB = wantELB 109 } 110 if haveELB < minELB { 111 return false, fmt.Sprintf( 112 "Need at least %d healthy instances in ELB, have %d", minELB, haveELB) 113 } 114 return true, "" 115 } 116 117 // capacitySatisfiedUpdate only cares about specific targets 118 func capacitySatisfiedUpdate(d *schema.ResourceData, haveASG, haveELB int) (bool, string) { 119 if wantASG := d.Get("desired_capacity").(int); wantASG > 0 { 120 if haveASG != wantASG { 121 return false, fmt.Sprintf( 122 "Need exactly %d healthy instances in ASG, have %d", wantASG, haveASG) 123 } 124 } 125 if wantELB := d.Get("wait_for_elb_capacity").(int); wantELB > 0 { 126 if haveELB != wantELB { 127 return false, fmt.Sprintf( 128 "Need exactly %d healthy instances in ELB, have %d", wantELB, haveELB) 129 } 130 } 131 return true, "" 132 }