Merge pull request #636 from stevvooe/uuid-generate-detect-eperm

Correctly detect EPERM on crypto/rand.Random.Read failure
This commit is contained in:
Stephen Day 2015-06-16 16:39:18 -07:00
commit 25f9e314d2

View file

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"os"
"syscall" "syscall"
"time" "time"
) )
@ -61,19 +62,15 @@ func Generate() (u UUID) {
_, err := io.ReadFull(rand.Reader, u[:]) _, err := io.ReadFull(rand.Reader, u[:])
if err != nil { if err != nil {
if err == syscall.EPERM { if retryOnError(err) && retries < maxretries {
// EPERM represents an entropy pool exhaustion, a condition under retries++
// which we backoff and retry. Loggerf("error generating version 4 uuid, retrying: %v", err)
if retries < maxretries { continue
retries++
Loggerf("error generating version 4 uuid, retrying: %v", err)
continue
}
} }
// Any other errors represent a system problem. What did someone // Any other errors represent a system problem. What did someone
// do to /dev/urandom? // do to /dev/urandom?
panic(fmt.Errorf("error reading random number generator, retried for %v: %v", totalBackoff, err)) panic(fmt.Errorf("error reading random number generator, retried for %v: %v", totalBackoff.String(), err))
} }
break break
@ -110,3 +107,19 @@ func Parse(s string) (u UUID, err error) {
func (u UUID) String() string { func (u UUID) String() string {
return fmt.Sprintf(format, u[:4], u[4:6], u[6:8], u[8:10], u[10:]) return fmt.Sprintf(format, u[:4], u[4:6], u[6:8], u[8:10], u[10:])
} }
// retryOnError tries to detect whether or not retrying would be fruitful.
func retryOnError(err error) bool {
switch err := err.(type) {
case *os.PathError:
return retryOnError(err.Err) // unpack the target error
case syscall.Errno:
if err == syscall.EPERM {
// EPERM represents an entropy pool exhaustion, a condition under
// which we backoff and retry.
return true
}
}
return false
}