Merge pull request #10055 from fatmcgav/swift_add_version_expire
state/remote/swift: Add support for versioning state file in swift, and expiring objects
This commit is contained in:
commit
8ecc6fda0a
|
@ -11,6 +11,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gophercloud/gophercloud"
|
"github.com/gophercloud/gophercloud"
|
||||||
"github.com/gophercloud/gophercloud/openstack"
|
"github.com/gophercloud/gophercloud/openstack"
|
||||||
|
@ -22,21 +24,24 @@ const TFSTATE_NAME = "tfstate.tf"
|
||||||
|
|
||||||
// SwiftClient implements the Client interface for an Openstack Swift server.
|
// SwiftClient implements the Client interface for an Openstack Swift server.
|
||||||
type SwiftClient struct {
|
type SwiftClient struct {
|
||||||
client *gophercloud.ServiceClient
|
client *gophercloud.ServiceClient
|
||||||
authurl string
|
authurl string
|
||||||
cacert string
|
cacert string
|
||||||
cert string
|
cert string
|
||||||
domainid string
|
domainid string
|
||||||
domainname string
|
domainname string
|
||||||
insecure bool
|
insecure bool
|
||||||
key string
|
key string
|
||||||
password string
|
password string
|
||||||
path string
|
path string
|
||||||
region string
|
region string
|
||||||
tenantid string
|
tenantid string
|
||||||
tenantname string
|
tenantname string
|
||||||
userid string
|
userid string
|
||||||
username string
|
username string
|
||||||
|
archive bool
|
||||||
|
archivepath string
|
||||||
|
expireSecs int
|
||||||
}
|
}
|
||||||
|
|
||||||
func swiftFactory(conf map[string]string) (Client, error) {
|
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
|
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
|
c.insecure = false
|
||||||
raw, ok := conf["insecure"]
|
raw, ok := conf["insecure"]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -252,10 +286,17 @@ func (c *SwiftClient) Put(data []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Creating object %s at path %s", TFSTATE_NAME, c.path)
|
||||||
reader := bytes.NewReader(data)
|
reader := bytes.NewReader(data)
|
||||||
createOpts := objects.CreateOpts{
|
createOpts := objects.CreateOpts{
|
||||||
Content: reader,
|
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)
|
result := objects.Create(c.client, c.path, TFSTATE_NAME, createOpts)
|
||||||
|
|
||||||
return result.Err
|
return result.Err
|
||||||
|
@ -267,7 +308,22 @@ func (c *SwiftClient) Delete() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SwiftClient) ensureContainerExists() 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 {
|
if result.Err != nil {
|
||||||
return result.Err
|
return result.Err
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,4 +80,10 @@ The following configuration options are supported:
|
||||||
authentication. If omitted the `OS_CERT` environment variable is used.
|
authentication. If omitted the `OS_CERT` environment variable is used.
|
||||||
|
|
||||||
* `key` - (Optional) Specify client private key file for SSL client
|
* `key` - (Optional) Specify client private key file for SSL client
|
||||||
authentication. If omitted the `OS_KEY` environment variable is used.
|
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.
|
||||||
|
|
Loading…
Reference in New Issue