github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/backend/remote-state/manta/backend_state.go (about) 1 package manta 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "path" 8 "sort" 9 "strings" 10 11 tritonErrors "github.com/joyent/triton-go/errors" 12 "github.com/joyent/triton-go/storage" 13 14 "github.com/hashicorp/terraform/backend" 15 "github.com/hashicorp/terraform/state" 16 "github.com/hashicorp/terraform/state/remote" 17 "github.com/hashicorp/terraform/states" 18 ) 19 20 func (b *Backend) Workspaces() ([]string, error) { 21 result := []string{backend.DefaultStateName} 22 23 objs, err := b.storageClient.Dir().List(context.Background(), &storage.ListDirectoryInput{ 24 DirectoryName: path.Join(mantaDefaultRootStore, b.path), 25 }) 26 if err != nil { 27 if tritonErrors.IsResourceNotFound(err) { 28 return result, nil 29 } 30 return nil, err 31 } 32 33 for _, obj := range objs.Entries { 34 if obj.Type == "directory" && obj.Name != "" { 35 result = append(result, obj.Name) 36 } 37 } 38 39 sort.Strings(result[1:]) 40 return result, nil 41 } 42 43 func (b *Backend) DeleteWorkspace(name string) error { 44 if name == backend.DefaultStateName || name == "" { 45 return fmt.Errorf("can't delete default state") 46 } 47 48 //firstly we need to delete the state file 49 err := b.storageClient.Objects().Delete(context.Background(), &storage.DeleteObjectInput{ 50 ObjectPath: path.Join(mantaDefaultRootStore, b.statePath(name), b.objectName), 51 }) 52 if err != nil { 53 return err 54 } 55 56 //then we need to delete the state folder 57 err = b.storageClient.Objects().Delete(context.Background(), &storage.DeleteObjectInput{ 58 ObjectPath: path.Join(mantaDefaultRootStore, b.statePath(name)), 59 }) 60 if err != nil { 61 return err 62 } 63 64 return nil 65 } 66 67 func (b *Backend) StateMgr(name string) (state.State, error) { 68 return b.stateMgr(name, true) 69 } 70 71 func (b *Backend) StateMgrWithoutCheckVersion(name string) (state.State, error) { 72 return b.stateMgr(name, false) 73 } 74 75 func (b *Backend) stateMgr(name string, checkVersion bool) (state.State, error) { 76 if name == "" { 77 return nil, errors.New("missing state name") 78 } 79 80 client := &RemoteClient{ 81 storageClient: b.storageClient, 82 directoryName: b.statePath(name), 83 keyName: b.objectName, 84 } 85 86 stateMgr := &remote.State{Client: client} 87 88 //if this isn't the default state name, we need to create the object so 89 //it's listed by States. 90 if name != backend.DefaultStateName { 91 // take a lock on this state while we write it 92 lockInfo := state.NewLockInfo() 93 lockInfo.Operation = "init" 94 lockId, err := client.Lock(lockInfo) 95 if err != nil { 96 return nil, fmt.Errorf("failed to lock manta state: %s", err) 97 } 98 99 // Local helper function so we can call it multiple places 100 lockUnlock := func(parent error) error { 101 if err := stateMgr.Unlock(lockId); err != nil { 102 return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err) 103 } 104 return parent 105 } 106 107 // Grab the value 108 if checkVersion { 109 if err := stateMgr.RefreshState(); err != nil { 110 err = lockUnlock(err) 111 return nil, err 112 } 113 } else { 114 if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil { 115 err = lockUnlock(err) 116 return nil, err 117 } 118 } 119 120 // If we have no state, we have to create an empty state 121 if v := stateMgr.State(); v == nil { 122 if err := stateMgr.WriteState(states.NewState()); err != nil { 123 err = lockUnlock(err) 124 return nil, err 125 } 126 if err := stateMgr.PersistState(); err != nil { 127 err = lockUnlock(err) 128 return nil, err 129 } 130 } 131 132 // Unlock, the state should now be initialized 133 if err := lockUnlock(nil); err != nil { 134 return nil, err 135 } 136 137 } 138 139 return stateMgr, nil 140 } 141 142 func (b *Backend) client() *RemoteClient { 143 return &RemoteClient{} 144 } 145 146 func (b *Backend) statePath(name string) string { 147 if name == backend.DefaultStateName { 148 return b.path 149 } 150 151 return path.Join(b.path, name) 152 } 153 154 const errStateUnlock = ` 155 Error unlocking Manta state. Lock ID: %s 156 157 Error: %s 158 159 You may have to force-unlock this state in order to use it again. 160 `