github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/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() error { 36 g, err := getAwsAutoscalingGroup(d, meta) 37 if err != nil { 38 return resource.RetryError{Err: err} 39 } 40 if g == nil { 41 return nil 42 } 43 lbis, err := getLBInstanceStates(g, meta) 44 if err != nil { 45 return resource.RetryError{Err: err} 46 } 47 48 haveASG := 0 49 haveELB := 0 50 51 for _, i := range g.Instances { 52 if i.HealthStatus == nil || i.InstanceId == nil || i.LifecycleState == nil { 53 continue 54 } 55 56 if !strings.EqualFold(*i.HealthStatus, "Healthy") { 57 continue 58 } 59 60 if !strings.EqualFold(*i.LifecycleState, "InService") { 61 continue 62 } 63 64 haveASG++ 65 66 inAllLbs := true 67 for _, states := range lbis { 68 state, ok := states[*i.InstanceId] 69 if !ok || !strings.EqualFold(state, "InService") { 70 inAllLbs = false 71 } 72 } 73 if inAllLbs { 74 haveELB++ 75 } 76 } 77 78 satisfied, reason := satisfiedFunc(d, haveASG, haveELB) 79 80 log.Printf("[DEBUG] %q Capacity: %d ASG, %d ELB, satisfied: %t, reason: %q", 81 d.Id(), haveASG, haveELB, satisfied, reason) 82 83 if satisfied { 84 return nil 85 } 86 87 return fmt.Errorf("%q: Waiting up to %s: %s", d.Id(), wait, reason) 88 }) 89 } 90 91 type capacitySatisfiedFunc func(*schema.ResourceData, int, int) (bool, string) 92 93 // capacitySatifiedCreate treats all targets as minimums 94 func capacitySatifiedCreate(d *schema.ResourceData, haveASG, haveELB int) (bool, string) { 95 minASG := d.Get("min_size").(int) 96 if wantASG := d.Get("desired_capacity").(int); wantASG > 0 { 97 minASG = wantASG 98 } 99 if haveASG < minASG { 100 return false, fmt.Sprintf( 101 "Need at least %d healthy instances in ASG, have %d", minASG, haveASG) 102 } 103 minELB := d.Get("min_elb_capacity").(int) 104 if wantELB := d.Get("wait_for_elb_capacity").(int); wantELB > 0 { 105 minELB = wantELB 106 } 107 if haveELB < minELB { 108 return false, fmt.Sprintf( 109 "Need at least %d healthy instances in ELB, have %d", minELB, haveELB) 110 } 111 return true, "" 112 } 113 114 // capacitySatifiedUpdate only cares about specific targets 115 func capacitySatifiedUpdate(d *schema.ResourceData, haveASG, haveELB int) (bool, string) { 116 if wantASG := d.Get("desired_capacity").(int); wantASG > 0 { 117 if haveASG != wantASG { 118 return false, fmt.Sprintf( 119 "Need exactly %d healthy instances in ASG, have %d", wantASG, haveASG) 120 } 121 } 122 if wantELB := d.Get("wait_for_elb_capacity").(int); wantELB > 0 { 123 if haveELB != wantELB { 124 return false, fmt.Sprintf( 125 "Need exactly %d healthy instances in ELB, have %d", wantELB, haveELB) 126 } 127 } 128 return true, "" 129 }