Skip to content

Commit 82c2ca0

Browse files
committed
Move discovery logic to its own file
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
1 parent 83e0c32 commit 82c2ca0

File tree

5 files changed

+488
-461
lines changed

5 files changed

+488
-461
lines changed

openstack/utils/choose_version.go

Lines changed: 1 addition & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package utils
33
import (
44
"context"
55
"fmt"
6-
"strconv"
76
"strings"
87

98
"github.com/gophercloud/gophercloud/v2"
@@ -29,6 +28,7 @@ var goodStatus = map[string]bool{
2928
// It returns the highest-Priority Version, OR exact match with client endpoint,
3029
// among the alternatives that are provided, as well as its corresponding endpoint.
3130
func ChooseVersion(ctx context.Context, client *gophercloud.ProviderClient, recognized []*Version) (*Version, string, error) {
31+
// TODO(stephenfin): This could be removed since we can accomplish this with GetServiceVersions now.
3232
type linkResp struct {
3333
Href string `json:"href"`
3434
Rel string `json:"rel"`
@@ -114,129 +114,3 @@ func ChooseVersion(ctx context.Context, client *gophercloud.ProviderClient, reco
114114

115115
return highest, endpoint, nil
116116
}
117-
118-
type SupportedMicroversions struct {
119-
MaxMajor int
120-
MaxMinor int
121-
MinMajor int
122-
MinMinor int
123-
}
124-
125-
// GetServiceVersions returns the minimum and maximum microversion that is supported by the ServiceClient Endpoint.
126-
func GetServiceVersions(ctx context.Context, client *gophercloud.ProviderClient, endpointURL string) (SupportedMicroversions, error) {
127-
type valueResp struct {
128-
ID string `json:"id"`
129-
Status string `json:"status"`
130-
Version string `json:"version"`
131-
MinVersion string `json:"min_version"`
132-
}
133-
134-
type response struct {
135-
Version valueResp `json:"version"`
136-
Versions []valueResp `json:"versions"`
137-
}
138-
var minVersion, maxVersion string
139-
var supportedMicroversions SupportedMicroversions
140-
var resp response
141-
_, err := client.Request(ctx, "GET", endpointURL, &gophercloud.RequestOpts{
142-
JSONResponse: &resp,
143-
OkCodes: []int{200, 300},
144-
})
145-
146-
if err != nil {
147-
return supportedMicroversions, err
148-
}
149-
150-
if len(resp.Versions) > 0 {
151-
// We are dealing with an unversioned endpoint
152-
// We only handle the case when there is exactly one, and assume it is the correct one
153-
if len(resp.Versions) > 1 {
154-
return supportedMicroversions, fmt.Errorf("unversioned endpoint with multiple alternatives not supported")
155-
}
156-
minVersion = resp.Versions[0].MinVersion
157-
maxVersion = resp.Versions[0].Version
158-
} else {
159-
minVersion = resp.Version.MinVersion
160-
maxVersion = resp.Version.Version
161-
}
162-
163-
// Return early if the endpoint does not support microversions
164-
if minVersion == "" && maxVersion == "" {
165-
return supportedMicroversions, fmt.Errorf("microversions not supported by endpoint")
166-
}
167-
168-
supportedMicroversions.MinMajor, supportedMicroversions.MinMinor, err = ParseMicroversion(minVersion)
169-
if err != nil {
170-
return supportedMicroversions, err
171-
}
172-
173-
supportedMicroversions.MaxMajor, supportedMicroversions.MaxMinor, err = ParseMicroversion(maxVersion)
174-
if err != nil {
175-
return supportedMicroversions, err
176-
}
177-
178-
return supportedMicroversions, nil
179-
}
180-
181-
// GetSupportedMicroversions returns the minimum and maximum microversion that is supported by the ServiceClient Endpoint.
182-
func GetSupportedMicroversions(ctx context.Context, client *gophercloud.ServiceClient) (SupportedMicroversions, error) {
183-
return GetServiceVersions(ctx, client.ProviderClient, client.Endpoint)
184-
}
185-
186-
// RequireMicroversion checks that the required microversion is supported and
187-
// returns a ServiceClient with the microversion set.
188-
func RequireMicroversion(ctx context.Context, client gophercloud.ServiceClient, required string) (gophercloud.ServiceClient, error) {
189-
supportedMicroversions, err := GetSupportedMicroversions(ctx, &client)
190-
if err != nil {
191-
return client, fmt.Errorf("unable to determine supported microversions: %w", err)
192-
}
193-
supported, err := supportedMicroversions.IsSupported(required)
194-
if err != nil {
195-
return client, err
196-
}
197-
if !supported {
198-
return client, fmt.Errorf("microversion %s not supported. Supported versions: %v", required, supportedMicroversions)
199-
}
200-
client.Microversion = required
201-
return client, nil
202-
}
203-
204-
// IsSupported checks if a microversion falls in the supported interval.
205-
// It returns true if the version is within the interval and false otherwise.
206-
func (supported SupportedMicroversions) IsSupported(version string) (bool, error) {
207-
// Parse the version X.Y into X and Y integers that are easier to compare.
208-
vMajor, vMinor, err := ParseMicroversion(version)
209-
if err != nil {
210-
return false, err
211-
}
212-
213-
// Check that the major version number is supported.
214-
if (vMajor < supported.MinMajor) || (vMajor > supported.MaxMajor) {
215-
return false, nil
216-
}
217-
218-
// Check that the minor version number is supported
219-
if (vMinor <= supported.MaxMinor) && (vMinor >= supported.MinMinor) {
220-
return true, nil
221-
}
222-
223-
return false, nil
224-
}
225-
226-
// ParseMicroversion parses the version major.minor into separate integers major and minor.
227-
// For example, "2.53" becomes 2 and 53.
228-
func ParseMicroversion(version string) (major int, minor int, err error) {
229-
parts := strings.Split(version, ".")
230-
if len(parts) != 2 {
231-
return 0, 0, fmt.Errorf("invalid microversion format: %q", version)
232-
}
233-
major, err = strconv.Atoi(parts[0])
234-
if err != nil {
235-
return 0, 0, err
236-
}
237-
minor, err = strconv.Atoi(parts[1])
238-
if err != nil {
239-
return 0, 0, err
240-
}
241-
return major, minor, nil
242-
}

openstack/utils/discovery.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package utils
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strconv"
7+
"strings"
8+
9+
"github.com/gophercloud/gophercloud/v2"
10+
)
11+
12+
type SupportedMicroversions struct {
13+
MaxMajor int
14+
MaxMinor int
15+
MinMajor int
16+
MinMinor int
17+
}
18+
19+
// GetServiceVersions returns the minimum and maximum microversion that is supported by the ServiceClient Endpoint.
20+
func GetServiceVersions(ctx context.Context, client *gophercloud.ProviderClient, endpointURL string) (SupportedMicroversions, error) {
21+
type valueResp struct {
22+
ID string `json:"id"`
23+
Status string `json:"status"`
24+
Version string `json:"version"`
25+
MinVersion string `json:"min_version"`
26+
}
27+
28+
type response struct {
29+
Version valueResp `json:"version"`
30+
Versions []valueResp `json:"versions"`
31+
}
32+
var minVersion, maxVersion string
33+
var supportedMicroversions SupportedMicroversions
34+
var resp response
35+
_, err := client.Request(ctx, "GET", endpointURL, &gophercloud.RequestOpts{
36+
JSONResponse: &resp,
37+
OkCodes: []int{200, 300},
38+
})
39+
40+
if err != nil {
41+
return supportedMicroversions, err
42+
}
43+
44+
if len(resp.Versions) > 0 {
45+
// We are dealing with an unversioned endpoint
46+
// We only handle the case when there is exactly one, and assume it is the correct one
47+
if len(resp.Versions) > 1 {
48+
return supportedMicroversions, fmt.Errorf("unversioned endpoint with multiple alternatives not supported")
49+
}
50+
minVersion = resp.Versions[0].MinVersion
51+
maxVersion = resp.Versions[0].Version
52+
} else {
53+
minVersion = resp.Version.MinVersion
54+
maxVersion = resp.Version.Version
55+
}
56+
57+
// Return early if the endpoint does not support microversions
58+
if minVersion == "" && maxVersion == "" {
59+
return supportedMicroversions, fmt.Errorf("microversions not supported by endpoint")
60+
}
61+
62+
supportedMicroversions.MinMajor, supportedMicroversions.MinMinor, err = ParseMicroversion(minVersion)
63+
if err != nil {
64+
return supportedMicroversions, err
65+
}
66+
67+
supportedMicroversions.MaxMajor, supportedMicroversions.MaxMinor, err = ParseMicroversion(maxVersion)
68+
if err != nil {
69+
return supportedMicroversions, err
70+
}
71+
72+
return supportedMicroversions, nil
73+
}
74+
75+
// GetSupportedMicroversions returns the minimum and maximum microversion that is supported by the ServiceClient Endpoint.
76+
func GetSupportedMicroversions(ctx context.Context, client *gophercloud.ServiceClient) (SupportedMicroversions, error) {
77+
return GetServiceVersions(ctx, client.ProviderClient, client.Endpoint)
78+
}
79+
80+
// RequireMicroversion checks that the required microversion is supported and
81+
// returns a ServiceClient with the microversion set.
82+
func RequireMicroversion(ctx context.Context, client gophercloud.ServiceClient, required string) (gophercloud.ServiceClient, error) {
83+
supportedMicroversions, err := GetSupportedMicroversions(ctx, &client)
84+
if err != nil {
85+
return client, fmt.Errorf("unable to determine supported microversions: %w", err)
86+
}
87+
supported, err := supportedMicroversions.IsSupported(required)
88+
if err != nil {
89+
return client, err
90+
}
91+
if !supported {
92+
return client, fmt.Errorf("microversion %s not supported. Supported versions: %v", required, supportedMicroversions)
93+
}
94+
client.Microversion = required
95+
return client, nil
96+
}
97+
98+
// IsSupported checks if a microversion falls in the supported interval.
99+
// It returns true if the version is within the interval and false otherwise.
100+
func (supported SupportedMicroversions) IsSupported(version string) (bool, error) {
101+
// Parse the version X.Y into X and Y integers that are easier to compare.
102+
vMajor, vMinor, err := ParseMicroversion(version)
103+
if err != nil {
104+
return false, err
105+
}
106+
107+
// Check that the major version number is supported.
108+
if (vMajor < supported.MinMajor) || (vMajor > supported.MaxMajor) {
109+
return false, nil
110+
}
111+
112+
// Check that the minor version number is supported
113+
if (vMinor <= supported.MaxMinor) && (vMinor >= supported.MinMinor) {
114+
return true, nil
115+
}
116+
117+
return false, nil
118+
}
119+
120+
// ParseMicroversion parses the version major.minor into separate integers major and minor.
121+
// For example, "2.53" becomes 2 and 53.
122+
func ParseMicroversion(version string) (major int, minor int, err error) {
123+
parts := strings.Split(version, ".")
124+
if len(parts) != 2 {
125+
return 0, 0, fmt.Errorf("invalid microversion format: %q", version)
126+
}
127+
major, err = strconv.Atoi(parts[0])
128+
if err != nil {
129+
return 0, 0, err
130+
}
131+
minor, err = strconv.Atoi(parts[1])
132+
if err != nil {
133+
return 0, 0, err
134+
}
135+
return major, minor, nil
136+
}

0 commit comments

Comments
 (0)