Merge pull request #2816 from brancz/gophercloud-vendoring

vendor: fix mixed versions of gophercloud packages
This commit is contained in:
Frederic Branczyk 2017-06-07 09:54:31 +02:00 committed by GitHub
commit d26f789cb0
12 changed files with 243 additions and 171 deletions

View file

@ -57,7 +57,7 @@
### Naming
- For methods on a type in `response.go`, the receiver should be named `r` and the
- For methods on a type in `results.go`, the receiver should be named `r` and the
variable into which it will be unmarshalled `s`.
- Functions in `requests.go`, with the exception of functions that return a

View file

@ -182,9 +182,10 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, opts tokens3.Au
// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service.
func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
endpoint := client.IdentityBase + "v2.0/"
clientType := "identity"
var err error
if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
eo.ApplyDefaults("identity")
eo.ApplyDefaults(clientType)
endpoint, err = client.EndpointLocator(eo)
if err != nil {
return nil, err
@ -194,15 +195,17 @@ func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOp
return &gophercloud.ServiceClient{
ProviderClient: client,
Endpoint: endpoint,
Type: clientType,
}, nil
}
// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service.
func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
endpoint := client.IdentityBase + "v3/"
clientType := "identity"
var err error
if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
eo.ApplyDefaults("identity")
eo.ApplyDefaults(clientType)
endpoint, err = client.EndpointLocator(eo)
if err != nil {
return nil, err
@ -212,125 +215,81 @@ func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOp
return &gophercloud.ServiceClient{
ProviderClient: client,
Endpoint: endpoint,
Type: clientType,
}, nil
}
func initClientOpts(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clientType string) (*gophercloud.ServiceClient, error) {
sc := new(gophercloud.ServiceClient)
eo.ApplyDefaults(clientType)
url, err := client.EndpointLocator(eo)
if err != nil {
return sc, err
}
sc.ProviderClient = client
sc.Endpoint = url
sc.Type = clientType
return sc, nil
}
// NewObjectStorageV1 creates a ServiceClient that may be used with the v1 object storage package.
func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("object-store")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
return initClientOpts(client, eo, "object-store")
}
// NewComputeV2 creates a ServiceClient that may be used with the v2 compute package.
func NewComputeV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("compute")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
return initClientOpts(client, eo, "compute")
}
// NewNetworkV2 creates a ServiceClient that may be used with the v2 network package.
func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("network")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{
ProviderClient: client,
Endpoint: url,
ResourceBase: url + "v2.0/",
}, nil
sc, err := initClientOpts(client, eo, "network")
sc.ResourceBase = sc.Endpoint + "v2.0/"
return sc, err
}
// NewBlockStorageV1 creates a ServiceClient that may be used to access the v1 block storage service.
func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("volume")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
return initClientOpts(client, eo, "volume")
}
// NewBlockStorageV2 creates a ServiceClient that may be used to access the v2 block storage service.
func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("volumev2")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
return initClientOpts(client, eo, "volumev2")
}
// NewSharedFileSystemV2 creates a ServiceClient that may be used to access the v2 shared file system service.
func NewSharedFileSystemV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("sharev2")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
return initClientOpts(client, eo, "sharev2")
}
// NewCDNV1 creates a ServiceClient that may be used to access the OpenStack v1
// CDN service.
func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("cdn")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
return initClientOpts(client, eo, "cdn")
}
// NewOrchestrationV1 creates a ServiceClient that may be used to access the v1 orchestration service.
func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("orchestration")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
return initClientOpts(client, eo, "orchestration")
}
// NewDBV1 creates a ServiceClient that may be used to access the v1 DB service.
func NewDBV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("database")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
return initClientOpts(client, eo, "database")
}
// NewDNSV2 creates a ServiceClient that may be used to access the v2 DNS service.
func NewDNSV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("dns")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{
ProviderClient: client,
Endpoint: url,
ResourceBase: url + "v2/"}, nil
sc, err := initClientOpts(client, eo, "dns")
sc.ResourceBase = sc.Endpoint + "v2/"
return sc, err
}
// NewImageServiceV2 creates a ServiceClient that may be used to access the v2 image service.
func NewImageServiceV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("image")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client,
Endpoint: url,
ResourceBase: url + "v2/"}, nil
sc, err := initClientOpts(client, eo, "image")
sc.ResourceBase = sc.Endpoint + "v2/"
return sc, err
}

