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