Move deps from _workspace/ to vendor/

godep restore
pushd $GOPATH/src/github.com/appc/spec
git co master
popd
go get go4.org/errorutil
rm -rf Godeps
godep save ./...
git add vendor
git add -f $(git ls-files --other vendor/)
git co -- Godeps/LICENSES Godeps/.license_file_state Godeps/OWNERS
This commit is contained in:
Tim Hockin
2016-05-08 20:30:21 -07:00
parent 899f9b4e31
commit 3c0c5ed4e0
4400 changed files with 16739 additions and 376 deletions

View File

@@ -0,0 +1,5 @@
// Package tokens provides information and interaction with the token API
// resource for the OpenStack Identity service.
// For more information, see:
// http://developer.openstack.org/api-ref-identity-v2.html#identity-auth-v2
package tokens

View File

@@ -0,0 +1,30 @@
package tokens
import (
"errors"
"fmt"
)
var (
// ErrUserIDProvided is returned if you attempt to authenticate with a UserID.
ErrUserIDProvided = unacceptedAttributeErr("UserID")
// ErrAPIKeyProvided is returned if you attempt to authenticate with an APIKey.
ErrAPIKeyProvided = unacceptedAttributeErr("APIKey")
// ErrDomainIDProvided is returned if you attempt to authenticate with a DomainID.
ErrDomainIDProvided = unacceptedAttributeErr("DomainID")
// ErrDomainNameProvided is returned if you attempt to authenticate with a DomainName.
ErrDomainNameProvided = unacceptedAttributeErr("DomainName")
// ErrUsernameRequired is returned if you attempt to authenticate without a Username.
ErrUsernameRequired = errors.New("You must supply a Username in your AuthOptions.")
// ErrPasswordRequired is returned if you don't provide a password.
ErrPasswordRequired = errors.New("Please supply a Password in your AuthOptions.")
)
func unacceptedAttributeErr(attribute string) error {
return fmt.Errorf("The base Identity V2 API does not accept authentication by %s", attribute)
}

View File

