diff --git a/builtin/providers/openstack/config.go b/builtin/providers/openstack/config.go index 98d638ce7b..860db0b5d6 100644 --- a/builtin/providers/openstack/config.go +++ b/builtin/providers/openstack/config.go @@ -9,6 +9,7 @@ import ( "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack" + "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth" ) type Config struct { @@ -21,6 +22,7 @@ type Config struct { IdentityEndpoint string Insecure bool Password string + Swauth bool TenantID string TenantName string Token string @@ -95,9 +97,12 @@ func (c *Config) loadAndValidate() error { transport := &http.Transport{Proxy: http.ProxyFromEnvironment, TLSClientConfig: config} client.HTTPClient.Transport = transport - err = openstack.Authenticate(client, ao) - if err != nil { - return err + // If using Swift Authentication, there's no need to validate authentication normally. + if !c.Swauth { + err = openstack.Authenticate(client, ao) + if err != nil { + return err + } } c.osClient = client @@ -134,6 +139,14 @@ func (c *Config) networkingV2Client(region string) (*gophercloud.ServiceClient, } func (c *Config) objectStorageV1Client(region string) (*gophercloud.ServiceClient, error) { + // If Swift Authentication is being used, return a swauth client. + if c.Swauth { + return swauth.NewObjectStorageV1(c.osClient, swauth.AuthOpts{ + User: c.Username, + Key: c.Password, + }) + } + return openstack.NewObjectStorageV1(c.osClient, gophercloud.EndpointOpts{ Region: region, Availability: c.getEndpointType(), diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index e6ef6e32f1..6e7434a94b 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -125,6 +125,13 @@ func Provider() terraform.ResourceProvider { DefaultFunc: schema.EnvDefaultFunc("OS_KEY", ""), Description: descriptions["key"], }, + + "swauth": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("OS_SWAUTH", ""), + Description: descriptions["swauth"], + }, }, ResourcesMap: map[string]*schema.Resource{ @@ -196,6 +203,9 @@ func init() { "cert": "A client certificate to authenticate with.", "key": "A client private key to authenticate with.", + + "swauth": "Use Swift's authentication system instead of Keystone. Only used for\n" + + "interaction with Swift.", } } @@ -210,6 +220,7 @@ func configureProvider(d *schema.ResourceData) (interface{}, error) { IdentityEndpoint: d.Get("auth_url").(string), Insecure: d.Get("insecure").(bool), Password: d.Get("password").(string), + Swauth: d.Get("swauth").(bool), Token: d.Get("token").(string), TenantID: d.Get("tenant_id").(string), TenantName: d.Get("tenant_name").(string), diff --git a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1_test.go b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1_test.go index 9047fa26ee..4e6ef693c7 100644 --- a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1_test.go +++ b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1_test.go @@ -56,22 +56,20 @@ func testAccCheckObjectStorageV1ContainerDestroy(s *terraform.State) error { var testAccObjectStorageV1Container_basic = fmt.Sprintf(` resource "openstack_objectstorage_container_v1" "container_1" { - region = "%s" name = "tf-test-container" metadata { test = "true" } content_type = "application/json" - }`, - OS_REGION_NAME) + } +`) var testAccObjectStorageV1Container_update = fmt.Sprintf(` resource "openstack_objectstorage_container_v1" "container_1" { - region = "%s" name = "tf-test-container" metadata { test = "true" } content_type = "text/plain" - }`, - OS_REGION_NAME) + } +`) diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/requests.go new file mode 100644 index 0000000000..e8589ae0cb --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/requests.go @@ -0,0 +1,70 @@ +package swauth + +import "github.com/gophercloud/gophercloud" + +// AuthOptsBuilder describes struct types that can be accepted by the Auth call. +// The AuthOpts struct in this package does. +type AuthOptsBuilder interface { + ToAuthOptsMap() (map[string]string, error) +} + +// AuthOpts specifies an authentication request. +type AuthOpts struct { + // User is an Swauth-based username in username:tenant format. + User string `h:"X-Auth-User" required:"true"` + // Key is a secret/password to authenticate the User with. + Key string `h:"X-Auth-Key" required:"true"` +} + +// ToAuthOptsMap formats an AuthOpts structure into a request body. +func (opts AuthOpts) ToAuthOptsMap() (map[string]string, error) { + return gophercloud.BuildHeaders(opts) +} + +// Auth performs an authentication request for a Swauth-based user. +func Auth(c *gophercloud.ProviderClient, opts AuthOptsBuilder) (r GetAuthResult) { + h := make(map[string]string) + + if opts != nil { + headers, err := opts.ToAuthOptsMap() + if err != nil { + r.Err = err + return + } + + for k, v := range headers { + h[k] = v + } + } + + resp, err := c.Request("GET", getURL(c), &gophercloud.RequestOpts{ + MoreHeaders: h, + OkCodes: []int{200}, + }) + + if resp != nil { + r.Header = resp.Header + } + + r.Err = err + + return r +} + +// NewObjectStorageV1 creates a Swauth-authenticated *gophercloud.ServiceClient +// client that can issue ObjectStorage-based API calls. +func NewObjectStorageV1(pc *gophercloud.ProviderClient, authOpts AuthOpts) (*gophercloud.ServiceClient, error) { + auth, err := Auth(pc, authOpts).Extract() + if err != nil { + return nil, err + } + + swiftClient := &gophercloud.ServiceClient{ + ProviderClient: pc, + Endpoint: gophercloud.NormalizeURL(auth.StorageURL), + } + + swiftClient.TokenID = auth.Token + + return swiftClient, nil +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/results.go new file mode 100644 index 0000000000..294c43c07c --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/results.go @@ -0,0 +1,27 @@ +package swauth + +import ( + "github.com/gophercloud/gophercloud" +) + +// GetAuthResult temporarily contains the response from a Swauth +// authentication call. +type GetAuthResult struct { + gophercloud.HeaderResult +} + +// AuthResult contains the authentication information from a Swauth +// authentication request. +type AuthResult struct { + Token string `json:"X-Auth-Token"` + StorageURL string `json:"X-Storage-Url"` + CDNURL string `json:"X-CDN-Management-Url"` +} + +// Extract is a method that attempts to interpret any Swauth authentication +// response as a AuthResult struct. +func (r GetAuthResult) Extract() (*AuthResult, error) { + var s *AuthResult + err := r.ExtractInto(&s) + return s, err +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/urls.go b/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/urls.go new file mode 100644 index 0000000000..a30cabd60e --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth/urls.go @@ -0,0 +1,7 @@ +package swauth + +import "github.com/gophercloud/gophercloud" + +func getURL(c *gophercloud.ProviderClient) string { + return c.IdentityBase + "auth/v1.0" +} diff --git a/vendor/vendor.json b/vendor/vendor.json index ee9123be05..124e542e86 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1377,6 +1377,12 @@ "revision": "45720eeefeeeba03b2d7da500297ec68eeee51af", "revisionTime": "2016-10-31T15:28:56Z" }, + { + "checksumSHA1": "roxPPVwS2CjJhf0CApHNQxAX7EA=", + "path": "github.com/gophercloud/gophercloud/openstack/objectstorage/v1/swauth", + "revision": "d5eda9707e146108e4d424062b602fd97a71c2e6", + "revisionTime": "2016-11-14T18:28:31Z" + }, { "checksumSHA1": "TDOZnaS0TO0NirpxV1QwPerAQTY=", "path": "github.com/gophercloud/gophercloud/openstack/utils", diff --git a/website/source/docs/providers/openstack/index.html.markdown b/website/source/docs/providers/openstack/index.html.markdown index 9711cfbb2b..8ece031493 100644 --- a/website/source/docs/providers/openstack/index.html.markdown +++ b/website/source/docs/providers/openstack/index.html.markdown @@ -86,6 +86,13 @@ The following arguments are supported: service catalog. It can be set using the OS_ENDPOINT_TYPE environment variable. If not set, public endpoints is used. +* `swauth` - (Optional) Set to `true` to authenticate against Swauth, a + Swift-native authentication system. If omitted, the `OS_SWAUTH` environment + variable is used. You must also set `username` to the Swauth/Swift username + such as `username:project`. Set the `password` to the Swauth/Swift key. + Finally, set `auth_url` as the location of the Swift service. Note that this + will only work when used with the OpenStack Object Storage resources. + ## Rackspace Compatibility Using this OpenStack provider with Rackspace is not supported and not