View file

@ -0,0 +1,15 @@
// Package extensions provides information and interaction with the different extensions available
// for an OpenStack service.
//
// The purpose of OpenStack API extensions is to:
//
// - Introduce new features in the API without requiring a version change.
// - Introduce vendor-specific niche functionality.
// - Act as a proving ground for experimental functionalities that might be included in a future
// version of the API.
//
// Extensions usually have tags that prevent conflicts with other extensions that define attributes
// or resources with the same names, and with core resources and attributes.
// Because an extension might not be supported by all plug-ins, its availability varies with deployments
// and the specific plug-in.
package extensions

View file

@ -0,0 +1 @@
package extensions

View file

@ -0,0 +1,20 @@
package extensions
import (
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination"
)
// Get retrieves information for a specific extension using its alias.
func Get(c *gophercloud.ServiceClient, alias string) (r GetResult) {
_, r.Err = c.Get(ExtensionURL(c, alias), &r.Body, nil)
return
}
// List returns a Pager which allows you to iterate over the full collection of extensions.
// It does not accept query parameters.
func List(c *gophercloud.ServiceClient) pagination.Pager {
return pagination.NewPager(c, ListExtensionURL(c), func(r pagination.PageResult) pagination.Page {
return ExtensionPage{pagination.SinglePageBase(r)}
})
}

View file

@ -0,0 +1,53 @@
package extensions
import (
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination"
)
// GetResult temporarily stores the result of a Get call.
// Use its Extract() method to interpret it as an Extension.
type GetResult struct {
gophercloud.Result
}
// Extract interprets a GetResult as an Extension.
func (r GetResult) Extract() (*Extension, error) {
var s struct {
Extension *Extension `json:"extension"`
}
err := r.ExtractInto(&s)
return s.Extension, err
}
// Extension is a struct that represents an OpenStack extension.
type Extension struct {
Updated string `json:"updated"`
Name string `json:"name"`
Links []interface{} `json:"links"`
Namespace string `json:"namespace"`
Alias string `json:"alias"`
Description string `json:"description"`
}
// ExtensionPage is the page returned by a pager when traversing over a collection of extensions.
type ExtensionPage struct {
pagination.SinglePageBase
}
// IsEmpty checks whether an ExtensionPage struct is empty.
func (r ExtensionPage) IsEmpty() (bool, error) {
is, err := ExtractExtensions(r)
return len(is) == 0, err
}
// ExtractExtensions accepts a Page struct, specifically an ExtensionPage struct, and extracts the
// elements into a slice of Extension structs.
// In other words, a generic collection is mapped into a relevant slice.
func ExtractExtensions(r pagination.Page) ([]Extension, error) {
var s struct {
Extensions []Extension `json:"extensions"`
}
err := (r.(ExtensionPage)).ExtractInto(&s)
return s.Extensions, err
}

View file

@ -0,0 +1,13 @@
package extensions
import "github.com/gophercloud/gophercloud"
// ExtensionURL generates the URL for an extension resource by name.
func ExtensionURL(c *gophercloud.ServiceClient, name string) string {
return c.ServiceURL("extensions", name)
}
// ListExtensionURL generates the URL for the extensions resource collection.
func ListExtensionURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL("extensions")
}

View file

@ -11,6 +11,24 @@ type ListOptsBuilder interface {
ToFlavorListQuery() (string, error)
}
// AccessType maps to OpenStack's Flavor.is_public field. Although the is_public field is boolean, the
// request options are ternary, which is why AccessType is a string. The following values are
// allowed:
//
// PublicAccess (the default): Returns public flavors and private flavors associated with that project.
// PrivateAccess (admin only): Returns private flavors, across all projects.
// AllAccess (admin only): Returns public and private flavors across all projects.
//
// The AccessType arguement is optional, and if it is not supplied, OpenStack returns the PublicAccess
// flavors.
type AccessType string
const (
PublicAccess AccessType = "true"
PrivateAccess AccessType = "false"
AllAccess AccessType = "None"
)
// ListOpts helps control the results returned by the List() function.
// For example, a flavor with a minDisk field of 10 will not be returned if you specify MinDisk set to 20.
// Typically, software will use the last ID of the previous call to List to set the Marker for the current call.
@ -29,6 +47,10 @@ type ListOpts struct {
// Limit instructs List to refrain from sending excessively large lists of flavors.
Limit int `q:"limit"`
// AccessType, if provided, instructs List which set of flavors to return. If IsPublic not provided,
// flavors for the current project are returned.
AccessType AccessType `q:"is_public"`
}
// ToFlavorListQuery formats a ListOpts into a query string.

