cloudinit/datasource/datasource.go
Kelsey Hightower 31f61d7531 Use exponential backoff when fetching user-data from an URL.
The user-cloudinit-proc-cmdline systemd unit is responsible for
fetching user-data from various sources during the cloud-init
process. When fetching user-data from an URL datasource we face
a race condition since the network may not be available, which
can cause the job to fail and no further attempts to fetch the
user-data are made.

Eliminate the race condition when fetching user-data from an URL
datasource. Retry the fetch using an exponential backoff until
the user-data is retrieved.

Fixes issue 105.
2014-05-14 23:15:49 -07:00

48 lines
1.0 KiB
Go

package datasource
import (
"io/ioutil"
"log"
"math"
"net/http"
"time"
)
type Datasource interface {
Fetch() ([]byte, error)
Type() string
}
func fetchURL(url string) ([]byte, error) {
resp, err := getWithExponentialBackoff(url)
if err != nil {
return []byte{}, err
}
defer resp.Body.Close()
respBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return respBytes, nil
}
// getWithExponentialBackoff issues a GET to the specified URL. If the
// response is a non-2xx or produces an error, retry the GET forever using
// an exponential backoff.
func getWithExponentialBackoff(url string) (*http.Response, error) {
var err error
var resp *http.Response
for i := 0; ; i++ {
resp, err = http.Get(url)
if err == nil && resp.StatusCode/100 == 2 {
return resp, nil
}
duration := time.Millisecond * time.Duration((math.Pow(float64(2), float64(i)) * 100))
log.Printf("unable to fetch user-data from %s, try again in %s", url, duration)
time.Sleep(duration)
}
return resp, err
}