blob: 649c8425fb624cf9fd421814a947e18c239d1914 [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
Krzysztof Szukiełojć3f41d082017-05-07 14:43:06 +02007 "gerrit.mcp.mirantis.net/debian/gophercloud.git"
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
Ash Wilsonc4360202014-08-29 14:14:24 -040071 var highest *Version
72 var endpoint string
73
74 for _, value := range resp.Versions.Values {
Ash Wilsona0c4c842014-09-09 11:30:58 -040075 href := ""
76 for _, link := range value.Links {
77 if link.Rel == "self" {
Ash Wilsone7da01c2014-09-09 12:31:06 -040078 href = normalize(link.Href)
Ash Wilsona0c4c842014-09-09 11:30:58 -040079 }
80 }
Ash Wilsonc4360202014-08-29 14:14:24 -040081
Joe Topjiand74641f2017-07-25 02:58:19 +000082 for _, version := range recognized {
83 if strings.Contains(value.ID, version.ID) {
84 // Prefer a version that exactly matches the provided endpoint.
85 if href == identityEndpoint {
86 if href == "" {
87 return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", value.ID, client.IdentityBase)
88 }
89 return version, href, nil
Ash Wilsonc4360202014-08-29 14:14:24 -040090 }
91
Joe Topjiand74641f2017-07-25 02:58:19 +000092 // Otherwise, find the highest-priority version with a whitelisted status.
93 if goodStatus[strings.ToLower(value.Status)] {
94 if highest == nil || version.Priority > highest.Priority {
95 highest = version
96 endpoint = href
97 }
Ash Wilsonc4360202014-08-29 14:14:24 -040098 }
99 }
100 }
101 }
102
Ash Wilsona0c4c842014-09-09 11:30:58 -0400103 if highest == nil {
Ash Wilson2491b4c2015-02-12 16:13:39 -0500104 return nil, "", fmt.Errorf("No supported version available from endpoint %s", client.IdentityBase)
Ash Wilsona0c4c842014-09-09 11:30:58 -0400105 }
106 if endpoint == "" {
Ash Wilson2491b4c2015-02-12 16:13:39 -0500107 return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", highest.ID, client.IdentityBase)
Ash Wilsonc4360202014-08-29 14:14:24 -0400108 }
109
110 return highest, endpoint, nil
111}