blob: 5a311e4085506e87eb797d4894ac6385a82f74a8 [file] [log] [blame]
Ash Wilson5c0161c2014-10-07 10:42:34 -04001package openstack
2
3import (
4 "fmt"
5
6 "github.com/rackspace/gophercloud"
7 tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
Ash Wilson130a6e22014-10-07 10:48:17 -04008 endpoints3 "github.com/rackspace/gophercloud/openstack/identity/v3/endpoints"
9 services3 "github.com/rackspace/gophercloud/openstack/identity/v3/services"
10 "github.com/rackspace/gophercloud/pagination"
Ash Wilson5c0161c2014-10-07 10:42:34 -040011)
12
13// V2EndpointURL discovers the endpoint URL for a specific service from a ServiceCatalog acquired
14// during the v2 identity service. The specified EndpointOpts are used to identify a unique,
15// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided
16// criteria and when none do. The minimum that can be specified is a Type, but you will also often
17// need to specify a Name and/or a Region depending on what's available on your OpenStack
18// deployment.
19func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
20 // Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided.
21 var endpoints = make([]tokens2.Endpoint, 0, 1)
22 for _, entry := range catalog.Entries {
23 if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) {
24 for _, endpoint := range entry.Endpoints {
25 if opts.Region == "" || endpoint.Region == opts.Region {
26 endpoints = append(endpoints, endpoint)
27 }
28 }
29 }
30 }
31
32 // Report an error if the options were ambiguous.
Ash Wilson5c0161c2014-10-07 10:42:34 -040033 if len(endpoints) > 1 {
34 return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints)
35 }
36
37 // Extract the appropriate URL from the matching Endpoint.
38 for _, endpoint := range endpoints {
39 switch opts.Availability {
40 case gophercloud.AvailabilityPublic:
41 return gophercloud.NormalizeURL(endpoint.PublicURL), nil
42 case gophercloud.AvailabilityInternal:
43 return gophercloud.NormalizeURL(endpoint.InternalURL), nil
44 case gophercloud.AvailabilityAdmin:
45 return gophercloud.NormalizeURL(endpoint.AdminURL), nil
46 default:
47 return "", fmt.Errorf("Unexpected availability in endpoint query: %s", opts.Availability)
48 }
49 }
50
Ash Wilsonfc1af5a2014-10-08 09:10:41 -040051 // Report an error if there were no matching endpoints.
Ash Wilson5c0161c2014-10-07 10:42:34 -040052 return "", gophercloud.ErrEndpointNotFound
53}
Ash Wilson130a6e22014-10-07 10:48:17 -040054
Ash Wilson61c49a52014-10-08 14:15:04 -040055// V3EndpointURL discovers the endpoint URL for a specific service using multiple calls against
Ash Wilson130a6e22014-10-07 10:48:17 -040056// an identity v3 service endpoint. The specified EndpointOpts are used to identify a unique,
57// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided
58// criteria and when none do. The minimum that can be specified is a Type, but you will also often
59// need to specify a Name and/or a Region depending on what's available on your OpenStack
60// deployment.
Ash Wilson61c49a52014-10-08 14:15:04 -040061func V3EndpointURL(v3Client *gophercloud.ServiceClient, opts gophercloud.EndpointOpts) (string, error) {
Ash Wilson130a6e22014-10-07 10:48:17 -040062 // Discover the service we're interested in.
63 var services = make([]services3.Service, 0, 1)
64 servicePager := services3.List(v3Client, services3.ListOpts{ServiceType: opts.Type})
65 err := servicePager.EachPage(func(page pagination.Page) (bool, error) {
66 part, err := services3.ExtractServices(page)
67 if err != nil {
68 return false, err
69 }
70
71 for _, service := range part {
72 if service.Name == opts.Name {
73 services = append(services, service)
74 }
75 }
76
77 return true, nil
78 })
79 if err != nil {
80 return "", err
81 }
82
83 if len(services) == 0 {
84 return "", gophercloud.ErrServiceNotFound
85 }
86 if len(services) > 1 {
87 return "", fmt.Errorf("Discovered %d matching services: %#v", len(services), services)
88 }
89 service := services[0]
90
91 // Enumerate the endpoints available for this service.
92 var endpoints []endpoints3.Endpoint
93 endpointPager := endpoints3.List(v3Client, endpoints3.ListOpts{
94 Availability: opts.Availability,
95 ServiceID: service.ID,
96 })
97 err = endpointPager.EachPage(func(page pagination.Page) (bool, error) {
98 part, err := endpoints3.ExtractEndpoints(page)
99 if err != nil {
100 return false, err
101 }
102
103 for _, endpoint := range part {
104 if opts.Region == "" || endpoint.Region == opts.Region {
105 endpoints = append(endpoints, endpoint)
106 }
107 }
108
109 return true, nil
110 })
111 if err != nil {
112 return "", err
113 }
114
115 if len(endpoints) == 0 {
116 return "", gophercloud.ErrEndpointNotFound
117 }
118 if len(endpoints) > 1 {
119 return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints)
120 }
121 endpoint := endpoints[0]
122
123 return gophercloud.NormalizeURL(endpoint.URL), nil
124}