state/remote/swift: Add support for versioning state file in swift, and expiring object after period of time.

Update website docs with changes
This commit is contained in:
Gavin Williams 2016-11-11 15:13:10 +00:00
parent 73e191442d
commit c77ed69a4e
2 changed files with 79 additions and 17 deletions

View File

@ -11,6 +11,8 @@ import (
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack"
@ -37,6 +39,9 @@ type SwiftClient struct {
tenantname string
userid string
username string
archive bool
archivepath string
expireSecs int
}
func swiftFactory(conf map[string]string) (Client, error) {
@ -131,6 +136,35 @@ func (c *SwiftClient) validateConfig(conf map[string]string) (err error) {
}
c.path = path
if archivepath, ok := conf["archive_path"]; ok {
log.Printf("[DEBUG] Archivepath set, enabling object versioning")
c.archive = true
c.archivepath = archivepath
}
if expire, ok := conf["expire_after"]; ok {
log.Printf("[DEBUG] Requested that remote state expires after %s", expire)
if strings.HasSuffix(expire, "d") {
log.Printf("[DEBUG] Got a days expire after duration. Converting to hours")
days, err := strconv.Atoi(expire[:len(expire)-1])
if err != nil {
return fmt.Errorf("Error converting expire_after value %s to int: %s", expire, err)
}
expire = fmt.Sprintf("%dh", days*24)
log.Printf("[DEBUG] Expire after %s hours", expire)
}
expireDur, err := time.ParseDuration(expire)
if err != nil {
log.Printf("[DEBUG] Error parsing duration %s: %s", expire, err)
return fmt.Errorf("Error parsing expire_after duration '%s': %s", expire, err)
}
log.Printf("[DEBUG] Seconds duration = %d", int(expireDur.Seconds()))
c.expireSecs = int(expireDur.Seconds())
}
c.insecure = false
raw, ok := conf["insecure"]
if !ok {
@ -252,10 +286,17 @@ func (c *SwiftClient) Put(data []byte) error {
return err
}
log.Printf("[DEBUG] Creating object %s at path %s", TFSTATE_NAME, c.path)
reader := bytes.NewReader(data)
createOpts := objects.CreateOpts{
Content: reader,
}
if c.expireSecs != 0 {
log.Printf("[DEBUG] ExpireSecs = %d", c.expireSecs)
createOpts.DeleteAfter = c.expireSecs
}
result := objects.Create(c.client, c.path, TFSTATE_NAME, createOpts)
return result.Err
@ -267,7 +308,22 @@ func (c *SwiftClient) Delete() error {
}
func (c *SwiftClient) ensureContainerExists() error {
result := containers.Create(c.client, c.path, nil)
containerOpts := &containers.CreateOpts{}
if c.archive {
log.Printf("[DEBUG] Creating container %s", c.archivepath)
result := containers.Create(c.client, c.archivepath, nil)
if result.Err != nil {
log.Printf("[DEBUG] Error creating container %s: %s", c.archivepath, result.Err)
return result.Err
}
log.Printf("[DEBUG] Enabling Versioning on container %s", c.path)
containerOpts.VersionsLocation = c.archivepath
}
log.Printf("[DEBUG] Creating container %s", c.path)
result := containers.Create(c.client, c.path, containerOpts)
if result.Err != nil {
return result.Err
}

View File

@ -81,3 +81,9 @@ The following configuration options are supported:
* `key` - (Optional) Specify client private key file for SSL client
authentication. If omitted the `OS_KEY` environment variable is used.
* `archive_path` - (Optional) The path to store archived copied of `terraform.tfstate`.
If specified, Swift object versioning is enabled on the container created at `path`.
* `expire_after` - (Optional) How long should the `terraform.tfstate` created at `path`
be retained for? Supported durations: `m` - Minutes, `h` - Hours, `d` - Days.