Skip to content

Commit c436020

Browse files
committed
Choose a version from an API base endpoint.
1 parent 0545143 commit c436020

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

openstack/utils/choose_version.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/racker/perigee"
7+
)
8+
9+
// Version is a supported API version, corresponding to a vN package within the appropriate service.
10+
type Version struct {
11+
ID string
12+
Priority int
13+
}
14+
15+
// ChooseVersion queries the base endpoint of a API to choose the most recent non-experimental alternative from a service's
16+
// published versions.
17+
// It returns the highest-Priority Version among the alternatives that are provided, as well as its corresponding endpoint.
18+
func ChooseVersion(baseEndpoint string, recognized []*Version) (*Version, string, error) {
19+
type linkResp struct {
20+
Href string `json:"href"`
21+
Rel string `json:"rel"`
22+
}
23+
24+
type valueResp struct {
25+
ID string `json:"id"`
26+
Status string `json:"status"`
27+
Links []linkResp `json:"links"`
28+
}
29+
30+
type versionsResp struct {
31+
Values []valueResp `json:"values"`
32+
}
33+
34+
type response struct {
35+
Versions versionsResp `json:"versions"`
36+
}
37+
38+
var resp response
39+
_, err := perigee.Request("GET", baseEndpoint, perigee.Options{
40+
Results: &resp,
41+
OkCodes: []int{200},
42+
})
43+
44+
if err != nil {
45+
return nil, "", err
46+
}
47+
48+
byID := make(map[string]*Version)
49+
for _, version := range recognized {
50+
byID[version.ID] = version
51+
}
52+
53+
var highest *Version
54+
var endpoint string
55+
56+
for _, value := range resp.Versions.Values {
57+
if matching, ok := byID[value.ID]; ok {
58+
if highest == nil || matching.Priority > highest.Priority {
59+
highest = matching
60+
61+
found := false
62+
for _, link := range value.Links {
63+
if link.Rel == "self" {
64+
found = true
65+
endpoint = link.Href
66+
}
67+
}
68+
69+
if !found {
70+
return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", value.ID, baseEndpoint)
71+
}
72+
}
73+
}
74+
}
75+
76+
if highest == nil || endpoint == "" {
77+
return nil, "", fmt.Errorf("No supported version available from endpoint %s", baseEndpoint)
78+
}
79+
80+
return highest, endpoint, nil
81+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/rackspace/gophercloud/testhelper"
9+
)
10+
11+
func TestChooseVersion(t *testing.T) {
12+
testhelper.SetupHTTP()
13+
defer testhelper.TeardownHTTP()
14+
15+
testhelper.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
16+
fmt.Fprintf(w, `
17+
{
18+
"versions": {
19+
"values": [
20+
{
21+
"status": "stable",
22+
"id": "v3.0",
23+
"links": [
24+
{ "href": "https://example.com:1000/", "rel": "self" }
25+
]
26+
},
27+
{
28+
"status": "stable",
29+
"id": "v2.0",
30+
"links": [
31+
{ "href": "https://example.com:2000/", "rel": "self" }
32+
]
33+
}
34+
]
35+
}
36+
}
37+
`)
38+
})
39+
40+
v2 := &Version{ID: "v2.0", Priority: 2}
41+
v3 := &Version{ID: "v3.0", Priority: 3}
42+
43+
v, endpoint, err := ChooseVersion(testhelper.Endpoint(), []*Version{v2, v3})
44+
45+
if err != nil {
46+
t.Fatalf("Unexpected error from ChooseVersion: %v", err)
47+
}
48+
49+
if v != v3 {
50+
t.Errorf("Expected %#v to win, but %#v did instead", v3, v)
51+
}
52+
53+
expected := "https://example.com:1000/"
54+
if endpoint != expected {
55+
t.Errorf("Expected endpoint [%s], but was [%s] instead", expected, endpoint)
56+
}
57+
}

0 commit comments

Comments
 (0)