openstack errors
diff --git a/openstack/auth_env.go b/openstack/auth_env.go
index 41e41e4..2309783 100644
--- a/openstack/auth_env.go
+++ b/openstack/auth_env.go
@@ -1,7 +1,6 @@
package openstack
import (
- "fmt"
"os"
"github.com/gophercloud/gophercloud"
@@ -9,14 +8,6 @@
var nilOptions = gophercloud.AuthOptions{}
-// ErrNoAuthUrl, ErrNoUsername, and ErrNoPassword errors indicate of the required OS_AUTH_URL, OS_USERNAME, or OS_PASSWORD
-// environment variables, respectively, remain undefined. See the AuthOptions() function for more details.
-var (
- ErrNoAuthURL = fmt.Errorf("Environment variable OS_AUTH_URL needs to be set.")
- ErrNoUsername = fmt.Errorf("Environment variable OS_USERNAME needs to be set.")
- ErrNoPassword = fmt.Errorf("Environment variable OS_PASSWORD needs to be set.")
-)
-
// AuthOptionsFromEnv fills out an identity.AuthOptions structure with the settings found on the various OpenStack
// OS_* environment variables. The following variables provide sources of truth: OS_AUTH_URL, OS_USERNAME,
// OS_PASSWORD, OS_TENANT_ID, and OS_TENANT_NAME. Of these, OS_USERNAME, OS_PASSWORD, and OS_AUTH_URL must
@@ -32,15 +23,24 @@
domainName := os.Getenv("OS_DOMAIN_NAME")
if authURL == "" {
- return nilOptions, ErrNoAuthURL
+ err := &ErrNoAuthURL{}
+ err.Function = "openstack.AuthOptionsFromEnv"
+ err.Argument = "authURL"
+ return nilOptions, err
}
if username == "" && userID == "" {
- return nilOptions, ErrNoUsername
+ err := &ErrNoUsername{}
+ err.Function = "openstack.AuthOptionsFromEnv"
+ err.Argument = "username"
+ return nilOptions, err
}
if password == "" {
- return nilOptions, ErrNoPassword
+ err := &ErrNoPassword{}
+ err.Function = "openstack.AuthOptionsFromEnv"
+ err.Argument = "password"
+ return nilOptions, err
}
ao := gophercloud.AuthOptions{
diff --git a/openstack/client.go b/openstack/client.go
index c40922a..be08be0 100644
--- a/openstack/client.go
+++ b/openstack/client.go
@@ -3,7 +3,6 @@
import (
"fmt"
"net/url"
- "strings"
"github.com/gophercloud/gophercloud"
tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens"
@@ -91,7 +90,11 @@
}
func v2auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions) error {
- v2Client := NewIdentityV2(client)
+ v2Client, err := NewIdentityV2(client, eo)
+ if err != nil {
+ return err
+ }
+
if endpoint != "" {
v2Client.Endpoint = endpoint
}
@@ -129,7 +132,11 @@
func v3auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions) error {
// Override the generated service endpoint with the one returned by the version endpoint.
- v3Client := NewIdentityV3(client)
+ v3Client, err := NewIdentityV3(client, eo)
+ if err != nil {
+ return err
+ }
+
if endpoint != "" {
v3Client.Endpoint = endpoint
}
@@ -180,57 +187,23 @@
}
// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service.
-func NewIdentityV2(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
+func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
v2Endpoint := client.IdentityBase + "v2.0/"
return &gophercloud.ServiceClient{
ProviderClient: client,
Endpoint: v2Endpoint,
- }
+ }, nil
}
// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service.
-func NewIdentityV3(client *gophercloud.ProviderClient) *gophercloud.ServiceClient {
+func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
v3Endpoint := client.IdentityBase + "v3/"
return &gophercloud.ServiceClient{
ProviderClient: client,
Endpoint: v3Endpoint,
- }
-}
-
-func NewIdentityAdminV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
- eo.ApplyDefaults("identity")
- eo.Availability = gophercloud.AvailabilityAdmin
-
- url, err := client.EndpointLocator(eo)
- if err != nil {
- return nil, err
- }
-
- // Force using v2 API
- if strings.Contains(url, "/v3") {
- url = strings.Replace(url, "/v3", "/v2.0", -1)
- }
-
- return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
-}
-
-func NewIdentityAdminV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
- eo.ApplyDefaults("identity")
- eo.Availability = gophercloud.AvailabilityAdmin
-
- url, err := client.EndpointLocator(eo)
- if err != nil {
- return nil, err
- }
-
- // Force using v3 API
- if strings.Contains(url, "/v2.0") {
- url = strings.Replace(url, "/v2.0", "/v3", -1)
- }
-
- return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
+ }, nil
}
// NewObjectStorageV1 creates a ServiceClient that may be used with the v1 object storage package.
diff --git a/openstack/endpoint_location.go b/openstack/endpoint_location.go
index 1184b34..70f6800 100644
--- a/openstack/endpoint_location.go
+++ b/openstack/endpoint_location.go
@@ -1,8 +1,6 @@
package openstack
import (
- "fmt"
-
"github.com/gophercloud/gophercloud"
tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens"
tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
@@ -29,7 +27,10 @@
// Report an error if the options were ambiguous.
if len(endpoints) > 1 {
- return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints)
+ err := &ErrMultipleMatchingEndpointsV2{}
+ err.Endpoints = endpoints
+ err.Function = "openstack.V2EndpointURL"
+ return "", err
}
// Extract the appropriate URL from the matching Endpoint.
@@ -42,12 +43,18 @@
case gophercloud.AvailabilityAdmin:
return gophercloud.NormalizeURL(endpoint.AdminURL), nil
default:
- return "", fmt.Errorf("Unexpected availability in endpoint query: %s", opts.Availability)
+ err := &ErrInvalidAvailabilityProvided{}
+ err.Function = "openstack.V2EndpointURL"
+ err.Argument = "Availability"
+ err.Value = opts.Availability
+ return "", err
}
}
// Report an error if there were no matching endpoints.
- return "", &gophercloud.ErrEndpointNotFound{}
+ err := &gophercloud.ErrEndpointNotFound{}
+ err.Function = "openstack.V2EndpointURL"
+ return "", err
}
// V3EndpointURL discovers the endpoint URL for a specific service from a Catalog acquired
@@ -66,7 +73,10 @@
if opts.Availability != gophercloud.AvailabilityAdmin &&
opts.Availability != gophercloud.AvailabilityPublic &&
opts.Availability != gophercloud.AvailabilityInternal {
- return "", fmt.Errorf("Unexpected availability in endpoint query: %s", opts.Availability)
+ err := &ErrInvalidAvailabilityProvided{}
+ err.Function = "openstack.V3EndpointURL"
+ err.Argument = "Availability"
+ err.Value = opts.Availability
}
if (opts.Availability == gophercloud.Availability(endpoint.Interface)) &&
(opts.Region == "" || endpoint.Region == opts.Region) {
@@ -78,7 +88,10 @@
// Report an error if the options were ambiguous.
if len(endpoints) > 1 {
- return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints)
+ err := &ErrMultipleMatchingEndpointsV3{}
+ err.Endpoints = endpoints
+ err.Function = "openstack.V3EndpointURL"
+ return "", err
}
// Extract the URL from the matching Endpoint.
@@ -87,5 +100,7 @@
}
// Report an error if there were no matching endpoints.
- return "", &gophercloud.ErrEndpointNotFound{}
+ err := &gophercloud.ErrEndpointNotFound{}
+ err.Function = "openstack.V3EndpointURL"
+ return "", err
}
diff --git a/openstack/errors.go b/openstack/errors.go
new file mode 100644
index 0000000..8467200
--- /dev/null
+++ b/openstack/errors.go
@@ -0,0 +1,71 @@
+package openstack
+
+import (
+ "fmt"
+
+ "github.com/gophercloud/gophercloud"
+ tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens"
+ tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
+)
+
+// ErrEndpointNotFound is the error when no suitable endpoint can be found
+// in the user's catalog
+type ErrEndpointNotFound struct{ *gophercloud.BaseError }
+
+func (e ErrEndpointNotFound) Error() string {
+ return "No suitable endpoint could be found in the service catalog."
+}
+
+// ErrInvalidAvailabilityProvided is the error when an invalid endpoint
+// availability is provided
+type ErrInvalidAvailabilityProvided struct{ *gophercloud.ErrInvalidInput }
+
+func (e ErrInvalidAvailabilityProvided) Error() string {
+ return "Unexpected availability in endpoint query"
+}
+
+// ErrMultipleMatchingEndpointsV2 is the error when more than one endpoint
+// for the given options is found in the v2 catalog
+type ErrMultipleMatchingEndpointsV2 struct {
+ *gophercloud.BaseError
+ Endpoints []tokens2.Endpoint
+}
+
+func (e *ErrMultipleMatchingEndpointsV2) Error() string {
+ return fmt.Sprintf("Discovered %d matching endpoints: %#v", len(e.Endpoints), e.Endpoints)
+}
+
+// ErrMultipleMatchingEndpointsV3 is the error when more than one endpoint
+// for the given options is found in the v3 catalog
+type ErrMultipleMatchingEndpointsV3 struct {
+ *gophercloud.BaseError
+ Endpoints []tokens3.Endpoint
+}
+
+func (e *ErrMultipleMatchingEndpointsV3) Error() string {
+ return fmt.Sprintf("Discovered %d matching endpoints: %#v", len(e.Endpoints), e.Endpoints)
+}
+
+// ErrNoAuthURL is the error when the OS_AUTH_URL environment variable is not
+// found
+type ErrNoAuthURL struct{ *gophercloud.ErrInvalidInput }
+
+func (e *ErrNoAuthURL) Error() string {
+ return "Environment variable OS_AUTH_URL needs to be set."
+}
+
+// ErrNoUsername is the error when the OS_USERNAME environment variable is not
+// found
+type ErrNoUsername struct{ *gophercloud.ErrInvalidInput }
+
+func (e *ErrNoUsername) Error() string {
+ return "Environment variable OS_USERNAME needs to be set."
+}
+
+// ErrNoPassword is the error when the OS_PASSWORD environment variable is not
+// found
+type ErrNoPassword struct{ *gophercloud.ErrInvalidInput }
+
+func (e *ErrNoPassword) Error() string {
+ return "Environment variable OS_PASSWORD needs to be set."
+}