blob: 6dbb8aca0bb7c1fceb0c1cfe0f5f804cdbc35d60 [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
7 "github.com/racker/perigee"
8)
9
10// Version is a supported API version, corresponding to a vN package within the appropriate service.
11type Version struct {
12 ID string
13 Priority int
14}
15
Ash Wilsonaef9dc52014-08-29 14:21:26 -040016var goodStatus = map[string]bool{
17 "current": true,
18 "supported": true,
19 "stable": true,
20}
21
Ash Wilsonc4360202014-08-29 14:14:24 -040022// ChooseVersion queries the base endpoint of a API to choose the most recent non-experimental alternative from a service's
23// published versions.
24// It returns the highest-Priority Version among the alternatives that are provided, as well as its corresponding endpoint.
25func ChooseVersion(baseEndpoint string, recognized []*Version) (*Version, string, error) {
26 type linkResp struct {
27 Href string `json:"href"`
28 Rel string `json:"rel"`
29 }
30
31 type valueResp struct {
32 ID string `json:"id"`
33 Status string `json:"status"`
34 Links []linkResp `json:"links"`
35 }
36
37 type versionsResp struct {
38 Values []valueResp `json:"values"`
39 }
40
41 type response struct {
42 Versions versionsResp `json:"versions"`
43 }
44
45 var resp response
46 _, err := perigee.Request("GET", baseEndpoint, perigee.Options{
47 Results: &resp,
48 OkCodes: []int{200},
49 })
50
51 if err != nil {
52 return nil, "", err
53 }
54
55 byID := make(map[string]*Version)
56 for _, version := range recognized {
57 byID[version.ID] = version
58 }
59
60 var highest *Version
61 var endpoint string
62
63 for _, value := range resp.Versions.Values {
Ash Wilsonaef9dc52014-08-29 14:21:26 -040064 if matching, ok := byID[value.ID]; ok && goodStatus[strings.ToLower(value.Status)] {
Ash Wilsonc4360202014-08-29 14:14:24 -040065 if highest == nil || matching.Priority > highest.Priority {
66 highest = matching
67
68 found := false
69 for _, link := range value.Links {
70 if link.Rel == "self" {
71 found = true
72 endpoint = link.Href
73 }
74 }
75
76 if !found {
77 return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", value.ID, baseEndpoint)
78 }
79 }
80 }
81 }
82
83 if highest == nil || endpoint == "" {
84 return nil, "", fmt.Errorf("No supported version available from endpoint %s", baseEndpoint)
85 }
86
87 return highest, endpoint, nil
88}