github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/state/state.go (about) 1 package state 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "os/user" 8 "time" 9 10 uuid "github.com/hashicorp/go-uuid" 11 12 "github.com/hashicorp/terraform/states/statemgr" 13 "github.com/hashicorp/terraform/version" 14 ) 15 16 // State is a deprecated alias for statemgr.Full 17 type State = statemgr.Full 18 19 // StateReader is a deprecated alias for statemgr.Reader 20 type StateReader = statemgr.Reader 21 22 // StateWriter is a deprecated alias for statemgr.Writer 23 type StateWriter = statemgr.Writer 24 25 // StateRefresher is a deprecated alias for statemgr.Refresher 26 type StateRefresher = statemgr.Refresher 27 28 // StatePersister is a deprecated alias for statemgr.Persister 29 type StatePersister = statemgr.Persister 30 31 // Locker is a deprecated alias for statemgr.Locker 32 type Locker = statemgr.Locker 33 34 // test hook to verify that LockWithContext has attempted a lock 35 var postLockHook func() 36 37 // Lock the state, using the provided context for timeout and cancellation. 38 // This backs off slightly to an upper limit. 39 func LockWithContext(ctx context.Context, s State, info *LockInfo) (string, error) { 40 delay := time.Second 41 maxDelay := 16 * time.Second 42 for { 43 id, err := s.Lock(info) 44 if err == nil { 45 return id, nil 46 } 47 48 le, ok := err.(*LockError) 49 if !ok { 50 // not a lock error, so we can't retry 51 return "", err 52 } 53 54 if le == nil || le.Info == nil || le.Info.ID == "" { 55 // If we dont' have a complete LockError, there's something wrong with the lock 56 return "", err 57 } 58 59 if postLockHook != nil { 60 postLockHook() 61 } 62 63 // there's an existing lock, wait and try again 64 select { 65 case <-ctx.Done(): 66 // return the last lock error with the info 67 return "", err 68 case <-time.After(delay): 69 if delay < maxDelay { 70 delay *= 2 71 } 72 } 73 } 74 } 75 76 // Generate a LockInfo structure, populating the required fields. 77 func NewLockInfo() *LockInfo { 78 id, err := uuid.GenerateUUID() 79 if err != nil { 80 // this of course shouldn't happen 81 panic(err) 82 } 83 84 // don't error out on user and hostname, as we don't require them 85 userName := "" 86 if userInfo, err := user.Current(); err == nil { 87 userName = userInfo.Username 88 } 89 host, _ := os.Hostname() 90 91 info := &LockInfo{ 92 ID: id, 93 Who: fmt.Sprintf("%s@%s", userName, host), 94 Version: version.Version, 95 Created: time.Now().UTC(), 96 } 97 return info 98 } 99 100 // LockInfo is a deprecated lias for statemgr.LockInfo 101 type LockInfo = statemgr.LockInfo 102 103 // LockError is a deprecated alias for statemgr.LockError 104 type LockError = statemgr.LockError