2015-06-05 21:05:21 +02:00
|
|
|
package remote
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/md5"
|
2016-11-01 12:24:52 +01:00
|
|
|
"crypto/tls"
|
2015-06-05 21:05:21 +02:00
|
|
|
"fmt"
|
2016-11-01 12:24:52 +01:00
|
|
|
"log"
|
|
|
|
"net/http"
|
2015-06-05 21:05:21 +02:00
|
|
|
"os"
|
2016-11-01 12:24:52 +01:00
|
|
|
"strconv"
|
2015-06-05 21:05:21 +02:00
|
|
|
|
2016-11-01 12:24:52 +01:00
|
|
|
"github.com/gophercloud/gophercloud"
|
|
|
|
"github.com/gophercloud/gophercloud/openstack"
|
|
|
|
"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
|
|
|
|
"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects"
|
2015-06-05 21:05:21 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const TFSTATE_NAME = "tfstate.tf"
|
|
|
|
|
|
|
|
// SwiftClient implements the Client interface for an Openstack Swift server.
|
|
|
|
type SwiftClient struct {
|
|
|
|
client *gophercloud.ServiceClient
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
|
|
|
func swiftFactory(conf map[string]string) (Client, error) {
|
|
|
|
client := &SwiftClient{}
|
|
|
|
|
|
|
|
if err := client.validateConfig(conf); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return client, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *SwiftClient) validateConfig(conf map[string]string) (err error) {
|
|
|
|
if val := os.Getenv("OS_AUTH_URL"); val == "" {
|
|
|
|
return fmt.Errorf("missing OS_AUTH_URL environment variable")
|
|
|
|
}
|
|
|
|
if val := os.Getenv("OS_USERNAME"); val == "" {
|
|
|
|
return fmt.Errorf("missing OS_USERNAME environment variable")
|
|
|
|
}
|
|
|
|
if val := os.Getenv("OS_TENANT_NAME"); val == "" {
|
|
|
|
return fmt.Errorf("missing OS_TENANT_NAME environment variable")
|
|
|
|
}
|
|
|
|
if val := os.Getenv("OS_PASSWORD"); val == "" {
|
|
|
|
return fmt.Errorf("missing OS_PASSWORD environment variable")
|
|
|
|
}
|
|
|
|
path, ok := conf["path"]
|
|
|
|
if !ok || path == "" {
|
|
|
|
return fmt.Errorf("missing 'path' configuration")
|
|
|
|
}
|
|
|
|
|
2016-11-01 12:24:52 +01:00
|
|
|
ao := gophercloud.AuthOptions{
|
2015-06-05 21:05:21 +02:00
|
|
|
IdentityEndpoint: os.Getenv("OS_AUTH_URL"),
|
|
|
|
Username: os.Getenv("OS_USERNAME"),
|
|
|
|
TenantName: os.Getenv("OS_TENANT_NAME"),
|
|
|
|
Password: os.Getenv("OS_PASSWORD"),
|
2016-11-01 12:24:52 +01:00
|
|
|
DomainName: os.Getenv("OS_DOMAIN_NAME"),
|
|
|
|
DomainID: os.Getenv("OS_DOMAIN_ID"),
|
|
|
|
}
|
2015-06-05 21:05:21 +02:00
|
|
|
|
2016-11-01 12:24:52 +01:00
|
|
|
provider, err := openstack.NewClient(ao.IdentityEndpoint)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
config := &tls.Config{}
|
|
|
|
insecure := false
|
|
|
|
if insecure_env := os.Getenv("OS_INSECURE"); insecure_env != "" {
|
|
|
|
insecure, err = strconv.ParseBool(insecure_env)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if insecure {
|
|
|
|
log.Printf("[DEBUG] Insecure mode set")
|
|
|
|
config.InsecureSkipVerify = true
|
|
|
|
}
|
|
|
|
|
|
|
|
transport := &http.Transport{Proxy: http.ProxyFromEnvironment, TLSClientConfig: config}
|
|
|
|
provider.HTTPClient.Transport = transport
|
|
|
|
|
|
|
|
err = openstack.Authenticate(provider, ao)
|
2015-06-05 21:05:21 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
c.path = path
|
|
|
|
c.client, err = openstack.NewObjectStorageV1(provider, gophercloud.EndpointOpts{
|
|
|
|
Region: os.Getenv("OS_REGION_NAME"),
|
|
|
|
})
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *SwiftClient) Get() (*Payload, error) {
|
|
|
|
result := objects.Download(c.client, c.path, TFSTATE_NAME, nil)
|
|
|
|
|
2016-11-01 12:24:52 +01:00
|
|
|
// Extract any errors from result
|
|
|
|
_, err := result.Extract()
|
|
|
|
|
|
|
|
// 404 response is to be expected if the object doesn't already exist!
|
|
|
|
if _, ok := err.(gophercloud.ErrDefault404); ok {
|
|
|
|
log.Printf("[DEBUG] Container doesn't exist to download.")
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes, err := result.ExtractContent()
|
2015-06-05 21:05:21 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
hash := md5.Sum(bytes)
|
|
|
|
payload := &Payload{
|
|
|
|
Data: bytes,
|
2015-06-24 07:31:24 +02:00
|
|
|
MD5: hash[:md5.Size],
|
2015-06-05 21:05:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return payload, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *SwiftClient) Put(data []byte) error {
|
|
|
|
if err := c.ensureContainerExists(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
reader := bytes.NewReader(data)
|
2016-11-01 12:24:52 +01:00
|
|
|
createOpts := objects.CreateOpts{
|
|
|
|
Content: reader,
|
|
|
|
}
|
|
|
|
result := objects.Create(c.client, c.path, TFSTATE_NAME, createOpts)
|
2015-06-05 21:05:21 +02:00
|
|
|
|
|
|
|
return result.Err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *SwiftClient) Delete() error {
|
|
|
|
result := objects.Delete(c.client, c.path, TFSTATE_NAME, nil)
|
|
|
|
return result.Err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *SwiftClient) ensureContainerExists() error {
|
|
|
|
result := containers.Create(c.client, c.path, nil)
|
|
|
|
if result.Err != nil {
|
|
|
|
return result.Err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|