github.com/sathish1597/hashicorp-terraform@v0.11.12-beta1/backend/remote-state/azure/backend_state.go (about)

     1  package azure
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/Azure/azure-sdk-for-go/storage"
     9  	"github.com/hashicorp/terraform/backend"
    10  	"github.com/hashicorp/terraform/state"
    11  	"github.com/hashicorp/terraform/state/remote"
    12  	"github.com/hashicorp/terraform/terraform"
    13  )
    14  
    15  const (
    16  	// This will be used as directory name, the odd looking colon is simply to
    17  	// reduce the chance of name conflicts with existing objects.
    18  	keyEnvPrefix = "env:"
    19  )
    20  
    21  func (b *Backend) States() ([]string, error) {
    22  	prefix := b.keyName + keyEnvPrefix
    23  	params := storage.ListBlobsParameters{
    24  		Prefix: prefix,
    25  	}
    26  
    27  	container := b.blobClient.GetContainerReference(b.containerName)
    28  	resp, err := container.ListBlobs(params)
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	envs := map[string]struct{}{}
    34  	for _, obj := range resp.Blobs {
    35  		key := obj.Name
    36  		if strings.HasPrefix(key, prefix) {
    37  			name := strings.TrimPrefix(key, prefix)
    38  			// we store the state in a key, not a directory
    39  			if strings.Contains(name, "/") {
    40  				continue
    41  			}
    42  
    43  			envs[name] = struct{}{}
    44  		}
    45  	}
    46  
    47  	result := []string{backend.DefaultStateName}
    48  	for name := range envs {
    49  		result = append(result, name)
    50  	}
    51  	sort.Strings(result[1:])
    52  	return result, nil
    53  }
    54  
    55  func (b *Backend) DeleteState(name string) error {
    56  	if name == backend.DefaultStateName || name == "" {
    57  		return fmt.Errorf("can't delete default state")
    58  	}
    59  
    60  	containerReference := b.blobClient.GetContainerReference(b.containerName)
    61  	blobReference := containerReference.GetBlobReference(b.path(name))
    62  	options := &storage.DeleteBlobOptions{}
    63  
    64  	return blobReference.Delete(options)
    65  }
    66  
    67  func (b *Backend) State(name string) (state.State, error) {
    68  	client := &RemoteClient{
    69  		blobClient:    b.blobClient,
    70  		containerName: b.containerName,
    71  		keyName:       b.path(name),
    72  	}
    73  
    74  	stateMgr := &remote.State{Client: client}
    75  
    76  	//if this isn't the default state name, we need to create the object so
    77  	//it's listed by States.
    78  	if name != backend.DefaultStateName {
    79  		// take a lock on this state while we write it
    80  		lockInfo := state.NewLockInfo()
    81  		lockInfo.Operation = "init"
    82  		lockId, err := client.Lock(lockInfo)
    83  		if err != nil {
    84  			return nil, fmt.Errorf("failed to lock azure state: %s", err)
    85  		}
    86  
    87  		// Local helper function so we can call it multiple places
    88  		lockUnlock := func(parent error) error {
    89  			if err := stateMgr.Unlock(lockId); err != nil {
    90  				return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
    91  			}
    92  			return parent
    93  		}
    94  
    95  		// Grab the value
    96  		if err := stateMgr.RefreshState(); err != nil {
    97  			err = lockUnlock(err)
    98  			return nil, err
    99  		}
   100  
   101  		// If we have no state, we have to create an empty state
   102  		if v := stateMgr.State(); v == nil {
   103  			if err := stateMgr.WriteState(terraform.NewState()); err != nil {
   104  				err = lockUnlock(err)
   105  				return nil, err
   106  			}
   107  			if err := stateMgr.PersistState(); err != nil {
   108  				err = lockUnlock(err)
   109  				return nil, err
   110  			}
   111  		}
   112  
   113  		// Unlock, the state should now be initialized
   114  		if err := lockUnlock(nil); err != nil {
   115  			return nil, err
   116  		}
   117  
   118  	}
   119  
   120  	return stateMgr, nil
   121  }
   122  
   123  func (b *Backend) client() *RemoteClient {
   124  	return &RemoteClient{}
   125  }
   126  
   127  func (b *Backend) path(name string) string {
   128  	if name == backend.DefaultStateName {
   129  		return b.keyName
   130  	}
   131  
   132  	return b.keyName + keyEnvPrefix + name
   133  }
   134  
   135  const errStateUnlock = `
   136  Error unlocking Azure state. Lock ID: %s
   137  
   138  Error: %s
   139  
   140  You may have to force-unlock this state in order to use it again.
   141  `