@@ -20,6 +20,8 @@ import (
20
20
"context"
21
21
"fmt"
22
22
sysos "os"
23
+ "slices"
24
+ "strings"
23
25
24
26
"github.com/gophercloud/gophercloud"
25
27
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
@@ -33,9 +35,9 @@ import (
33
35
34
36
// InstancesV2 encapsulates an implementation of InstancesV2 for OpenStack.
35
37
type InstancesV2 struct {
36
- compute * gophercloud.ServiceClient
37
- network * gophercloud.ServiceClient
38
- region string
38
+ compute map [ string ] * gophercloud.ServiceClient
39
+ network map [ string ] * gophercloud.ServiceClient
40
+ regions [] string
39
41
regionProviderID bool
40
42
networkingOpts NetworkingOpts
41
43
}
@@ -51,16 +53,25 @@ func (os *OpenStack) InstancesV2() (cloudprovider.InstancesV2, bool) {
51
53
func (os * OpenStack ) instancesv2 () (* InstancesV2 , bool ) {
52
54
klog .V (4 ).Info ("openstack.Instancesv2() called" )
53
55
54
- compute , err := client .NewComputeV2 (os .provider , os .epOpts )
55
- if err != nil {
56
- klog .Errorf ("unable to access compute v2 API : %v" , err )
57
- return nil , false
58
- }
56
+ var err error
57
+ compute := make (map [string ]* gophercloud.ServiceClient , len (os .regions ))
58
+ network := make (map [string ]* gophercloud.ServiceClient , len (os .regions ))
59
59
60
- network , err := client .NewNetworkV2 (os .provider , os .epOpts )
61
- if err != nil {
62
- klog .Errorf ("unable to access network v2 API : %v" , err )
63
- return nil , false
60
+ for _ , region := range os .regions {
61
+ opt := os .epOpts
62
+ opt .Region = region
63
+
64
+ compute [region ], err = client .NewComputeV2 (os .provider , opt )
65
+ if err != nil {
66
+ klog .Errorf ("unable to access compute v2 API : %v" , err )
67
+ return nil , false
68
+ }
69
+
70
+ network [region ], err = client .NewNetworkV2 (os .provider , opt )
71
+ if err != nil {
72
+ klog .Errorf ("unable to access network v2 API : %v" , err )
73
+ return nil , false
74
+ }
64
75
}
65
76
66
77
regionalProviderID := false
@@ -71,17 +82,23 @@ func (os *OpenStack) instancesv2() (*InstancesV2, bool) {
71
82
return & InstancesV2 {
72
83
compute : compute ,
73
84
network : network ,
74
- region : os .epOpts . Region ,
85
+ regions : os .regions ,
75
86
regionProviderID : regionalProviderID ,
76
87
networkingOpts : os .networkingOpts ,
77
88
}, true
78
89
}
79
90
80
91
// InstanceExists indicates whether a given node exists according to the cloud provider
81
92
func (i * InstancesV2 ) InstanceExists (ctx context.Context , node * v1.Node ) (bool , error ) {
82
- _ , err := i .getInstance (ctx , node )
93
+ klog .V (4 ).InfoS ("openstack.InstanceExists() called" , "node" , klog .KObj (node ),
94
+ "providerID" , node .Spec .ProviderID ,
95
+ "region" , node .Labels [v1 .LabelTopologyRegion ])
96
+
97
+ _ , _ , err := i .getInstance (ctx , node )
83
98
if err == cloudprovider .InstanceNotFound {
84
- klog .V (6 ).Infof ("instance not found for node: %s" , node .Name )
99
+ klog .V (6 ).InfoS ("Node is not found in cloud provider" , "node" , klog .KObj (node ),
100
+ "providerID" , node .Spec .ProviderID ,
101
+ "region" , node .Labels [v1 .LabelTopologyRegion ])
85
102
return false , nil
86
103
}
87
104
@@ -94,7 +111,11 @@ func (i *InstancesV2) InstanceExists(ctx context.Context, node *v1.Node) (bool,
94
111
95
112
// InstanceShutdown returns true if the instance is shutdown according to the cloud provider.
96
113
func (i * InstancesV2 ) InstanceShutdown (ctx context.Context , node * v1.Node ) (bool , error ) {
97
- server , err := i .getInstance (ctx , node )
114
+ klog .V (4 ).InfoS ("openstack.InstanceShutdown() called" , "node" , klog .KObj (node ),
115
+ "providerID" , node .Spec .ProviderID ,
116
+ "region" , node .Labels [v1 .LabelTopologyRegion ])
117
+
118
+ server , _ , err := i .getInstance (ctx , node )
98
119
if err != nil {
99
120
return false , err
100
121
}
@@ -109,7 +130,7 @@ func (i *InstancesV2) InstanceShutdown(ctx context.Context, node *v1.Node) (bool
109
130
110
131
// InstanceMetadata returns the instance's metadata.
111
132
func (i * InstancesV2 ) InstanceMetadata (ctx context.Context , node * v1.Node ) (* cloudprovider.InstanceMetadata , error ) {
112
- srv , err := i .getInstance (ctx , node )
133
+ srv , region , err := i .getInstance (ctx , node )
113
134
if err != nil {
114
135
return nil , err
115
136
}
@@ -118,79 +139,128 @@ func (i *InstancesV2) InstanceMetadata(ctx context.Context, node *v1.Node) (*clo
118
139
server = * srv
119
140
}
120
141
121
- instanceType , err := srvInstanceType (i .compute , & server .Server )
142
+ instanceType , err := srvInstanceType (i .compute [ region ] , & server .Server )
122
143
if err != nil {
123
144
return nil , err
124
145
}
125
146
126
- ports , err := getAttachedPorts (i .network , server .ID )
147
+ ports , err := getAttachedPorts (i .network [ region ] , server .ID )
127
148
if err != nil {
128
149
return nil , err
129
150
}
130
151
131
- addresses , err := nodeAddresses (& server .Server , ports , i .network , i .networkingOpts )
152
+ addresses , err := nodeAddresses (& server .Server , ports , i .network [ region ] , i .networkingOpts )
132
153
if err != nil {
133
154
return nil , err
134
155
}
135
156
136
157
return & cloudprovider.InstanceMetadata {
137
- ProviderID : i .makeInstanceID (& server .Server ),
158
+ ProviderID : i .makeInstanceID (& server .Server , region ),
138
159
InstanceType : instanceType ,
139
160
NodeAddresses : addresses ,
140
161
Zone : server .AvailabilityZone ,
141
- Region : i . region ,
162
+ Region : region ,
142
163
}, nil
143
164
}
144
165
145
- func (i * InstancesV2 ) makeInstanceID (srv * servers.Server ) string {
166
+ func (i * InstancesV2 ) makeInstanceID (srv * servers.Server , region string ) string {
146
167
if i .regionProviderID {
147
- return fmt .Sprintf ("%s://%s/%s" , ProviderName , i . region , srv .ID )
168
+ return fmt .Sprintf ("%s://%s/%s" , ProviderName , region , srv .ID )
148
169
}
149
170
return fmt .Sprintf ("%s:///%s" , ProviderName , srv .ID )
150
171
}
151
172
152
- func (i * InstancesV2 ) getInstance (ctx context.Context , node * v1.Node ) (* ServerAttributesExt , error ) {
153
- if node .Spec .ProviderID == "" {
154
- opt := servers.ListOpts {
155
- Name : fmt .Sprintf ("^%s$" , node .Name ),
156
- }
157
- mc := metrics .NewMetricContext ("server" , "list" )
158
- allPages , err := servers .List (i .compute , opt ).AllPages ()
159
- if mc .ObserveRequest (err ) != nil {
160
- return nil , fmt .Errorf ("error listing servers %v: %v" , opt , err )
161
- }
173
+ func (i * InstancesV2 ) getInstance (ctx context.Context , node * v1.Node ) (* ServerAttributesExt , string , error ) {
174
+ klog .V (4 ).InfoS ("openstack.getInstance() called" , "node" , klog .KObj (node ),
175
+ "providerID" , node .Spec .ProviderID ,
176
+ "region" , node .Labels [v1 .LabelTopologyRegion ])
162
177
163
- serverList := []ServerAttributesExt {}
164
- err = servers .ExtractServersInto (allPages , & serverList )
165
- if err != nil {
166
- return nil , fmt .Errorf ("error extracting servers from pages: %v" , err )
167
- }
168
- if len (serverList ) == 0 {
169
- return nil , cloudprovider .InstanceNotFound
170
- }
171
- if len (serverList ) > 1 {
172
- return nil , fmt .Errorf ("getInstance: multiple instances found" )
173
- }
174
- return & serverList [0 ], nil
178
+ if node .Spec .ProviderID == "" {
179
+ return i .getInstanceByName (node )
175
180
}
176
181
177
182
instanceID , instanceRegion , err := instanceIDFromProviderID (node .Spec .ProviderID )
178
183
if err != nil {
179
- return nil , err
184
+ return nil , "" , err
185
+ }
186
+
187
+ if instanceRegion == "" {
188
+ return i .getInstanceByID (instanceID , node .Labels [v1 .LabelTopologyRegion ])
180
189
}
181
190
182
- if instanceRegion != "" && instanceRegion != i . region {
183
- return nil , fmt .Errorf ("ProviderID \" %s\" didn't match supported region \" %s\" " , node .Spec .ProviderID , i . region )
191
+ if ! slices . Contains ( i . regions , instanceRegion ) {
192
+ return nil , "" , fmt .Errorf ("getInstance: ProviderID \" %s\" didn't match supported regions \" %s\" " , node .Spec .ProviderID , strings . Join ( i . regions , "," ) )
184
193
}
185
194
186
195
server := ServerAttributesExt {}
187
196
mc := metrics .NewMetricContext ("server" , "get" )
188
- err = servers .Get (i .compute , instanceID ).ExtractInto (& server )
197
+ err = servers .Get (i .compute [ instanceRegion ] , instanceID ).ExtractInto (& server )
189
198
if mc .ObserveRequest (err ) != nil {
190
199
if errors .IsNotFound (err ) {
191
- return nil , cloudprovider .InstanceNotFound
200
+ return nil , "" , cloudprovider .InstanceNotFound
192
201
}
193
- return nil , err
202
+ return nil , "" , err
194
203
}
195
- return & server , nil
204
+
205
+ return & server , instanceRegion , nil
206
+ }
207
+
208
+ func (i * InstancesV2 ) getInstanceByID (instanceID , preferedRegion string ) (* ServerAttributesExt , string , error ) {
209
+ server := ServerAttributesExt {}
210
+ regions := i .regions
211
+
212
+ if preferedRegion != "" && slices .Contains (i .regions , preferedRegion ) {
213
+ regions = []string {preferedRegion }
214
+ for _ , r := range i .regions {
215
+ if r != preferedRegion {
216
+ regions = append (regions , r )
217
+ }
218
+ }
219
+ }
220
+
221
+ mc := metrics .NewMetricContext ("server" , "get" )
222
+ for _ , r := range regions {
223
+ err := servers .Get (i .compute [r ], instanceID ).ExtractInto (& server )
224
+ if mc .ObserveRequest (err ) != nil {
225
+ if errors .IsNotFound (err ) {
226
+ continue
227
+ }
228
+
229
+ return nil , "" , err
230
+ }
231
+
232
+ return & server , r , nil
233
+ }
234
+
235
+ return nil , "" , cloudprovider .InstanceNotFound
236
+ }
237
+
238
+ func (i * InstancesV2 ) getInstanceByName (node * v1.Node ) (* ServerAttributesExt , string , error ) {
239
+ opt := servers.ListOpts {
240
+ Name : fmt .Sprintf ("^%s$" , node .Name ),
241
+ }
242
+ mc := metrics .NewMetricContext ("server" , "list" )
243
+ serverList := []ServerAttributesExt {}
244
+
245
+ for _ , r := range i .regions {
246
+ allPages , err := servers .List (i .compute [r ], opt ).AllPages ()
247
+ if mc .ObserveRequest (err ) != nil {
248
+ return nil , "" , fmt .Errorf ("error listing servers %v: %v" , opt , err )
249
+ }
250
+
251
+ err = servers .ExtractServersInto (allPages , & serverList )
252
+ if err != nil {
253
+ return nil , "" , fmt .Errorf ("error extracting servers from pages: %v" , err )
254
+ }
255
+ if len (serverList ) == 0 {
256
+ continue
257
+ }
258
+ if len (serverList ) > 1 {
259
+ return nil , "" , fmt .Errorf ("getInstanceByName: multiple instances found" )
260
+ }
261
+
262
+ return & serverList [0 ], r , nil
263
+ }
264
+
265
+ return nil , "" , cloudprovider .InstanceNotFound
196
266
}
0 commit comments