@@ -30,19 +30,30 @@ import (
30
30
"github.com/gophercloud/utils/v2/openstack/clientconfig"
31
31
32
32
"sigs.k8s.io/cluster-api-provider-openstack/pkg/metrics"
33
+ openstackutil "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/openstack"
33
34
)
34
35
35
36
/*
36
- NovaMinimumMicroversion is the minimum Nova microversion supported by CAPO
37
- 2.60 corresponds to OpenStack Queens
37
+ Constants for specific microversion requirements.
38
+ 2.60 corresponds to OpenStack Queens and 2.53 to OpenStack Pike,
39
+ 2.38 is the maximum in OpenStack Newton.
38
40
39
41
For the canonical description of Nova microversions, see
40
42
https://docs.openstack.org/nova/latest/reference/api-microversion-history.html
41
43
42
- CAPO uses server tags, which were added in microversion 2.52.
44
+ CAPO uses server tags, which were first added in microversion 2.26 and then refined
45
+ in 2.52 so it is possible to apply them when creating a server (which is what CAPO does).
46
+ We round up to 2.53 here since that takes us to the maximum in Pike.
47
+
43
48
CAPO supports multiattach volume types, which were added in microversion 2.60.
49
+
50
+ 2.38 was chosen as a base level since it is reasonably old, but not too old.
44
51
*/
45
- const NovaMinimumMicroversion = "2.60"
52
+ const (
53
+ MinimumNovaMicroversion = "2.38"
54
+ NovaTagging = "2.53"
55
+ NovaMultiAttachVolume = "2.60"
56
+ )
46
57
47
58
type ComputeClient interface {
48
59
ListAvailabilityZones () ([]availabilityzones.AvailabilityZone , error )
@@ -57,9 +68,14 @@ type ComputeClient interface {
57
68
DeleteAttachedInterface (serverID , portID string ) error
58
69
59
70
ListServerGroups () ([]servergroups.ServerGroup , error )
71
+ WithMicroversion (required string ) (ComputeClient , error )
60
72
}
61
73
62
- type computeClient struct { client * gophercloud.ServiceClient }
74
+ type computeClient struct {
75
+ client * gophercloud.ServiceClient
76
+ minVersion string
77
+ maxVersion string
78
+ }
63
79
64
80
// NewComputeClient returns a new compute client.
65
81
func NewComputeClient (providerClient * gophercloud.ProviderClient , providerClientOpts * clientconfig.ClientOpts ) (ComputeClient , error ) {
@@ -70,9 +86,25 @@ func NewComputeClient(providerClient *gophercloud.ProviderClient, providerClient
70
86
if err != nil {
71
87
return nil , fmt .Errorf ("failed to create compute service client: %v" , err )
72
88
}
73
- compute .Microversion = NovaMinimumMicroversion
74
89
75
- return & computeClient {compute }, nil
90
+ // Find the minimum and maximum versions supported by the server
91
+ serviceMin , serviceMax , err := openstackutil .GetSupportedMicroversions (* compute )
92
+ if err != nil {
93
+ return nil , fmt .Errorf ("unable to verify compatible server version: %w" , err )
94
+ }
95
+
96
+ supported , err := openstackutil .MicroversionSupported (MinimumNovaMicroversion , serviceMin , serviceMax )
97
+ if err != nil {
98
+ return nil , fmt .Errorf ("unable to verify compatible server version: %w" , err )
99
+ }
100
+ if ! supported {
101
+ return nil , fmt .Errorf ("no compatible server version. CAPO requires %s, but min=%s and max=%s" ,
102
+ MinimumNovaMicroversion , serviceMin , serviceMax )
103
+ }
104
+
105
+ compute .Microversion = MinimumNovaMicroversion
106
+
107
+ return & computeClient {client : compute , minVersion : serviceMin , maxVersion : serviceMax }, nil
76
108
}
77
109
78
110
func (c computeClient ) ListAvailabilityZones () ([]availabilityzones.AvailabilityZone , error ) {
@@ -154,6 +186,21 @@ func (c computeClient) ListServerGroups() ([]servergroups.ServerGroup, error) {
154
186
return servergroups .ExtractServerGroups (allPages )
155
187
}
156
188
189
+ // WithMicroversion checks that the required Nova microversion is supported and sets it for
190
+ // the ComputeClient.
191
+ func (c computeClient ) WithMicroversion (required string ) (ComputeClient , error ) {
192
+ supported , err := openstackutil .MicroversionSupported (required , c .minVersion , c .maxVersion )
193
+ if err != nil {
194
+ return nil , err
195
+ }
196
+ if ! supported {
197
+ return nil , fmt .Errorf ("microversion %s not supported. Min=%s, max=%s" , required , c .minVersion , c .maxVersion )
198
+ }
199
+ versionedClient := c
200
+ versionedClient .client .Microversion = required
201
+ return versionedClient , nil
202
+ }
203
+
157
204
type computeErrorClient struct { error }
158
205
159
206
// NewComputeErrorClient returns a ComputeClient in which every method returns the given error.
@@ -196,3 +243,7 @@ func (e computeErrorClient) DeleteAttachedInterface(_, _ string) error {
196
243
func (e computeErrorClient ) ListServerGroups () ([]servergroups.ServerGroup , error ) {
197
244
return nil , e .error
198
245
}
246
+
247
+ func (e computeErrorClient ) WithMicroversion (_ string ) (ComputeClient , error ) {
248
+ return nil , e .error
249
+ }
0 commit comments