github.com/angdraug/packer@v1.3.2/builder/digitalocean/wait.go (about) 1 package digitalocean 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "time" 8 9 "github.com/digitalocean/godo" 10 ) 11 12 // waitForDropletUnlocked waits for the Droplet to be unlocked to 13 // avoid "pending" errors when making state changes. 14 func waitForDropletUnlocked( 15 client *godo.Client, dropletId int, timeout time.Duration) error { 16 done := make(chan struct{}) 17 defer close(done) 18 19 result := make(chan error, 1) 20 go func() { 21 attempts := 0 22 for { 23 attempts += 1 24 25 log.Printf("[DEBUG] Checking droplet lock state... (attempt: %d)", attempts) 26 droplet, _, err := client.Droplets.Get(context.TODO(), dropletId) 27 if err != nil { 28 result <- err 29 return 30 } 31 32 if !droplet.Locked { 33 result <- nil 34 return 35 } 36 37 // Wait 3 seconds in between 38 time.Sleep(3 * time.Second) 39 40 // Verify we shouldn't exit 41 select { 42 case <-done: 43 // We finished, so just exit the goroutine 44 return 45 default: 46 // Keep going 47 } 48 } 49 }() 50 51 log.Printf("[DEBUG] Waiting for up to %d seconds for droplet to unlock", timeout/time.Second) 52 select { 53 case err := <-result: 54 return err 55 case <-time.After(timeout): 56 return fmt.Errorf( 57 "Timeout while waiting to for droplet to unlock") 58 } 59 } 60 61 // waitForDropletState simply blocks until the droplet is in 62 // a state we expect, while eventually timing out. 63 func waitForDropletState( 64 desiredState string, dropletId int, 65 client *godo.Client, timeout time.Duration) error { 66 done := make(chan struct{}) 67 defer close(done) 68 69 result := make(chan error, 1) 70 go func() { 71 attempts := 0 72 for { 73 attempts += 1 74 75 log.Printf("Checking droplet status... (attempt: %d)", attempts) 76 droplet, _, err := client.Droplets.Get(context.TODO(), dropletId) 77 if err != nil { 78 result <- err 79 return 80 } 81 82 if droplet.Status == desiredState { 83 result <- nil 84 return 85 } 86 87 // Wait 3 seconds in between 88 time.Sleep(3 * time.Second) 89 90 // Verify we shouldn't exit 91 select { 92 case <-done: 93 // We finished, so just exit the goroutine 94 return 95 default: 96 // Keep going 97 } 98 } 99 }() 100 101 log.Printf("Waiting for up to %d seconds for droplet to become %s", timeout/time.Second, desiredState) 102 select { 103 case err := <-result: 104 return err 105 case <-time.After(timeout): 106 err := fmt.Errorf("Timeout while waiting to for droplet to become '%s'", desiredState) 107 return err 108 } 109 } 110 111 // waitForActionState simply blocks until the droplet action is in 112 // a state we expect, while eventually timing out. 113 func waitForActionState( 114 desiredState string, dropletId, actionId int, 115 client *godo.Client, timeout time.Duration) error { 116 done := make(chan struct{}) 117 defer close(done) 118 119 result := make(chan error, 1) 120 go func() { 121 attempts := 0 122 for { 123 attempts += 1 124 125 log.Printf("Checking action status... (attempt: %d)", attempts) 126 action, _, err := client.DropletActions.Get(context.TODO(), dropletId, actionId) 127 if err != nil { 128 result <- err 129 return 130 } 131 132 if action.Status == desiredState { 133 result <- nil 134 return 135 } 136 137 // Wait 3 seconds in between 138 time.Sleep(3 * time.Second) 139 140 // Verify we shouldn't exit 141 select { 142 case <-done: 143 // We finished, so just exit the goroutine 144 return 145 default: 146 // Keep going 147 } 148 } 149 }() 150 151 log.Printf("Waiting for up to %d seconds for action to become %s", timeout/time.Second, desiredState) 152 select { 153 case err := <-result: 154 return err 155 case <-time.After(timeout): 156 err := fmt.Errorf("Timeout while waiting to for action to become '%s'", desiredState) 157 return err 158 } 159 } 160 161 // waitForImageState simply blocks until the image action is in 162 // a state we expect, while eventually timing out. 163 func waitForImageState( 164 desiredState string, imageId, actionId int, 165 client *godo.Client, timeout time.Duration) error { 166 done := make(chan struct{}) 167 defer close(done) 168 169 result := make(chan error, 1) 170 go func() { 171 attempts := 0 172 for { 173 attempts += 1 174 175 log.Printf("Checking action status... (attempt: %d)", attempts) 176 action, _, err := client.ImageActions.Get(context.TODO(), imageId, actionId) 177 if err != nil { 178 result <- err 179 return 180 } 181 182 if action.Status == desiredState { 183 result <- nil 184 return 185 } 186 187 // Wait 3 seconds in between 188 time.Sleep(3 * time.Second) 189 190 // Verify we shouldn't exit 191 select { 192 case <-done: 193 // We finished, so just exit the goroutine 194 return 195 default: 196 // Keep going 197 } 198 } 199 }() 200 201 log.Printf("Waiting for up to %d seconds for image transfer to become %s", timeout/time.Second, desiredState) 202 select { 203 case err := <-result: 204 return err 205 case <-time.After(timeout): 206 err := fmt.Errorf("Timeout while waiting to for image transfer to become '%s'", desiredState) 207 return err 208 } 209 }