github.com/hugorut/terraform@v1.1.3/src/backend/remote-state/pg/backend_state.go (about) 1 package pg 2 3 import ( 4 "fmt" 5 6 "github.com/hugorut/terraform/src/backend" 7 "github.com/hugorut/terraform/src/states" 8 "github.com/hugorut/terraform/src/states/remote" 9 "github.com/hugorut/terraform/src/states/statemgr" 10 ) 11 12 func (b *Backend) Workspaces() ([]string, error) { 13 query := `SELECT name FROM %s.%s WHERE name != 'default' ORDER BY name` 14 rows, err := b.db.Query(fmt.Sprintf(query, b.schemaName, statesTableName)) 15 if err != nil { 16 return nil, err 17 } 18 defer rows.Close() 19 20 result := []string{ 21 backend.DefaultStateName, 22 } 23 24 for rows.Next() { 25 var name string 26 if err := rows.Scan(&name); err != nil { 27 return nil, err 28 } 29 result = append(result, name) 30 } 31 if err := rows.Err(); err != nil { 32 return nil, err 33 } 34 35 return result, nil 36 } 37 38 func (b *Backend) DeleteWorkspace(name string) error { 39 if name == backend.DefaultStateName || name == "" { 40 return fmt.Errorf("can't delete default state") 41 } 42 43 query := `DELETE FROM %s.%s WHERE name = $1` 44 _, err := b.db.Exec(fmt.Sprintf(query, b.schemaName, statesTableName), name) 45 if err != nil { 46 return err 47 } 48 49 return nil 50 } 51 52 func (b *Backend) StateMgr(name string) (statemgr.Full, error) { 53 // Build the state client 54 var stateMgr statemgr.Full = &remote.State{ 55 Client: &RemoteClient{ 56 Client: b.db, 57 Name: name, 58 SchemaName: b.schemaName, 59 }, 60 } 61 62 // Check to see if this state already exists. 63 // If the state doesn't exist, we have to assume this 64 // is a normal create operation, and take the lock at that point. 65 existing, err := b.Workspaces() 66 if err != nil { 67 return nil, err 68 } 69 70 exists := false 71 for _, s := range existing { 72 if s == name { 73 exists = true 74 break 75 } 76 } 77 78 // Grab a lock, we use this to write an empty state if one doesn't 79 // exist already. We have to write an empty state as a sentinel value 80 // so Workspaces() knows it exists. 81 if !exists { 82 lockInfo := statemgr.NewLockInfo() 83 lockInfo.Operation = "init" 84 lockId, err := stateMgr.Lock(lockInfo) 85 if err != nil { 86 return nil, fmt.Errorf("failed to lock state in Postgres: %s", err) 87 } 88 89 // Local helper function so we can call it multiple places 90 lockUnlock := func(parent error) error { 91 if err := stateMgr.Unlock(lockId); err != nil { 92 return fmt.Errorf(`error unlocking Postgres state: %s`, err) 93 } 94 return parent 95 } 96 97 if v := stateMgr.State(); v == nil { 98 if err := stateMgr.WriteState(states.NewState()); err != nil { 99 err = lockUnlock(err) 100 return nil, err 101 } 102 if err := stateMgr.PersistState(); err != nil { 103 err = lockUnlock(err) 104 return nil, err 105 } 106 } 107 108 // Unlock, the state should now be initialized 109 if err := lockUnlock(nil); err != nil { 110 return nil, err 111 } 112 } 113 114 return stateMgr, nil 115 }