github.com/pdecat/terraform@v0.11.9-beta1/backend/remote-state/swift/client.go (about)

     1  package swift
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/md5"
     6  	"log"
     7  	"os"
     8  
     9  	"github.com/gophercloud/gophercloud"
    10  	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
    11  	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects"
    12  
    13  	"github.com/hashicorp/terraform/state/remote"
    14  )
    15  
    16  const (
    17  	TFSTATE_NAME      = "tfstate.tf"
    18  	TFSTATE_LOCK_NAME = "tfstate.lock"
    19  )
    20  
    21  // RemoteClient implements the Client interface for an Openstack Swift server.
    22  type RemoteClient struct {
    23  	client           *gophercloud.ServiceClient
    24  	container        string
    25  	archive          bool
    26  	archiveContainer string
    27  	expireSecs       int
    28  }
    29  
    30  func (c *RemoteClient) Get() (*remote.Payload, error) {
    31  	log.Printf("[DEBUG] Getting object %s in container %s", TFSTATE_NAME, c.container)
    32  	result := objects.Download(c.client, c.container, TFSTATE_NAME, nil)
    33  
    34  	// Extract any errors from result
    35  	_, err := result.Extract()
    36  
    37  	// 404 response is to be expected if the object doesn't already exist!
    38  	if _, ok := err.(gophercloud.ErrDefault404); ok {
    39  		log.Println("[DEBUG] Object doesn't exist to download.")
    40  		return nil, nil
    41  	}
    42  
    43  	bytes, err := result.ExtractContent()
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	hash := md5.Sum(bytes)
    49  	payload := &remote.Payload{
    50  		Data: bytes,
    51  		MD5:  hash[:md5.Size],
    52  	}
    53  
    54  	return payload, nil
    55  }
    56  
    57  func (c *RemoteClient) Put(data []byte) error {
    58  	if err := c.ensureContainerExists(); err != nil {
    59  		return err
    60  	}
    61  
    62  	log.Printf("[DEBUG] Putting object %s in container %s", TFSTATE_NAME, c.container)
    63  	reader := bytes.NewReader(data)
    64  	createOpts := objects.CreateOpts{
    65  		Content: reader,
    66  	}
    67  
    68  	if c.expireSecs != 0 {
    69  		log.Printf("[DEBUG] ExpireSecs = %d", c.expireSecs)
    70  		createOpts.DeleteAfter = c.expireSecs
    71  	}
    72  
    73  	result := objects.Create(c.client, c.container, TFSTATE_NAME, createOpts)
    74  
    75  	return result.Err
    76  }
    77  
    78  func (c *RemoteClient) Delete() error {
    79  	log.Printf("[DEBUG] Deleting object %s in container %s", TFSTATE_NAME, c.container)
    80  	result := objects.Delete(c.client, c.container, TFSTATE_NAME, nil)
    81  	return result.Err
    82  }
    83  
    84  func (c *RemoteClient) ensureContainerExists() error {
    85  	containerOpts := &containers.CreateOpts{}
    86  
    87  	if c.archive {
    88  		log.Printf("[DEBUG] Creating archive container %s", c.archiveContainer)
    89  		result := containers.Create(c.client, c.archiveContainer, nil)
    90  		if result.Err != nil {
    91  			log.Printf("[DEBUG] Error creating archive container %s: %s", c.archiveContainer, result.Err)
    92  			return result.Err
    93  		}
    94  
    95  		log.Printf("[DEBUG] Enabling Versioning on container %s", c.container)
    96  		containerOpts.VersionsLocation = c.archiveContainer
    97  	}
    98  
    99  	log.Printf("[DEBUG] Creating container %s", c.container)
   100  	result := containers.Create(c.client, c.container, containerOpts)
   101  	if result.Err != nil {
   102  		return result.Err
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  func multiEnv(ks []string) string {
   109  	for _, k := range ks {
   110  		if v := os.Getenv(k); v != "" {
   111  			return v
   112  		}
   113  	}
   114  	return ""
   115  }