1
1
package drivers
2
2
3
3
import (
4
+ "bufio"
4
5
"encoding/json"
5
6
"fmt"
7
+ "os"
6
8
"strings"
7
9
8
10
"github.com/lxc/incus/v6/shared/api"
9
11
"github.com/lxc/incus/v6/shared/logger"
10
12
"github.com/lxc/incus/v6/shared/subprocess"
13
+ "github.com/lxc/incus/v6/shared/util"
11
14
)
12
15
13
16
// CephGetRBDImageName returns the RBD image name as it is used in ceph.
@@ -182,21 +185,21 @@ func CephMonitors(cluster string) (Monitors, error) {
182
185
183
186
// CephKeyring retrieves the CephX key for the given entity.
184
187
func CephKeyring (cluster string , client string ) (string , error ) {
188
+ // See if we can't find it from the filesystem directly (short path).
189
+ value , err := cephKeyringFromFile (cluster , client )
190
+ if err == nil {
191
+ return value , nil
192
+ }
193
+
185
194
// If client isn't prefixed, prefix it with 'client.'.
186
195
if ! strings .Contains (client , "." ) {
187
196
client = "client." + client
188
197
}
189
198
190
199
// Check that cephx is enabled.
191
- authType , err := callCeph (
192
- "--cluster" , cluster ,
193
- "config" , "get" , client , "auth_service_required" ,
194
- )
200
+ authType , err := callCeph ("--cluster" , cluster , "config" , "get" , client , "auth_service_required" )
195
201
if err != nil {
196
- return "" , fmt .Errorf (
197
- "Failed to query ceph config for auth_service_required: %w" ,
198
- err ,
199
- )
202
+ return "" , fmt .Errorf ("Failed to query ceph config for auth_service_required: %w" , err )
200
203
}
201
204
202
205
if authType == "none" {
@@ -208,20 +211,119 @@ func CephKeyring(cluster string, client string) (string, error) {
208
211
key := struct {
209
212
Key string `json:"key"`
210
213
}{}
211
- err = callCephJSON (& key ,
212
- "--cluster" , cluster ,
213
- "auth" , "get-key" , client ,
214
- )
214
+ err = callCephJSON (& key , "--cluster" , cluster , "auth" , "get-key" , client )
215
215
if err != nil {
216
- return "" , fmt .Errorf (
217
- "Failed to get keyring for %q on %q: %w" ,
218
- client , cluster , err ,
219
- )
216
+ return "" , fmt .Errorf ("Failed to get keyring for %q on %q: %w" , client , cluster , err )
220
217
}
221
218
222
219
return key .Key , nil
223
220
}
224
221
222
+ func cephGetKeyFromFile (path string ) (string , error ) {
223
+ cephKeyring , err := os .Open (path )
224
+ if err != nil {
225
+ return "" , fmt .Errorf ("Failed to open %q: %w" , path , err )
226
+ }
227
+
228
+ // Locate the keyring entry and its value.
229
+ var cephSecret string
230
+ scan := bufio .NewScanner (cephKeyring )
231
+ for scan .Scan () {
232
+ line := scan .Text ()
233
+ line = strings .TrimSpace (line )
234
+
235
+ if line == "" {
236
+ continue
237
+ }
238
+
239
+ if strings .HasPrefix (line , "key" ) {
240
+ fields := strings .SplitN (line , "=" , 2 )
241
+ if len (fields ) < 2 {
242
+ continue
243
+ }
244
+
245
+ cephSecret = strings .TrimSpace (fields [1 ])
246
+ break
247
+ }
248
+ }
249
+
250
+ if cephSecret == "" {
251
+ return "" , fmt .Errorf ("Couldn't find a keyring entry" )
252
+ }
253
+
254
+ return cephSecret , nil
255
+ }
256
+
257
+ // cephKeyringFromFile gets the key for a particular Ceph cluster and client name.
258
+ func cephKeyringFromFile (cluster string , client string ) (string , error ) {
259
+ var cephSecret string
260
+ cephConfigPath := fmt .Sprintf ("/etc/ceph/%v.conf" , cluster )
261
+
262
+ keyringPathFull := fmt .Sprintf ("/etc/ceph/%v.client.%v.keyring" , cluster , client )
263
+ keyringPathCluster := fmt .Sprintf ("/etc/ceph/%v.keyring" , cluster )
264
+ keyringPathGlobal := "/etc/ceph/keyring"
265
+ keyringPathGlobalBin := "/etc/ceph/keyring.bin"
266
+
267
+ if util .PathExists (keyringPathFull ) {
268
+ return cephGetKeyFromFile (keyringPathFull )
269
+ } else if util .PathExists (keyringPathCluster ) {
270
+ return cephGetKeyFromFile (keyringPathCluster )
271
+ } else if util .PathExists (keyringPathGlobal ) {
272
+ return cephGetKeyFromFile (keyringPathGlobal )
273
+ } else if util .PathExists (keyringPathGlobalBin ) {
274
+ return cephGetKeyFromFile (keyringPathGlobalBin )
275
+ } else if util .PathExists (cephConfigPath ) {
276
+ // Open the CEPH config file.
277
+ cephConfig , err := os .Open (cephConfigPath )
278
+ if err != nil {
279
+ return "" , fmt .Errorf ("Failed to open %q: %w" , cephConfigPath , err )
280
+ }
281
+
282
+ // Locate the keyring entry and its value.
283
+ scan := bufio .NewScanner (cephConfig )
284
+ for scan .Scan () {
285
+ line := scan .Text ()
286
+ line = strings .TrimSpace (line )
287
+
288
+ if line == "" {
289
+ continue
290
+ }
291
+
292
+ if strings .HasPrefix (line , "key" ) {
293
+ fields := strings .SplitN (line , "=" , 2 )
294
+ if len (fields ) < 2 {
295
+ continue
296
+ }
297
+
298
+ // Check all key related config keys.
299
+ switch strings .TrimSpace (fields [0 ]) {
300
+ case "key" :
301
+ cephSecret = strings .TrimSpace (fields [1 ])
302
+ case "keyfile" :
303
+ key , err := os .ReadFile (fields [1 ])
304
+ if err != nil {
305
+ return "" , err
306
+ }
307
+
308
+ cephSecret = strings .TrimSpace (string (key ))
309
+ case "keyring" :
310
+ return cephGetKeyFromFile (strings .TrimSpace (fields [1 ]))
311
+ }
312
+ }
313
+
314
+ if cephSecret != "" {
315
+ break
316
+ }
317
+ }
318
+ }
319
+
320
+ if cephSecret == "" {
321
+ return "" , fmt .Errorf ("Couldn't find a keyring entry" )
322
+ }
323
+
324
+ return cephSecret , nil
325
+ }
326
+
225
327
// CephFsid retrieves the FSID for the given cluster.
226
328
func CephFsid (cluster string ) (string , error ) {
227
329
// Call ceph fsid.
0 commit comments