github.com/codeherentuk/terraform@v0.11.12-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 }