Merge pull request #57584 from dims/update-to-latest-gophercloud

Automatic merge from submit-queue (batch tested with PRs 57584, 57679). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Update to latest gophercloud

**What this PR does / why we need it**:

Catch up with all the latest stuff from gophercloud

be3fd784 - Flavor Extra Specs Create
c2cafb46 - Flavor Extra Specs: List / Get
7b1b8775 - Compute v2: Flavor Access Add
cf81d92c - Add DELETE support in V3 volume types
a879b375 - Fix incorrect variable name
2997913a - Add pagination support in snapshots
a5c71868 - Support pagination in volume resources
1db0312e - TrivialFix incorrect variable name
69194d93 - Add basic CRUD acceptance testcases in snapshot V3
22c7abce - Add CREATE support in V3 volume types
aed60e9f - Add basic CRUD acceptance in volume V3
7cbf4661 - BlockStorage v3: volumetype get/list acc test
bcab0f79 - Update README with Thank Yous
f85e7c0f - Docs: Updating Contributing and Style Guides
be1b616c - Fix a small syntax error of TestShareTypeExtraSpecs test
3f38a1ee - Add List/Get support for volume type in volume V3
48a40399 - Support for setting availability_zone_hints to a router
747776a7 - Fix the undefined function error of TestPortsbindingCRUD test
a7ec61ea - Fix the undefined function error of TestNetworksProviderCRUD test
25e18920 - Compute v2: Add the extended status information API
b63d2fd3 - availability_zone_hints for network(s)
157d7511 - Add support for ipv6_address_mode and ipv6_ra_mode in subnets
ed468967 - DBv1: configurations acceptance test
578e2aab - Configuration group time parsing error
669959f8 - Compute v2: attachinterfaces acceptance test
8113f0cb - Add Nova interface-detach support
d6484abc - Add Nova interface-attach support
7883fd95 - fix reauth deadlock by not calling Token() during reauth
4d0f8253 - Add support to get interface of a server
7dc13e0d - AccTests: BlockStorage v2 ForceDelete
1e86e54d - Refactor blockstorage actionURL
e30da231 - Feature/support force delete
e193578c - add UseTokenLock method in ProviderClient to allow safe concurrent access
e6a5f874 - ObjectStorage v1: Rename ExtractLastMarker to extractLastMarker
c47bb004 - BlockStorage v2/v3: Reorder snapshot/volume ListOpts and update godoc
2c05d0e4 - Add 'tenant' support in volume&snapshot API
639d71fd - Networking v2: Port Security Extension
755794a7 - ObjectStorage v1: Subdir and Marker detection
a043441f - fixed bug with endless loop when using delimiter on folded directory
a4799293 - OpenStack: support OS_PROJECT_* variables

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes #

**Special notes for your reviewer**:

**Release note**:

```release-note
NONE
```

Kubernetes-commit: df259cc54d62fdf8ca89ab05d6e7931c022bfaea
This commit is contained in:
Kubernetes Publisher
2018-01-02 17:43:30 -08:00
6 changed files with 156 additions and 26 deletions

14
Godeps/Godeps.json generated
View File

