Correctly detect EPERM on crypto/rand.Random.Read failure
Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
020bd0b45f
commit
7e35d16cb6
1 changed files with 22 additions and 9 deletions
25
uuid/uuid.go
25
uuid/uuid.go
|
@ -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
|
|
||||||
// which we backoff and retry.
|
|
||||||
if retries < maxretries {
|
|
||||||
retries++
|
retries++
|
||||||
Loggerf("error generating version 4 uuid, retrying: %v", err)
|
Loggerf("error generating version 4 uuid, retrying: %v", err)
|
||||||
continue
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue