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  }