@@ -0,0 +1,195 @@
// +build fixtures
package tokens
import (
"fmt"
"net/http"
"testing"
"time"
"github.com/rackspace/gophercloud/openstack/identity/v2/tenants"
th "github.com/rackspace/gophercloud/testhelper"
thclient "github.com/rackspace/gophercloud/testhelper/client"
)
// ExpectedToken is the token that should be parsed from TokenCreationResponse.
var ExpectedToken = &Token{
ID: "aaaabbbbccccdddd",
ExpiresAt: time.Date(2014, time.January, 31, 15, 30, 58, 0, time.UTC),
Tenant: tenants.Tenant{
ID: "fc394f2ab2df4114bde39905f800dc57",
Name: "test",
Description: "There are many tenants. This one is yours.",
Enabled: true,
},
}
// ExpectedServiceCatalog is the service catalog that should be parsed from TokenCreationResponse.
var ExpectedServiceCatalog = &ServiceCatalog{
Entries: []CatalogEntry{
CatalogEntry{
Name: "inscrutablewalrus",
Type: "something",
Endpoints: []Endpoint{
Endpoint{
PublicURL: "http://something0:1234/v2/",
Region: "region0",
},
Endpoint{
PublicURL: "http://something1:1234/v2/",
Region: "region1",
},
},
},
CatalogEntry{
Name: "arbitrarypenguin",
Type: "else",
Endpoints: []Endpoint{
Endpoint{
PublicURL: "http://else0:4321/v3/",
Region: "region0",
},
},
},
},
}
// ExpectedUser is the token that should be parsed from TokenGetResponse.
var ExpectedUser = &User{
ID: "a530fefc3d594c4ba2693a4ecd6be74e",
Name: "apiserver",
Roles: []Role{{"member"}, {"service"}},
UserName: "apiserver",
}
// TokenCreationResponse is a JSON response that contains ExpectedToken and ExpectedServiceCatalog.
const TokenCreationResponse = `
{
"access": {
"token": {
"issued_at": "2014-01-30T15:30:58.000000Z",
"expires": "2014-01-31T15:30:58Z",
"id": "aaaabbbbccccdddd",
"tenant": {
"description": "There are many tenants. This one is yours.",
"enabled": true,
"id": "fc394f2ab2df4114bde39905f800dc57",
"name": "test"
}
},
"serviceCatalog": [
{
"endpoints": [
{
"publicURL": "http://something0:1234/v2/",
"region": "region0"
},
{
"publicURL": "http://something1:1234/v2/",
"region": "region1"
}
],
"type": "something",
"name": "inscrutablewalrus"
},
{
"endpoints": [
{
"publicURL": "http://else0:4321/v3/",
"region": "region0"
}
],
"type": "else",
"name": "arbitrarypenguin"
}
]
}
}
`
// TokenGetResponse is a JSON response that contains ExpectedToken and ExpectedUser.
const TokenGetResponse = `
{
"access": {
"token": {
"issued_at": "2014-01-30T15:30:58.000000Z",
"expires": "2014-01-31T15:30:58Z",
"id": "aaaabbbbccccdddd",
"tenant": {
"description": "There are many tenants. This one is yours.",
"enabled": true,
"id": "fc394f2ab2df4114bde39905f800dc57",
"name": "test"
}
},
"serviceCatalog": [],
"user": {
"id": "a530fefc3d594c4ba2693a4ecd6be74e",
"name": "apiserver",
"roles": [
{
"name": "member"
},
{
"name": "service"
}
],
"roles_links": [],
"username": "apiserver"
}
}
}`
// HandleTokenPost expects a POST against a /tokens handler, ensures that the request body has been
// constructed properly given certain auth options, and returns the result.
func HandleTokenPost(t *testing.T, requestJSON string) {
th.Mux.HandleFunc("/tokens", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
th.TestHeader(t, r, "Content-Type", "application/json")
th.TestHeader(t, r, "Accept", "application/json")
if requestJSON != "" {
th.TestJSONRequest(t, r, requestJSON)
}
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, TokenCreationResponse)
})
}
// HandleTokenGet expects a Get against a /tokens handler, ensures that the request body has been
// constructed properly given certain auth options, and returns the result.
func HandleTokenGet(t *testing.T, token string) {
th.Mux.HandleFunc("/tokens/"+token, func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "Accept", "application/json")
th.TestHeader(t, r, "X-Auth-Token", thclient.TokenID)
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, TokenGetResponse)
})
}
// IsSuccessful ensures that a CreateResult was successful and contains the correct token and
// service catalog.
func IsSuccessful(t *testing.T, result CreateResult) {
token, err := result.ExtractToken()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ExpectedToken, token)
serviceCatalog, err := result.ExtractServiceCatalog()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ExpectedServiceCatalog, serviceCatalog)
}
// GetIsSuccessful ensures that a GetResult was successful and contains the correct token and
// User Info.
func GetIsSuccessful(t *testing.T, result GetResult) {
token, err := result.ExtractToken()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ExpectedToken, token)
user, err := result.ExtractUser()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ExpectedUser, user)
}

View File

