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  `