@@ -172,31 +172,31 @@
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud", "ImportPath": "github.com/gophercloud/gophercloud",
"Rev": "8183543f90d1aef267a5ecc209f2e0715b355acb" "Rev": "8e59687aa4b27ab22a0bf3295f1e165ff7bd5f97"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack", "ImportPath": "github.com/gophercloud/gophercloud/openstack",
"Rev": "8183543f90d1aef267a5ecc209f2e0715b355acb" "Rev": "8e59687aa4b27ab22a0bf3295f1e165ff7bd5f97"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tenants",
"Rev": "8183543f90d1aef267a5ecc209f2e0715b355acb" "Rev": "8e59687aa4b27ab22a0bf3295f1e165ff7bd5f97"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens",
"Rev": "8183543f90d1aef267a5ecc209f2e0715b355acb" "Rev": "8e59687aa4b27ab22a0bf3295f1e165ff7bd5f97"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens", "ImportPath": "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens",
"Rev": "8183543f90d1aef267a5ecc209f2e0715b355acb" "Rev": "8e59687aa4b27ab22a0bf3295f1e165ff7bd5f97"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/openstack/utils", "ImportPath": "github.com/gophercloud/gophercloud/openstack/utils",
"Rev": "8183543f90d1aef267a5ecc209f2e0715b355acb" "Rev": "8e59687aa4b27ab22a0bf3295f1e165ff7bd5f97"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud/pagination", "ImportPath": "github.com/gophercloud/gophercloud/pagination",
"Rev": "8183543f90d1aef267a5ecc209f2e0715b355acb" "Rev": "8e59687aa4b27ab22a0bf3295f1e165ff7bd5f97"
}, },
{ {
"ImportPath": "github.com/gregjones/httpcache", "ImportPath": "github.com/gregjones/httpcache",

View File

@@ -141,3 +141,19 @@ See the [contributing guide](./.github/CONTRIBUTING.md).
If you're struggling with something or have spotted a potential bug, feel free If you're struggling with something or have spotted a potential bug, feel free
to submit an issue to our [bug tracker](/issues). to submit an issue to our [bug tracker](/issues).
## Thank You
We'd like to extend special thanks and appreciation to the following:
### OpenLab
<a href="http://openlabtesting.org/"><img src="assets/openlab.png" width="600px"></a>
OpenLab is providing a full CI environment to test each PR and merge for a variety of OpenStack releases.
### VEXXHOST
<a href="https://vexxhost.com/"><img src="assets/vexxhost.png" width="600px"></a>
VEXXHOST is providing their services to assist with the development and testing of Gophercloud.

View File

@@ -1,6 +1,8 @@
## On Pull Requests ## On Pull Requests
- Please make sure to read our [contributing guide](/.github/CONTRIBUTING.md).
- Before you start a PR there needs to be a Github issue and a discussion about it - Before you start a PR there needs to be a Github issue and a discussion about it
on that issue with a core contributor, even if it's just a 'SGTM'. on that issue with a core contributor, even if it's just a 'SGTM'.
@@ -34,6 +36,9 @@
append. It makes it difficult for the reviewer to see what's changed from one append. It makes it difficult for the reviewer to see what's changed from one
review to the next. review to the next.
- See [#583](https://github.com/gophercloud/gophercloud/issues/583) as an example of a
well-formatted issue which contains all relevant information we need to review and approve.
## On Code ## On Code
- In re design: follow as closely as is reasonable the code already in the library. - In re design: follow as closely as is reasonable the code already in the library.

View File

@@ -16,7 +16,12 @@ The following variables provide sources of truth: OS_AUTH_URL, OS_USERNAME,
OS_PASSWORD, OS_TENANT_ID, and OS_TENANT_NAME. OS_PASSWORD, OS_TENANT_ID, and OS_TENANT_NAME.
Of these, OS_USERNAME, OS_PASSWORD, and OS_AUTH_URL must have settings, Of these, OS_USERNAME, OS_PASSWORD, and OS_AUTH_URL must have settings,
or an error will result. OS_TENANT_ID and OS_TENANT_NAME are optional. or an error will result. OS_TENANT_ID, OS_TENANT_NAME, OS_PROJECT_ID, and
OS_PROJECT_NAME are optional.
OS_TENANT_ID and OS_TENANT_NAME are mutually exclusive to OS_PROJECT_ID and
OS_PROJECT_NAME. If OS_PROJECT_ID and OS_PROJECT_NAME are set, they will
still be referred as "tenant" in Gophercloud.
To use this function, first set the OS_* environment variables (for example, To use this function, first set the OS_* environment variables (for example,
by sourcing an `openrc` file), then: by sourcing an `openrc` file), then:
@@ -34,6 +39,16 @@ func AuthOptionsFromEnv() (gophercloud.AuthOptions, error) {
domainID := os.Getenv("OS_DOMAIN_ID") domainID := os.Getenv("OS_DOMAIN_ID")
domainName := os.Getenv("OS_DOMAIN_NAME") domainName := os.Getenv("OS_DOMAIN_NAME")
// If OS_PROJECT_ID is set, overwrite tenantID with the value.
if v := os.Getenv("OS_PROJECT_ID"); v != "" {
tenantID = v
}
// If OS_PROJECT_NAME is set, overwrite tenantName with the value.
if v := os.Getenv("OS_PROJECT_NAME"); v != "" {
tenantName = v
}
if authURL == "" { if authURL == "" {
err := gophercloud.ErrMissingInput{Argument: "authURL"} err := gophercloud.ErrMissingInput{Argument: "authURL"}
return nilOptions, err return nilOptions, err

View File

@@ -56,11 +56,12 @@ func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
endpoint = gophercloud.NormalizeURL(endpoint) endpoint = gophercloud.NormalizeURL(endpoint)
base = gophercloud.NormalizeURL(base) base = gophercloud.NormalizeURL(base)
return &gophercloud.ProviderClient{ p := new(gophercloud.ProviderClient)
IdentityBase: base, p.IdentityBase = base
IdentityEndpoint: endpoint, p.IdentityEndpoint = endpoint
}, nil p.UseTokenLock()
return p, nil
} }
/* /*
@@ -158,9 +159,21 @@ func v2auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
} }
if options.AllowReauth { if options.AllowReauth {
// here we're creating a throw-away client (tac). it's a copy of the user's provider client, but
// with the token and reauth func zeroed out. combined with setting `AllowReauth` to `false`,
// this should retry authentication only once
tac := *client
tac.ReauthFunc = nil
tac.TokenID = ""
tao := options
tao.AllowReauth = false
client.ReauthFunc = func() error { client.ReauthFunc = func() error {
client.TokenID = "" err := v2auth(&tac, endpoint, tao, eo)
return v2auth(client, endpoint, options, eo) if err != nil {
return err
}
client.TokenID = tac.TokenID
return nil
} }
} }
client.TokenID = token.ID client.TokenID = token.ID
@@ -202,9 +215,32 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, opts tokens3.Au
client.TokenID = token.ID client.TokenID = token.ID
if opts.CanReauth() { if opts.CanReauth() {
// here we're creating a throw-away client (tac). it's a copy of the user's provider client, but
// with the token and reauth func zeroed out. combined with setting `AllowReauth` to `false`,
// this should retry authentication only once
tac := *client
tac.ReauthFunc = nil
tac.TokenID = ""
var tao tokens3.AuthOptionsBuilder
switch ot := opts.(type) {
case *gophercloud.AuthOptions:
o := *ot
o.AllowReauth = false
tao = &o
case *tokens3.AuthOptions:
o := *ot
o.AllowReauth = false
tao = &o
default:
tao = opts
}
client.ReauthFunc = func() error { client.ReauthFunc = func() error {
client.TokenID = "" err := v3auth(&tac, endpoint, tao, eo)
return v3auth(client, endpoint, opts, eo) if err != nil {
return err
}
client.TokenID = tac.TokenID
return nil
} }
} }
client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) { client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {

View File

@@ -7,6 +7,7 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
"sync"
) )
// DefaultUserAgent is the default User-Agent string set in the request header. // DefaultUserAgent is the default User-Agent string set in the request header.
@@ -51,6 +52,8 @@ type ProviderClient struct {
IdentityEndpoint string IdentityEndpoint string
// TokenID is the ID of the most recently issued valid token. // TokenID is the ID of the most recently issued valid token.
// NOTE: Aside from within a custom ReauthFunc, this field shouldn't be set by an application.
// To safely read or write this value, call `Token` or `SetToken`, respectively
TokenID string TokenID string
// EndpointLocator describes how this provider discovers the endpoints for // EndpointLocator describes how this provider discovers the endpoints for
@@ -68,16 +71,59 @@ type ProviderClient struct {
// authentication functions for different Identity service versions. // authentication functions for different Identity service versions.
ReauthFunc func() error ReauthFunc func() error
Debug bool mut *sync.RWMutex
reauthmut *reauthlock
}
type reauthlock struct {
sync.RWMutex
reauthing bool
} }
// AuthenticatedHeaders returns a map of HTTP headers that are common for all // AuthenticatedHeaders returns a map of HTTP headers that are common for all
// authenticated service requests. // authenticated service requests.
func (client *ProviderClient) AuthenticatedHeaders() map[string]string { func (client *ProviderClient) AuthenticatedHeaders() (m map[string]string) {
if client.TokenID == "" { if client.reauthmut != nil {
return map[string]string{} client.reauthmut.RLock()
if client.reauthmut.reauthing {
client.reauthmut.RUnlock()
return
}
client.reauthmut.RUnlock()
} }
return map[string]string{"X-Auth-Token": client.TokenID} t := client.Token()
if t == "" {
return
}
return map[string]string{"X-Auth-Token": t}
}
// UseTokenLock creates a mutex that is used to allow safe concurrent access to the auth token.
// If the application's ProviderClient is not used concurrently, this doesn't need to be called.
func (client *ProviderClient) UseTokenLock() {
client.mut = new(sync.RWMutex)
client.reauthmut = new(reauthlock)
}
// Token safely reads the value of the auth token from the ProviderClient. Applications should
// call this method to access the token instead of the TokenID field
func (client *ProviderClient) Token() string {
if client.mut != nil {
client.mut.RLock()
defer client.mut.RUnlock()
}
return client.TokenID
}
// SetToken safely sets the value of the auth token in the ProviderClient. Applications may
// use this method in a custom ReauthFunc
func (client *ProviderClient) SetToken(t string) {
if client.mut != nil {
client.mut.Lock()
defer client.mut.Unlock()
}
client.TokenID = t
} }
// RequestOpts customizes the behavior of the provider.Request() method. // RequestOpts customizes the behavior of the provider.Request() method.
@@ -166,6 +212,8 @@ func (client *ProviderClient) Request(method, url string, options *RequestOpts)
// Set connection parameter to close the connection immediately when we've got the response // Set connection parameter to close the connection immediately when we've got the response
req.Close = true req.Close = true
prereqtok := req.Header.Get("X-Auth-Token")
// Issue the request. // Issue the request.
resp, err := client.HTTPClient.Do(req) resp, err := client.HTTPClient.Do(req)
if err != nil { if err != nil {
@@ -189,9 +237,6 @@ func (client *ProviderClient) Request(method, url string, options *RequestOpts)
if !ok { if !ok {
body, _ := ioutil.ReadAll(resp.Body) body, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close() resp.Body.Close()
//pc := make([]uintptr, 1)
//runtime.Callers(2, pc)
//f := runtime.FuncForPC(pc[0])
respErr := ErrUnexpectedResponseCode{ respErr := ErrUnexpectedResponseCode{
URL: url, URL: url,
Method: method, Method: method,
@@ -199,7 +244,6 @@ func (client *ProviderClient) Request(method, url string, options *RequestOpts)
Actual: resp.StatusCode, Actual: resp.StatusCode,
Body: body, Body: body,
} }
//respErr.Function = "gophercloud.ProviderClient.Request"
errType := options.ErrorContext errType := options.ErrorContext
switch resp.StatusCode { switch resp.StatusCode {
@@ -210,7 +254,21 @@ func (client *ProviderClient) Request(method, url string, options *RequestOpts)
} }
case http.StatusUnauthorized: case http.StatusUnauthorized:
if client.ReauthFunc != nil { if client.ReauthFunc != nil {
err = client.ReauthFunc() if client.mut != nil {
client.mut.Lock()
client.reauthmut.Lock()
client.reauthmut.reauthing = true
client.reauthmut.Unlock()
if curtok := client.TokenID; curtok == prereqtok {
err = client.ReauthFunc()
}
client.reauthmut.Lock()
client.reauthmut.reauthing = false
client.reauthmut.Unlock()
client.mut.Unlock()
} else {
err = client.ReauthFunc()
}
if err != nil { if err != nil {
e := &ErrUnableToReauthenticate{} e := &ErrUnableToReauthenticate{}
e.ErrOriginal = respErr e.ErrOriginal = respErr