mirror of
https://github.com/kubernetes/client-go.git
synced 2026-01-29 21:38:35 +00:00
Automatic merge from submit-queue (batch tested with PRs 50087, 39587, 50042, 50241, 49914) plugin/pkg/client/auth: add openstack auth provider This is an implementation of auth provider for OpenStack world, just like python-openstackclient, we read the environment variables of a list `OS_*`, and client will cache a token to interact with each components, we can do the same here, the client side can cache a token locally at the first time, and rotate automatically when it expires. This requires an implementation of token authenticator at server side, refer: 1. [made by me] https://github.com/kubernetes/kubernetes/pull/25536, I can carry this on when it is fine to go. 2. [made by @kfox1111] https://github.com/kubernetes/kubernetes/pull/25391 The reason why I want to add this is due to the `client-side` nature, it will be confusing to implement it downstream, we would like to add this support here, and customers can get `kubectl` like they usually do(`brew install kubernetes-cli`), and it will just work. When this is done, we can deprecate the password keystone authenticator as the following reasons: 1. as mentioned at some other places, the `domain` is another parameters which should be provided. 2. in case the user supplies `apikey` and `secrets`, we might want to fill the `UserInfo` with the real name which is not implemented for now. cc @erictune @liggitt ``` add openstack auth provider ``` Kubernetes-commit: 59b8fa32f129be29f146bfd4888a5d1ab7e71ca5
115 lines
2.8 KiB
Go
115 lines
2.8 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/gophercloud/gophercloud"
|
|
)
|
|
|
|
// Version is a supported API version, corresponding to a vN package within the appropriate service.
|
|
type Version struct {
|
|
ID string
|
|
Suffix string
|
|
Priority int
|
|
}
|
|
|
|
var goodStatus = map[string]bool{
|
|
"current": true,
|
|
"supported": true,
|
|
"stable": true,
|
|
}
|
|
|
|
// ChooseVersion queries the base endpoint of an API to choose the most recent non-experimental alternative from a service's
|
|
// published versions.
|
|
// It returns the highest-Priority Version among the alternatives that are provided, as well as its corresponding endpoint.
|
|
func ChooseVersion(client *gophercloud.ProviderClient, recognized []*Version) (*Version, string, error) {
|
|
type linkResp struct {
|
|
Href string `json:"href"`
|
|
Rel string `json:"rel"`
|
|
}
|
|
|
|
type valueResp struct {
|
|
ID string `json:"id"`
|
|
Status string `json:"status"`
|
|
Links []linkResp `json:"links"`
|
|
}
|
|
|
|
type versionsResp struct {
|
|
Values []valueResp `json:"values"`
|
|
}
|
|
|
|
type response struct {
|
|
Versions versionsResp `json:"versions"`
|
|
}
|
|
|
|
normalize := func(endpoint string) string {
|
|
if !strings.HasSuffix(endpoint, "/") {
|
|
return endpoint + "/"
|
|
}
|
|
return endpoint
|
|
}
|
|
identityEndpoint := normalize(client.IdentityEndpoint)
|
|
|
|
// If a full endpoint is specified, check version suffixes for a match first.
|
|
for _, v := range recognized {
|
|
if strings.HasSuffix(identityEndpoint, v.Suffix) {
|
|
return v, identityEndpoint, nil
|
|
}
|
|
}
|
|
|
|
var resp response
|
|
_, err := client.Request("GET", client.IdentityBase, &gophercloud.RequestOpts{
|
|
JSONResponse: &resp,
|
|
OkCodes: []int{200, 300},
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
byID := make(map[string]*Version)
|
|
for _, version := range recognized {
|
|
byID[version.ID] = version
|
|
}
|
|
|
|
var highest *Version
|
|
var endpoint string
|
|
|
|
for _, value := range resp.Versions.Values {
|
|
href := ""
|
|
for _, link := range value.Links {
|
|
if link.Rel == "self" {
|
|
href = normalize(link.Href)
|
|
}
|
|
}
|
|
|
|
if matching, ok := byID[value.ID]; ok {
|
|
// Prefer a version that exactly matches the provided endpoint.
|
|
if href == identityEndpoint {
|
|
if href == "" {
|
|
return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", value.ID, client.IdentityBase)
|
|
}
|
|
return matching, href, nil
|
|
}
|
|
|
|
// Otherwise, find the highest-priority version with a whitelisted status.
|
|
if goodStatus[strings.ToLower(value.Status)] {
|
|
if highest == nil || matching.Priority > highest.Priority {
|
|
highest = matching
|
|
endpoint = href
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if highest == nil {
|
|
return nil, "", fmt.Errorf("No supported version available from endpoint %s", client.IdentityBase)
|
|
}
|
|
if endpoint == "" {
|
|
return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", highest.ID, client.IdentityBase)
|
|
}
|
|
|
|
return highest, endpoint, nil
|
|
}
|