Merge remote-tracking branch 'upstream/v0.2.0' into update-identity-v2

Conflicts:
	openstack/common/extensions/requests.go
	openstack/identity/v3/tokens/results.go
	openstack/networking/v2/extensions/delegate_test.go
diff --git a/openstack/identity/v3/tokens/results.go b/openstack/identity/v3/tokens/results.go
index 145a43d..e96da51 100644
--- a/openstack/identity/v3/tokens/results.go
+++ b/openstack/identity/v3/tokens/results.go
@@ -1,44 +1,78 @@
 package tokens
 
 import (
+	"net/http"
 	"time"
 
 	"github.com/mitchellh/mapstructure"
 	"github.com/rackspace/gophercloud"
 )
 
-// TokenCreateResult contains the document structure returned from a Create call.
-type TokenCreateResult struct {
-	response map[string]interface{}
-	tokenID  string
+// commonResult is the deferred result of a Create or a Get call.
+type commonResult struct {
+	gophercloud.CommonResult
+
+	// header stores the headers from the original HTTP response because token responses are returned in an X-Subject-Token header.
+	header http.Header
 }
 
-// TokenID retrieves a token generated by a Create call from an token creation response.
-func (r *TokenCreateResult) TokenID() (string, error) {
-	return r.tokenID, nil
-}
-
-// ExpiresAt retrieves the token expiration time.
-func (r *TokenCreateResult) ExpiresAt() (time.Time, error) {
-	type tokenResp struct {
-		ExpiresAt string `mapstructure:"expires_at"`
+// Extract interprets a commonResult as a Token.
+func (r commonResult) Extract() (*Token, error) {
+	if r.Err != nil {
+		return nil, r.Err
 	}
 
-	type response struct {
-		Token tokenResp `mapstructure:"token"`
+	var response struct {
+		Token struct {
+			ExpiresAt string `mapstructure:"expires_at"`
+		} `mapstructure:"token"`
 	}
 
-	var resp response
-	err := mapstructure.Decode(r.response, &resp)
+	var token Token
+
+	// Parse the token itself from the stored headers.
+	token.ID = r.header.Get("X-Subject-Token")
+
+	err := mapstructure.Decode(r.Resp, &response)
 	if err != nil {
-		return time.Time{}, err
+		return nil, err
 	}
 
 	// Attempt to parse the timestamp.
-	ts, err := time.Parse(gophercloud.RFC3339Milli, resp.Token.ExpiresAt)
+	token.ExpiresAt, err = time.Parse(gophercloud.RFC3339Milli, response.Token.ExpiresAt)
 	if err != nil {
-		return time.Time{}, err
+		return nil, err
 	}
 
-	return ts, nil
+	return &token, nil
+}
+
+// CreateResult is the deferred response from a Create call.
+type CreateResult struct {
+	commonResult
+}
+
+// createErr quickly creates a CreateResult that reports an error.
+func createErr(err error) CreateResult {
+	return CreateResult{
+		commonResult: commonResult{
+			CommonResult: gophercloud.CommonResult{Err: err},
+			header:       nil,
+		},
+	}
+}
+
+// GetResult is the deferred response from a Get call.
+type GetResult struct {
+	commonResult
+}
+
+// Token is a string that grants a user access to a controlled set of services in an OpenStack provider.
+// Each Token is valid for a set length of time.
+type Token struct {
+	// ID is the issued token.
+	ID string
+
+	// ExpiresAt is the timestamp at which this token will no longer be accepted.
+	ExpiresAt time.Time
 }