Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Prefer versioned service type aliases #3350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions endpoint_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,21 @@ func (eo *EndpointOpts) ApplyDefaults(t string) {
// TODO(stephenfin): This should probably be an error in v3
for t, aliases := range ServiceTypeAliases {
if slices.Contains(aliases, eo.Type) {
// we intentionally override the service type, even if it
// was explicitly requested by the user
eo.Type = t
eo.Aliases = aliases
// we pretend the alias is the official service type and the
// official service type is an alias which allows us to prefer
// what the user requested
// TODO(stephenfin): We should stop doing this once we have
// proper version discovery
// https://github.com/gophercloud/gophercloud/issues/3349
altAliases := []string{t}
for _, alias := range aliases {
if alias == eo.Type {
continue
}
altAliases = append(altAliases, alias)
}
eo.Aliases = altAliases
continue
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions openstack/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,17 +404,17 @@ func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.Endpoi
// 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) {
return initClientOpts(client, eo, "block-storage")
return initClientOpts(client, eo, "volumev2")
}

// NewBlockStorageV3 creates a ServiceClient that may be used to access the v3 block storage service.
func NewBlockStorageV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "block-storage")
return initClientOpts(client, eo, "volumev3")
}

// 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) {
return initClientOpts(client, eo, "shared-file-system")
return initClientOpts(client, eo, "sharev2")
}

// NewOrchestrationV1 creates a ServiceClient that may be used to access the v1
Expand Down Expand Up @@ -485,7 +485,7 @@ func NewContainerInfraV1(client *gophercloud.ProviderClient, eo gophercloud.Endp

// NewWorkflowV2 creates a ServiceClient that may be used with the v2 workflow management package.
func NewWorkflowV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
return initClientOpts(client, eo, "workflow")
return initClientOpts(client, eo, "workflowv2")
}

// NewPlacementV1 creates a ServiceClient that may be used with the placement package.
Expand Down
117 changes: 67 additions & 50 deletions openstack/endpoint_location.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
package openstack

import (
"regexp"
"slices"

"github.com/gophercloud/gophercloud/v2"
tokens2 "github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens"
tokens3 "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens"
)

func extractServiceTypeVersion(serviceType string) string {
versionedServiceTypeAliasRegexp := regexp.MustCompile(`^.*v(\d)$`)

matches := versionedServiceTypeAliasRegexp.FindAllStringSubmatch(serviceType, 1)
if matches != nil {
// no point converting to an int
return matches[0][1]
}
return ""
}

/*
V2EndpointURL discovers the endpoint URL for a specific service from a
ServiceCatalog acquired during the v2 identity service.
Expand All @@ -31,34 +43,29 @@ func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpt
}
}

// If multiple endpoints were found, use the first result
// and disregard the other endpoints.
//
// This behavior matches the Python library. See GH-1764.
if len(endpoints) > 1 {
endpoints = endpoints[0:1]
// Report an error if there were no matching endpoints.
if len(endpoints) == 0 {
err := &gophercloud.ErrEndpointNotFound{}
return "", err
}

// Extract the appropriate URL from the matching Endpoint.
for _, endpoint := range endpoints {
switch opts.Availability {
case gophercloud.AvailabilityPublic:
return gophercloud.NormalizeURL(endpoint.PublicURL), nil
case gophercloud.AvailabilityInternal:
return gophercloud.NormalizeURL(endpoint.InternalURL), nil
case gophercloud.AvailabilityAdmin:
return gophercloud.NormalizeURL(endpoint.AdminURL), nil
default:
err := &ErrInvalidAvailabilityProvided{}
err.Argument = "Availability"
err.Value = opts.Availability
return "", err
}
//
// If multiple endpoints were found, use the first result and disregard the other endpoints.
// This behavior matches the Python library. See GH-1764.
switch opts.Availability {
case gophercloud.AvailabilityPublic:
return gophercloud.NormalizeURL(endpoints[0].PublicURL), nil
case gophercloud.AvailabilityInternal:
return gophercloud.NormalizeURL(endpoints[0].InternalURL), nil
case gophercloud.AvailabilityAdmin:
return gophercloud.NormalizeURL(endpoints[0].AdminURL), nil
default:
err := &ErrInvalidAvailabilityProvided{}
err.Argument = "Availability"
err.Value = opts.Availability
return "", err
}

// Report an error if there were no matching endpoints.
err := &gophercloud.ErrEndpointNotFound{}
return "", err
}

/*
Expand All @@ -72,42 +79,52 @@ will also often need to specify a Name and/or a Region depending on what's
available on your OpenStack deployment.
*/
func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
if opts.Availability != gophercloud.AvailabilityAdmin &&
opts.Availability != gophercloud.AvailabilityPublic &&
opts.Availability != gophercloud.AvailabilityInternal {
err := &ErrInvalidAvailabilityProvided{}
err.Argument = "Availability"
err.Value = opts.Availability
return "", err
}

// Extract Endpoints from the catalog entries that match the requested Type, Interface,
// Name if provided, and Region if provided.
var endpoints = make([]tokens3.Endpoint, 0, 1)

requestedVersion := extractServiceTypeVersion(opts.Type)
entriesByType := map[string][]tokens3.CatalogEntry{}
for _, entry := range catalog.Entries {
if (slices.Contains(opts.Types(), entry.Type)) && (opts.Name == "" || entry.Name == opts.Name) {
for _, endpoint := range entry.Endpoints {
if opts.Availability != gophercloud.AvailabilityAdmin &&
opts.Availability != gophercloud.AvailabilityPublic &&
opts.Availability != gophercloud.AvailabilityInternal {
err := &ErrInvalidAvailabilityProvided{}
err.Argument = "Availability"
err.Value = opts.Availability
return "", err
}
if (opts.Availability == gophercloud.Availability(endpoint.Interface)) &&
(opts.Region == "" || endpoint.Region == opts.Region || endpoint.RegionID == opts.Region) {
endpoints = append(endpoints, endpoint)
// If we explicitly requested e.g. volumev3 and the endpoint is using volumev2, ignore
actualVersion := extractServiceTypeVersion(entry.Type)
if requestedVersion != "" && actualVersion != "" && requestedVersion != actualVersion {
continue
}
entriesByType[entry.Type] = append(entriesByType[entry.Type], entry)
}

for _, serviceType := range opts.Types() {
if entries, ok := entriesByType[serviceType]; ok {
for _, entry := range entries {
for _, endpoint := range entry.Endpoints {
if (opts.Availability == gophercloud.Availability(endpoint.Interface)) &&
(opts.Region == "" || endpoint.Region == opts.Region || endpoint.RegionID == opts.Region) {
endpoints = append(endpoints, endpoint)
}
}
}
}
}

// If multiple endpoints were found, use the first result
// and disregard the other endpoints.
//
// This behavior matches the Python library. See GH-1764.
if len(endpoints) > 1 {
endpoints = endpoints[0:1]
// Report an error if there were no matching endpoints.
if len(endpoints) == 0 {
err := &gophercloud.ErrEndpointNotFound{}
return "", err
}

// Extract the URL from the matching Endpoint.
for _, endpoint := range endpoints {
return gophercloud.NormalizeURL(endpoint.URL), nil
}

// Report an error if there were no matching endpoints.
err := &gophercloud.ErrEndpointNotFound{}
return "", err
//
// If multiple endpoints were found, use the first result and disregard the other endpoints.
// This behavior matches the Python library. See GH-1764.
return gophercloud.NormalizeURL(endpoints[0].URL), nil
}
Loading