github.com/huaweicloud/golangsdk@v0.0.0-20210831081626-d823fe11ceba/openstack/utils/choose_version.go (about) 1 package utils 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/huaweicloud/golangsdk" 8 ) 9 10 // Version is a supported API version, corresponding to a vN package within the appropriate service. 11 type Version struct { 12 ID string 13 Suffix string 14 Priority int 15 } 16 17 var goodStatus = map[string]bool{ 18 "current": true, 19 "supported": true, 20 "stable": true, 21 } 22 23 // ChooseVersion queries the base endpoint of an API to choose the most recent non-experimental alternative from a service's 24 // published versions. 25 // It returns the highest-Priority Version among the alternatives that are provided, as well as its corresponding endpoint. 26 func ChooseVersion(client *golangsdk.ProviderClient, recognized []*Version) (*Version, string, error) { 27 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 46 normalize := func(endpoint string) string { 47 if !strings.HasSuffix(endpoint, "/") { 48 return endpoint + "/" 49 } 50 return endpoint 51 } 52 identityEndpoint := normalize(client.IdentityEndpoint) 53 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 } 60 61 var resp response 62 _, err := client.Request("GET", client.IdentityBase, &golangsdk.RequestOpts{ 63 JSONResponse: &resp, 64 OkCodes: []int{200, 300}, 65 }) 66 67 if err != nil { 68 return nil, "", err 69 } 70 71 var highest *Version 72 var endpoint string 73 74 for _, value := range resp.Versions.Values { 75 href := "" 76 for _, link := range value.Links { 77 if link.Rel == "self" { 78 href = normalize(link.Href) 79 } 80 } 81 82 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 90 } 91 92 // 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 } 98 } 99 } 100 } 101 } 102 103 if highest == nil { 104 return nil, "", fmt.Errorf("No supported version available from endpoint %s", client.IdentityBase) 105 } 106 if endpoint == "" { 107 return nil, "", fmt.Errorf("Endpoint missing in version %s response from %s", highest.ID, client.IdentityBase) 108 } 109 110 return highest, endpoint, nil 111 }