@@ -3,6 +3,7 @@ package swift
3
3
import (
4
4
"crypto/tls"
5
5
"crypto/x509"
6
+ "errors"
6
7
"fmt"
7
8
"net/http"
8
9
"reflect"
@@ -19,7 +20,7 @@ import (
19
20
yamlv2 "gopkg.in/yaml.v2"
20
21
21
22
corev1 "k8s.io/api/core/v1"
22
- "k8s.io/apimachinery/pkg/api/errors"
23
+ apimachineryerrors "k8s.io/apimachinery/pkg/api/errors"
23
24
k8sutilerrors "k8s.io/apimachinery/pkg/util/errors"
24
25
"k8s.io/klog/v2"
25
26
@@ -63,19 +64,26 @@ func replaceEmpty(a string, b string) string {
63
64
}
64
65
65
66
// IsSwiftEnabled checks if Swift service is available for OpenStack platform
66
- func IsSwiftEnabled (listers * regopclient.StorageListers ) bool {
67
+ func IsSwiftEnabled (listers * regopclient.StorageListers ) ( bool , error ) {
67
68
driver := NewDriver (& imageregistryv1.ImageRegistryConfigStorageSwift {}, listers )
68
69
conn , err := driver .getSwiftClient ()
69
70
if err != nil {
70
- klog .Errorf ("swift storage inaccessible: %v" , err )
71
- return false
71
+ if errors .As (err , & ErrContainerEndpointNotFound {}) {
72
+ klog .Errorf ("error connecting to Swift: %v" , err )
73
+ return false , nil
74
+ }
75
+ klog .Errorf ("error connecting to OpenStack: %v" , err )
76
+ return false , err
72
77
}
78
+
73
79
// Try to list containers to make sure the user has required permissions to do that
74
- if _ , err = containers .List (conn , containers.ListOpts {}).AllPages (); err != nil {
80
+ if err := containers .List (conn , containers.ListOpts {}).EachPage (func (_ pagination.Page ) (bool , error ) {
81
+ return false , nil
82
+ }); err != nil {
75
83
klog .Errorf ("error listing swift containers: %v" , err )
76
- return false
84
+ return false , nil
77
85
}
78
- return true
86
+ return true , nil
79
87
}
80
88
81
89
// GetConfig reads credentials
@@ -84,7 +92,7 @@ func GetConfig(listers *regopclient.StorageListers) (*Swift, error) {
84
92
85
93
// Look for a user defined secret to get the Swift credentials
86
94
sec , err := listers .Secrets .Get (defaults .ImageRegistryPrivateConfigurationUser )
87
- if err != nil && errors .IsNotFound (err ) {
95
+ if err != nil && apimachineryerrors .IsNotFound (err ) {
88
96
// If no user defined credentials were provided, then try to find them in the secret,
89
97
// created by cloud-credential-operator.
90
98
sec , err = listers .Secrets .Get (defaults .CloudCredentialsName )
@@ -103,7 +111,7 @@ func GetConfig(listers *regopclient.StorageListers) (*Swift, error) {
103
111
var cloudName string
104
112
cloudInfra , err := util .GetInfrastructure (listers )
105
113
if err != nil {
106
- if ! errors .IsNotFound (err ) {
114
+ if ! apimachineryerrors .IsNotFound (err ) {
107
115
return nil , fmt .Errorf ("failed to get cluster infrastructure info: %v" , err )
108
116
}
109
117
}
@@ -173,7 +181,7 @@ func GetConfig(listers *regopclient.StorageListers) (*Swift, error) {
173
181
// system trust bundle should be used instead.
174
182
func (d * driver ) CABundle () (string , bool , error ) {
175
183
cm , err := d .Listers .OpenShiftConfig .Get ("cloud-provider-config" )
176
- if errors .IsNotFound (err ) {
184
+ if apimachineryerrors .IsNotFound (err ) {
177
185
return "" , true , nil
178
186
}
179
187
if err != nil {
@@ -186,6 +194,15 @@ func (d *driver) CABundle() (string, bool, error) {
186
194
return caBundle , false , nil
187
195
}
188
196
197
+ type ErrContainerEndpointNotFound struct {
198
+ wrapped error
199
+ }
200
+
201
+ func (err ErrContainerEndpointNotFound ) Unwrap () error { return err .wrapped }
202
+ func (err ErrContainerEndpointNotFound ) Error () string {
203
+ return fmt .Sprintf ("container endpoint not found in the OpenStack catalog: %v" , err .wrapped )
204
+ }
205
+
189
206
// getSwiftClient returns a client that allows to interact with the OpenStack Swift service
190
207
func (d * driver ) getSwiftClient () (* gophercloud.ServiceClient , error ) {
191
208
cfg , err := GetConfig (d .Listers )
@@ -215,18 +232,18 @@ func (d *driver) getSwiftClient() (*gophercloud.ServiceClient, error) {
215
232
216
233
provider , err := openstack .NewClient (opts .IdentityEndpoint )
217
234
if err != nil {
218
- return nil , fmt .Errorf ("Create new provider client failed : %v " , err )
235
+ return nil , fmt .Errorf ("failed to create a new OpenStack provider client: %w " , err )
219
236
}
220
237
221
238
cert , _ , err := d .CABundle ()
222
239
if err != nil {
223
- return nil , fmt .Errorf ("Failed to get cloud provider CA certificate: %v " , err )
240
+ return nil , fmt .Errorf ("failed to get cloud provider CA certificate: %w " , err )
224
241
}
225
242
226
243
if cert != "" {
227
244
certPool , err := x509 .SystemCertPool ()
228
245
if err != nil {
229
- return nil , fmt .Errorf ("Create system cert pool failed : %v " , err )
246
+ return nil , fmt .Errorf ("failed to read the system cert pool: %w " , err )
230
247
}
231
248
certPool .AppendCertsFromPEM ([]byte (cert ))
232
249
client := http.Client {
@@ -241,24 +258,42 @@ func (d *driver) getSwiftClient() (*gophercloud.ServiceClient, error) {
241
258
242
259
err = openstack .Authenticate (provider , * opts )
243
260
if err != nil {
244
- return nil , fmt .Errorf ("Failed to authenticate provider client : %v " , err )
261
+ return nil , fmt .Errorf ("failed to authenticate against OpenStack : %w " , err )
245
262
}
246
263
247
264
endpointOpts := gophercloud.EndpointOpts {
248
265
Region : regionName ,
249
266
Name : "swift" ,
250
267
}
251
268
252
- var client * gophercloud.ServiceClient
253
- client , err = openstack .NewContainerV1 (provider , endpointOpts )
254
- if _ , ok := err .(* gophercloud.ErrEndpointNotFound ); ok {
255
- endpointOpts .Type = "object-store"
256
- client , err = openstack .NewContainerV1 (provider , endpointOpts )
257
- if err != nil {
258
- return nil , err
269
+ client , err := openstack .NewContainerV1 (provider , endpointOpts )
270
+ if err != nil {
271
+ if _ , ok := err .(* gophercloud.ErrEndpointNotFound ); ok {
272
+ // In gophercloud the default endpoint type for
273
+ // containers is "container". However, some OpenStack
274
+ // clouds are deployed with a single endpoint type for
275
+ // all Swift entities - "object-store".
276
+ //
277
+ // If a "container" endpoint is not found, then try
278
+ // "object-store".
279
+ endpointOpts .Type = "object-store"
280
+
281
+ var errOnAlternativeEndpoint error
282
+ client , errOnAlternativeEndpoint = openstack .NewContainerV1 (provider , endpointOpts )
283
+ if errOnAlternativeEndpoint != nil {
284
+ if _ , ok := errOnAlternativeEndpoint .(* gophercloud.ErrEndpointNotFound ); ok {
285
+ // If none of the endpoints is found, then
286
+ // return the error we got on the default one
287
+ // so that we limit confusion on the error
288
+ // trace.
289
+ return nil , ErrContainerEndpointNotFound {err }
290
+ } else {
291
+ return nil , fmt .Errorf ("failed to get the object storage alternative endpoint: %w" , errOnAlternativeEndpoint )
292
+ }
293
+ }
294
+ return client , nil
259
295
}
260
- } else if err != nil {
261
- return nil , err
296
+ return nil , fmt .Errorf ("failed to get the object storage endpoint: %w" , err )
262
297
}
263
298
264
299
return client , nil
0 commit comments