@@ -14,10 +14,12 @@ import (
1414 "fmt"
1515 "io"
1616 "log"
17+ "math/big"
1718 "strings"
1819 "time"
1920
2021 compute "google.golang.org/api/compute/v1"
22+ "google.golang.org/api/googleapi"
2123 impersonate "google.golang.org/api/impersonate"
2224 oauth2_svc "google.golang.org/api/oauth2/v2"
2325 "google.golang.org/api/option"
@@ -908,12 +910,31 @@ func (d *driverGCE) ImportOSLoginSSHKey(user, sshPublicKey string, expirationTim
908910 sshKey .ExpirationTimeUsec = * expirationTimeUsec
909911 }
910912
911- resp , err := d .osLoginService .Users .ImportSshPublicKey (parent , sshKey ).Do ()
912- if err != nil {
913- return nil , err
913+ const maxRetries = 10
914+ var err error
915+ for i := 0 ; i < maxRetries ; i ++ {
916+ resp , err := d .osLoginService .Users .ImportSshPublicKey (parent , sshKey ).Do ()
917+ if err == nil {
918+ return resp .LoginProfile , nil
919+ }
920+ // Retry on concurrent mutation errors
921+ if gErr , ok := err .(* googleapi.Error ); ok && gErr .Code == 409 && (i + 1 < maxRetries ) {
922+ log .Printf ("ImportSshPublicKey conflict (try %d/%d): %v" , i + 1 , maxRetries , err )
923+ sleepSecs := retrySleepSeconds ()
924+ // Sleep between 5-15 seconds (randomly chosen) before retry
925+ time .Sleep (time .Duration (sleepSecs ) * time .Second )
926+ } else {
927+ break
928+ }
914929 }
930+ return nil , err
931+ }
915932
916- return resp .LoginProfile , nil
933+ func retrySleepSeconds () int {
934+ // get a big.Int in range [0,10] :
935+ offset , _ := rand .Int (rand .Reader , big .NewInt (11 ))
936+ // convert to int via int64, and add bias:
937+ return int (offset .Int64 ()) + 5
917938}
918939
919940func (d * driverGCE ) DeleteOSLoginSSHKey (user , fingerprint string ) error {
0 commit comments