View file

@ -46,6 +46,8 @@ type Flavor struct {
Swap int `json:"swap"`
// VCPUs indicates how many (virtual) CPUs are available for this flavor.
VCPUs int `json:"vcpus"`
// IsPublic indicates whether the flavor is public.
IsPublic bool `json:"is_public"`
}
func (r *Flavor) UnmarshalJSON(b []byte) error {

View file

@ -182,13 +182,13 @@ func Get(c *gophercloud.ServiceClient, token string) (r GetResult) {
func Validate(c *gophercloud.ServiceClient, token string) (bool, error) {
resp, err := c.Request("HEAD", tokenURL(c), &gophercloud.RequestOpts{
MoreHeaders: subjectTokenHeaders(c, token),
OkCodes: []int{204, 404},
OkCodes: []int{200, 204, 400, 401, 403, 404},
})
if err != nil {
return false, err
}
return resp.StatusCode == 204, nil
return resp.StatusCode == 200 || resp.StatusCode == 204, nil
}
// Revoke immediately makes specified token invalid.

View file

@ -21,6 +21,12 @@ type ServiceClient struct {
// as-is, instead.
ResourceBase string
// This is the service client type (e.g. compute, sharev2).
// NOTE: FOR INTERNAL USE ONLY. DO NOT SET. GOPHERCLOUD WILL SET THIS.
// It is only exported because it gets set in a different package.
Type string
// The microversion of the service to use. Set this to use a particular microversion.
Microversion string
}
@ -37,11 +43,13 @@ func (client *ServiceClient) ServiceURL(parts ...string) string {
return client.ResourceBaseURL() + strings.Join(parts, "/")
}
// Get calls `Request` with the "GET" HTTP verb.
func (client *ServiceClient) Get(url string, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
func (client *ServiceClient) initReqOpts(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) {
if v, ok := (JSONBody).(io.Reader); ok {
opts.RawBody = v
} else if JSONBody != nil {
opts.JSONBody = JSONBody
}
if JSONResponse != nil {
opts.JSONResponse = JSONResponse
}
@ -49,93 +57,66 @@ func (client *ServiceClient) Get(url string, JSONResponse interface{}, opts *Req
if opts.MoreHeaders == nil {
opts.MoreHeaders = make(map[string]string)
}
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
if client.Microversion != "" {
client.setMicroversionHeader(opts)
}
}
// Get calls `Request` with the "GET" HTTP verb.
func (client *ServiceClient) Get(url string, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = new(RequestOpts)
}
client.initReqOpts(url, nil, JSONResponse, opts)
return client.Request("GET", url, opts)
}
// Post calls `Request` with the "POST" HTTP verb.
func (client *ServiceClient) Post(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
opts = new(RequestOpts)
}
if v, ok := (JSONBody).(io.Reader); ok {
opts.RawBody = v
} else if JSONBody != nil {
opts.JSONBody = JSONBody
}
if JSONResponse != nil {
opts.JSONResponse = JSONResponse
}
if opts.MoreHeaders == nil {
opts.MoreHeaders = make(map[string]string)
}
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
client.initReqOpts(url, JSONBody, JSONResponse, opts)
return client.Request("POST", url, opts)
}
// Put calls `Request` with the "PUT" HTTP verb.
func (client *ServiceClient) Put(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
opts = new(RequestOpts)
}
if v, ok := (JSONBody).(io.Reader); ok {
opts.RawBody = v
} else if JSONBody != nil {
opts.JSONBody = JSONBody
}
if JSONResponse != nil {
opts.JSONResponse = JSONResponse
}
if opts.MoreHeaders == nil {
opts.MoreHeaders = make(map[string]string)
}
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
client.initReqOpts(url, JSONBody, JSONResponse, opts)
return client.Request("PUT", url, opts)
}
// Patch calls `Request` with the "PATCH" HTTP verb.
func (client *ServiceClient) Patch(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
opts = new(RequestOpts)
}
if v, ok := (JSONBody).(io.Reader); ok {
opts.RawBody = v
} else if JSONBody != nil {
opts.JSONBody = JSONBody
}
if JSONResponse != nil {
opts.JSONResponse = JSONResponse
}
if opts.MoreHeaders == nil {
opts.MoreHeaders = make(map[string]string)
}
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
client.initReqOpts(url, JSONBody, JSONResponse, opts)
return client.Request("PATCH", url, opts)
}
// Delete calls `Request` with the "DELETE" HTTP verb.
func (client *ServiceClient) Delete(url string, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
opts = new(RequestOpts)
}
if opts.MoreHeaders == nil {
opts.MoreHeaders = make(map[string]string)
}
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
client.initReqOpts(url, nil, nil, opts)
return client.Request("DELETE", url, opts)
}
func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) {
switch client.Type {
case "compute":
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
case "sharev2":
opts.MoreHeaders["X-OpenStack-Manila-API-Version"] = client.Microversion
}
if client.Type != "" {
opts.MoreHeaders["OpenStack-API-Version"] = client.Type + " " + client.Microversion
}
}

