|  | 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 | 
|  | } | 
|  |  | 
|  | // 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 | 
|  | } | 
|  |  | 
|  | // 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}} | 
|  | } |