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  }