| package openstack |
| |
| import ( |
| "fmt" |
| |
| "github.com/rackspace/gophercloud" |
| tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens" |
| endpoints3 "github.com/rackspace/gophercloud/openstack/identity/v3/endpoints" |
| services3 "github.com/rackspace/gophercloud/openstack/identity/v3/services" |
| "github.com/rackspace/gophercloud/pagination" |
| ) |
| |
| // V2EndpointURL discovers the endpoint URL for a specific service from a ServiceCatalog acquired |
| // during the v2 identity service. The specified EndpointOpts are used to identify a unique, |
| // unambiguous endpoint to return. It's an error both when multiple endpoints match the provided |
| // criteria and when none do. The minimum that can be specified is a Type, but you will also often |
| // need to specify a Name and/or a Region depending on what's available on your OpenStack |
| // deployment. |
| func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) { |
| // Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided. |
| var endpoints = make([]tokens2.Endpoint, 0, 1) |
| for _, entry := range catalog.Entries { |
| if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { |
| for _, endpoint := range entry.Endpoints { |
| if opts.Region == "" || endpoint.Region == opts.Region { |
| endpoints = append(endpoints, endpoint) |
| } |
| } |
| } |
| } |
| |
| // Report an error if the options were ambiguous. |
| if len(endpoints) > 1 { |
| return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints) |
| } |
| |
| // 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: |
| return "", fmt.Errorf("Unexpected availability in endpoint query: %s", opts.Availability) |
| } |
| } |
| |
| // Report an error if there were no matching endpoints. |
| return "", gophercloud.ErrEndpointNotFound |
| } |
| |
| // V3EndpointURL discovers the endpoint URL for a specific service using multiple calls against |
| // an identity v3 service endpoint. The specified EndpointOpts are used to identify a unique, |
| // unambiguous endpoint to return. It's an error both when multiple endpoints match the provided |
| // criteria and when none do. The minimum that can be specified is a Type, but you will also often |
| // need to specify a Name and/or a Region depending on what's available on your OpenStack |
| // deployment. |
| func V3EndpointURL(v3Client *gophercloud.ServiceClient, opts gophercloud.EndpointOpts) (string, error) { |
| // Discover the service we're interested in. |
| var services = make([]services3.Service, 0, 1) |
| servicePager := services3.List(v3Client, services3.ListOpts{ServiceType: opts.Type}) |
| err := servicePager.EachPage(func(page pagination.Page) (bool, error) { |
| part, err := services3.ExtractServices(page) |
| if err != nil { |
| return false, err |
| } |
| |
| for _, service := range part { |
| if service.Name == opts.Name { |
| services = append(services, service) |
| } |
| } |
| |
| return true, nil |
| }) |
| if err != nil { |
| return "", err |
| } |
| |
| if len(services) == 0 { |
| return "", gophercloud.ErrServiceNotFound |
| } |
| if len(services) > 1 { |
| return "", fmt.Errorf("Discovered %d matching services: %#v", len(services), services) |
| } |
| service := services[0] |
| |
| // Enumerate the endpoints available for this service. |
| var endpoints []endpoints3.Endpoint |
| endpointPager := endpoints3.List(v3Client, endpoints3.ListOpts{ |
| Availability: opts.Availability, |
| ServiceID: service.ID, |
| }) |
| err = endpointPager.EachPage(func(page pagination.Page) (bool, error) { |
| part, err := endpoints3.ExtractEndpoints(page) |
| if err != nil { |
| return false, err |
| } |
| |
| for _, endpoint := range part { |
| if opts.Region == "" || endpoint.Region == opts.Region { |
| endpoints = append(endpoints, endpoint) |
| } |
| } |
| |
| return true, nil |
| }) |
| if err != nil { |
| return "", err |
| } |
| |
| if len(endpoints) == 0 { |
| return "", gophercloud.ErrEndpointNotFound |
| } |
| if len(endpoints) > 1 { |
| return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints) |
| } |
| endpoint := endpoints[0] |
| |
| return gophercloud.NormalizeURL(endpoint.URL), nil |
| } |