blob: c605d084444db8342052a56fcda4ed5d2015b45f [file] [log] [blame]
Ash Wilsonc4360202014-08-29 14:14:24 -04001package utils
2
3import (
4 "fmt"
Ash Wilsonaef9dc52014-08-29 14:21:26 -04005 "strings"
Ash Wilsonc4360202014-08-29 14:14:24 -04006
Jon Perritt27249f42016-02-18 10:35:59 -06007 "github.com/gophercloud/gophercloud"
Ash Wilsonc4360202014-08-29 14:14:24 -04008)
9
10// Version is a supported API version, corresponding to a vN package within the appropriate service.
11type Version struct {
12 ID string
Ash Wilson09694b92014-09-09 14:08:27 -040013 Suffix string
Ash Wilsonc4360202014-08-29 14:14:24 -040014 Priority int
15}
16
Ash Wilsonaef9dc52014-08-29 14:21:26 -040017var goodStatus = map[string]bool{
18 "current": true,
19 "supported": true,
20 "stable": true,
21}
22
Alex Gaynora6d5f9f2014-10-27 10:52:32 -070023// ChooseVersion queries the base endpoint of an API to choose the most recent non-experimental alternative from a service's
Ash Wilsonc4360202014-08-29 14:14:24 -040024// published versions.
25// It returns the highest-Priority Version among the alternatives that are provided, as well as its corresponding endpoint.
Ash Wilson2491b4c2015-02-12 16:13:39 -050026func ChooseVersion(client *gophercloud.ProviderClient, recognized []*Version) (*Version, string, error) {
Ash Wilsonc4360202014-08-29 14:14:24 -040027 type linkResp struct {
28 Href string `json:"href"`
29 Rel string `json:"rel"`
30 }
31
32 type valueResp struct {
33 ID string `json:"id"`
34 Status string `json:"status"`
35 Links []linkResp `json:"links"`
36 }
37
38 type versionsResp struct {
39 Values []valueResp `json:"values"`
40 }
41
42 type response struct {
43 Versions versionsResp `json:"versions"`
44 }
45
Ash Wilson09694b92014-09-09 14:08:27 -040046 normalize := func(endpoint string) string {
47 if !strings.HasSuffix(endpoint, "/") {
48 return endpoint + "/"
49 }
50 return endpoint
Ash Wilsona0c4c842014-09-09 11:30:58 -040051 }
Ash Wilson2491b4c2015-02-12 16:13:39 -050052 identityEndpoint := normalize(client.IdentityEndpoint)
Ash Wilson09694b92014-09-09 14:08:27 -040053
54 // If a full endpoint is specified, check version suffixes for a match first.
55 for _, v := range recognized {
56 if strings.HasSuffix(identityEndpoint, v.Suffix) {
57 return v, identityEndpoint, nil
58 }
59 }
Ash Wilsona0c4c842014-09-09 11:30:58 -040060
Ash Wilsonc4360202014-08-29 14:14:24 -040061 var resp response
Jon Perritta33da232016-03-02 04:43:08 -060062 _, err := client.Request("GET", client.IdentityBase, &gophercloud.RequestOpts{
Ash Wilson4bf41a32015-02-12 15:52:44 -050063 JSONResponse: &resp,
64 OkCodes: []int{200, 300},
Ash Wilsonc4360202014-08-29 14:14:24 -040065 })
66
67 if err != nil {
68 return nil, "", err
69 }
70
71 byID := make(map[string]*Version)
72 for _, version := range recognized {
73 byID[version.ID] = version
74 }
75
76 var highest *Version
77 var endpoint string
78
79 for _, value := range resp.Versions.Values {
Ash Wilsona0c4c842014-09-09 11:30:58 -040080 href := ""
81 for _, link := range value.Links {
82 if link.Rel == "self" {
Ash Wilsone7da01c2014-09-09 12:31:06 -040083 href = normalize(link.Href)
Ash Wilsona0c4c842014-09-09 11:30:58 -040084 }
85 }
Ash Wilsonc4360202014-08-29 14:14:24 -040086
Ash Wilsona0c4c842014-09-09 11:30:58 -040087 if matching, ok := byID[value.ID]; ok {
88 // Prefer a version that exactly matches the provided endpoint.
Ash Wilson09694b92014-09-09 14:08:27 -040089 if href == identityEndpoint {
Ash Wilsona0c4c842014-09-09 11:30:58 -040090 if href == "" {
Ash Wilson2491b4c2015-02-12 16:13:39 -050091 return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", value.ID, client.IdentityBase)
Ash Wilsonc4360202014-08-29 14:14:24 -040092 }
Ash Wilsona0c4c842014-09-09 11:30:58 -040093 return matching, href, nil
94 }
Ash Wilsonc4360202014-08-29 14:14:24 -040095
Ash Wilsona0c4c842014-09-09 11:30:58 -040096 // Otherwise, find the highest-priority version with a whitelisted status.
97 if goodStatus[strings.ToLower(value.Status)] {
98 if highest == nil || matching.Priority > highest.Priority {
99 highest = matching
100 endpoint = href
Ash Wilsonc4360202014-08-29 14:14:24 -0400101 }
102 }
103 }
104 }
105
Ash Wilsona0c4c842014-09-09 11:30:58 -0400106 if highest == nil {
Ash Wilson2491b4c2015-02-12 16:13:39 -0500107 return nil, "", fmt.Errorf("No supported version available from endpoint %s", client.IdentityBase)
Ash Wilsona0c4c842014-09-09 11:30:58 -0400108 }
109 if endpoint == "" {
Ash Wilson2491b4c2015-02-12 16:13:39 -0500110 return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", highest.ID, client.IdentityBase)
Ash Wilsonc4360202014-08-29 14:14:24 -0400111 }
112
113 return highest, endpoint, nil
114}