62
vendor/vendor.json vendored
View file

@ -354,46 +354,52 @@
"revisionTime": "2016-09-30T00:14:02Z"
},
{
"checksumSHA1": "cuTQkSEiIoMhDhB7xCbYDwDhrgw=",
"checksumSHA1": "ndG2xmm2bas4/t+kIEUp2xIni8c=",
"path": "github.com/gophercloud/gophercloud",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "0KdIjTH5IO8hlIl8kdfI6313GiY=",
"checksumSHA1": "24DO5BEQdFKNl1rfWgI2b4+ry5U=",
"path": "github.com/gophercloud/gophercloud/openstack",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "Au6MAsI90lewLByg9n+Yjtdqdh8=",
"path": "github.com/gophercloud/gophercloud/openstack/common/extensions",
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "4XWDCGMYqipwJymi9xJo9UffD7g=",
"path": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions",
"revision": "caa61b3ca9f504196fd3b338f43cd99d830f7e2e",
"revisionTime": "2017-05-11T18:09:16Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "e7AW3YDVYJPKUjpqsB4AL9RRlTw=",
"path": "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips",
"revision": "caa61b3ca9f504196fd3b338f43cd99d830f7e2e",
"revisionTime": "2017-05-11T18:09:16Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "S1BV3o8Pa0aM5RaUuRYXY7LnPIc=",
"checksumSHA1": "vTyXSR+Znw7/o/70UBOWG0F09r8=",
"path": "github.com/gophercloud/gophercloud/openstack/compute/v2/flavors",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "Rnzx2YgOD41k8KoPA08tR992PxQ=",
"path": "github.com/gophercloud/gophercloud/openstack/compute/v2/images",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "IjCvcaNnRW++hclt21WUkMYinaA=",
"path": "github.com/gophercloud/gophercloud/openstack/compute/v2/servers",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "9z5GwbsfpB49gzkHu10pDH5roKA=",
@ -404,14 +410,14 @@
{
"checksumSHA1": "1sVqsZBZBNhDXLY9XzjMkcOkcbg=",
"path": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "AvUU5En9YpG25iLlcAPDgcQODjI=",
"path": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "vsgZmEVQLtCmxuxf/q4u8XJGWpE=",
@ -420,22 +426,22 @@
"revisionTime": "2017-05-04T01:40:32Z"
},
{
"checksumSHA1": "ZKyEbJuIlvuZ9aUushINCXJHF4w=",
"checksumSHA1": "fHOkQNWyeGoMPjkYvqiOrOifTUw=",
"path": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "TDOZnaS0TO0NirpxV1QwPerAQTY=",
"path": "github.com/gophercloud/gophercloud/openstack/utils",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "FNy075ydQZXvnL2bNNIOCmy/ghs=",
"path": "github.com/gophercloud/gophercloud/pagination",
"revision": "0bf921da554eacc1552a70204be7a1201937c1e1",
"revisionTime": "2017-05-04T01:40:32Z"
"revision": "caf34a65f60295108141f62929245943bd00f237",
"revisionTime": "2017-06-07T03:48:29Z"
},
{
"checksumSHA1": "LclVLJYrBi03PBjsVPpgoMbUDQ8=",