@@ -0,0 +1,99 @@
package tokens
import (
"fmt"
"github.com/rackspace/gophercloud"
)
// AuthOptionsBuilder describes any argument that may be passed to the Create call.
type AuthOptionsBuilder interface {
// ToTokenCreateMap assembles the Create request body, returning an error if parameters are
// missing or inconsistent.
ToTokenCreateMap() (map[string]interface{}, error)
}
// AuthOptions wraps a gophercloud AuthOptions in order to adhere to the AuthOptionsBuilder
// interface.
type AuthOptions struct {
gophercloud.AuthOptions
}
// WrapOptions embeds a root AuthOptions struct in a package-specific one.
func WrapOptions(original gophercloud.AuthOptions) AuthOptions {
return AuthOptions{AuthOptions: original}
}
// ToTokenCreateMap converts AuthOptions into nested maps that can be serialized into a JSON
// request.
func (auth AuthOptions) ToTokenCreateMap() (map[string]interface{}, error) {
// Error out if an unsupported auth option is present.
if auth.UserID != "" {
return nil, ErrUserIDProvided
}
if auth.APIKey != "" {
return nil, ErrAPIKeyProvided
}
if auth.DomainID != "" {
return nil, ErrDomainIDProvided
}
if auth.DomainName != "" {
return nil, ErrDomainNameProvided
}
// Populate the request map.
authMap := make(map[string]interface{})
if auth.Username != "" {
if auth.Password != "" {
authMap["passwordCredentials"] = map[string]interface{}{
"username": auth.Username,
"password": auth.Password,
}
} else {
return nil, ErrPasswordRequired
}
} else if auth.TokenID != "" {
authMap["token"] = map[string]interface{}{
"id": auth.TokenID,
}
} else {
return nil, fmt.Errorf("You must provide either username/password or tenantID/token values.")
}
if auth.TenantID != "" {
authMap["tenantId"] = auth.TenantID
}
if auth.TenantName != "" {
authMap["tenantName"] = auth.TenantName
}
return map[string]interface{}{"auth": authMap}, nil
}
// Create authenticates to the identity service and attempts to acquire a Token.
// If successful, the CreateResult
// Generally, rather than interact with this call directly, end users should call openstack.AuthenticatedClient(),
// which abstracts all of the gory details about navigating service catalogs and such.
func Create(client *gophercloud.ServiceClient, auth AuthOptionsBuilder) CreateResult {
request, err := auth.ToTokenCreateMap()
if err != nil {
return CreateResult{gophercloud.Result{Err: err}}
}
var result CreateResult
_, result.Err = client.Post(CreateURL(client), request, &result.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 203},
})
return result
}
// Validates and retrieves information for user's token.
func Get(client *gophercloud.ServiceClient, token string) GetResult {
var result GetResult
_, result.Err = client.Get(GetURL(client, token), &result.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 203},
})
return result
}

View File

@@ -0,0 +1,170 @@
package tokens
import (
"time"
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/identity/v2/tenants"
)
// Token provides only the most basic information related to an authentication token.
type Token struct {
// ID provides the primary means of identifying a user to the OpenStack API.
// OpenStack defines this field as an opaque value, so do not depend on its content.
// It is safe, however, to compare for equality.
ID string
// ExpiresAt provides a timestamp in ISO 8601 format, indicating when the authentication token becomes invalid.
// After this point in time, future API requests made using this authentication token will respond with errors.
// Either the caller will need to reauthenticate manually, or more preferably, the caller should exploit automatic re-authentication.
// See the AuthOptions structure for more details.
ExpiresAt time.Time
// Tenant provides information about the tenant to which this token grants access.
Tenant tenants.Tenant
}
// Authorization need user info which can get from token authentication's response
type Role struct {
Name string `mapstructure:"name"`
}
type User struct {
ID string `mapstructure:"id"`
Name string `mapstructure:"name"`
UserName string `mapstructure:"username"`
Roles []Role `mapstructure:"roles"`
}
// Endpoint represents a single API endpoint offered by a service.
// It provides the public and internal URLs, if supported, along with a region specifier, again if provided.
// The significance of the Region field will depend upon your provider.
//
// In addition, the interface offered by the service will have version information associated with it
// through the VersionId, VersionInfo, and VersionList fields, if provided or supported.
//
// In all cases, fields which aren't supported by the provider and service combined will assume a zero-value ("").
type Endpoint struct {
TenantID string `mapstructure:"tenantId"`
PublicURL string `mapstructure:"publicURL"`
InternalURL string `mapstructure:"internalURL"`
AdminURL string `mapstructure:"adminURL"`
Region string `mapstructure:"region"`
VersionID string `mapstructure:"versionId"`
VersionInfo string `mapstructure:"versionInfo"`
VersionList string `mapstructure:"versionList"`
}
// CatalogEntry provides a type-safe interface to an Identity API V2 service catalog listing.
// Each class of service, such as cloud DNS or block storage services, will have a single
// CatalogEntry representing it.
//
// Note: when looking for the desired service, try, whenever possible, to key off the type field.
// Otherwise, you'll tie the representation of the service to a specific provider.
type CatalogEntry struct {
// Name will contain the provider-specified name for the service.
Name string `mapstructure:"name"`
// Type will contain a type string if OpenStack defines a type for the service.
// Otherwise, for provider-specific services, the provider may assign their own type strings.
Type string `mapstructure:"type"`
// Endpoints will let the caller iterate over all the different endpoints that may exist for
// the service.
Endpoints []Endpoint `mapstructure:"endpoints"`
}
// ServiceCatalog provides a view into the service catalog from a previous, successful authentication.
type ServiceCatalog struct {
Entries []CatalogEntry
}
// CreateResult defers the interpretation of a created token.
// Use ExtractToken() to interpret it as a Token, or ExtractServiceCatalog() to interpret it as a service catalog.
type CreateResult struct {
gophercloud.Result
}
// GetResult is the deferred response from a Get call, which is the same with a Created token.
// Use ExtractUser() to interpret it as a User.
type GetResult struct {
CreateResult
}
// ExtractToken returns the just-created Token from a CreateResult.
func (result CreateResult) ExtractToken() (*Token, error) {
if result.Err != nil {
return nil, result.Err
}
var response struct {
Access struct {
Token struct {
Expires string `mapstructure:"expires"`
ID string `mapstructure:"id"`
Tenant tenants.Tenant `mapstructure:"tenant"`
} `mapstructure:"token"`
} `mapstructure:"access"`
}
err := mapstructure.Decode(result.Body, &response)
if err != nil {
return nil, err
}
expiresTs, err := time.Parse(gophercloud.RFC3339Milli, response.Access.Token.Expires)
if err != nil {
return nil, err
}
return &Token{
ID: response.Access.Token.ID,
ExpiresAt: expiresTs,
Tenant: response.Access.Token.Tenant,
}, nil
}
// ExtractServiceCatalog returns the ServiceCatalog that was generated along with the user's Token.
func (result CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
if result.Err != nil {
return nil, result.Err
}
var response struct {
Access struct {
Entries []CatalogEntry `mapstructure:"serviceCatalog"`
} `mapstructure:"access"`
}
err := mapstructure.Decode(result.Body, &response)
if err != nil {
return nil, err
}
return &ServiceCatalog{Entries: response.Access.Entries}, nil
}
// createErr quickly packs an error in a CreateResult.
func createErr(err error) CreateResult {
return CreateResult{gophercloud.Result{Err: err}}
}
// ExtractUser returns the User from a GetResult.
func (result GetResult) ExtractUser() (*User, error) {
if result.Err != nil {
return nil, result.Err
}
var response struct {
Access struct {
User User `mapstructure:"user"`
} `mapstructure:"access"`
}
err := mapstructure.Decode(result.Body, &response)
if err != nil {
return nil, err
}
return &response.Access.User, nil
}

View File

@@ -0,0 +1,13 @@
package tokens
import "github.com/rackspace/gophercloud"
// CreateURL generates the URL used to create new Tokens.
func CreateURL(client *gophercloud.ServiceClient) string {
return client.ServiceURL("tokens")
}
// GetURL generates the URL used to Validate Tokens.
func GetURL(client *gophercloud.ServiceClient, token string) string {
return client.ServiceURL("tokens", token)
}