@@ -17,6 +17,15 @@ use crate::libvirt::domain::VirtiofsFilesystem;
17
17
use crate :: utils:: parse_memory_to_mb;
18
18
use crate :: xml_utils;
19
19
20
+ /// Create a virsh command with optional connection URI
21
+ pub ( super ) fn virsh_command ( connect_uri : Option < & str > ) -> Result < std:: process:: Command > {
22
+ let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
23
+ if let Some ( uri) = connect_uri {
24
+ cmd. arg ( "-c" ) . arg ( uri) ;
25
+ }
26
+ Ok ( cmd)
27
+ }
28
+
20
29
/// Firmware type for virtual machines
21
30
#[ derive( Debug , Clone , Copy , PartialEq , Eq , ValueEnum ) ]
22
31
#[ clap( rename_all = "kebab-case" ) ]
@@ -117,8 +126,8 @@ pub fn run(global_opts: &crate::libvirt::LibvirtOptions, opts: LibvirtRunOpts) -
117
126
// Validate labels don't contain commas
118
127
opts. validate_labels ( ) ?;
119
128
120
- let connect_uri = global_opts. connect . as_ref ( ) ;
121
- let lister = match connect_uri {
129
+ let connect_uri = global_opts. connect . as_deref ( ) ;
130
+ let lister = match global_opts . connect . as_ref ( ) {
122
131
Some ( uri) => DomainLister :: with_connection ( uri. clone ( ) ) ,
123
132
None => DomainLister :: new ( ) ,
124
133
} ;
@@ -231,24 +240,38 @@ fn get_default_pool_path(connect_uri: &str) -> Utf8PathBuf {
231
240
}
232
241
233
242
/// Ensure the default libvirt storage pool exists, creating it if necessary
234
- fn ensure_default_pool ( connect_uri : & str ) -> Result < ( ) > {
243
+ fn ensure_default_pool ( connect_uri : Option < & str > ) -> Result < ( ) > {
235
244
// Check if default pool already exists
236
- let mut cmd = crate :: hostexec :: command ( "virsh" , None ) ?;
237
- cmd. args ( & [ "-c" , connect_uri , " pool-info", "default" ] ) ;
245
+ let mut cmd = virsh_command ( connect_uri ) ?;
246
+ cmd. args ( & [ "pool-info" , "default" ] ) ;
238
247
let output = cmd
239
248
. output ( )
240
249
. with_context ( || "Failed to check for default pool" ) ?;
241
250
242
251
if output. status . success ( ) {
243
252
// Pool exists, make sure it's active
244
- let mut cmd = crate :: hostexec :: command ( "virsh" , None ) ?;
245
- cmd. args ( & [ "-c" , connect_uri , " pool-start", "default" ] ) ;
253
+ let mut cmd = virsh_command ( connect_uri ) ?;
254
+ cmd. args ( & [ "pool-start" , "default" ] ) ;
246
255
let _ = cmd. output ( ) ; // Ignore errors if already started
247
256
return Ok ( ( ) ) ;
248
257
}
249
258
250
259
// Pool doesn't exist, need to create it
251
- let pool_path = get_default_pool_path ( connect_uri) ;
260
+ // Determine the appropriate pool path based on the connection URI
261
+ let pool_path = if let Some ( uri) = connect_uri {
262
+ get_default_pool_path ( uri)
263
+ } else {
264
+ // If no URI specified, virsh will use its default connection
265
+ // We need to query what that is to determine the appropriate pool path
266
+ let mut cmd = virsh_command ( None ) ?;
267
+ cmd. args ( & [ "uri" ] ) ;
268
+ let output = cmd
269
+ . output ( )
270
+ . with_context ( || "Failed to query default libvirt URI" ) ?;
271
+ let uri_str = String :: from_utf8 ( output. stdout )
272
+ . with_context ( || "Invalid UTF-8 in virsh uri output" ) ?;
273
+ get_default_pool_path ( uri_str. trim ( ) )
274
+ } ;
252
275
info ! ( "Creating default storage pool at {:?}" , pool_path) ;
253
276
254
277
// Create the directory if it doesn't exist
@@ -271,8 +294,8 @@ fn ensure_default_pool(connect_uri: &str) -> Result<()> {
271
294
std:: fs:: write ( xml_path, & pool_xml) . with_context ( || "Failed to write pool XML" ) ?;
272
295
273
296
// Define the pool
274
- let mut cmd = crate :: hostexec :: command ( "virsh" , None ) ?;
275
- cmd. args ( & [ "-c" , connect_uri , " pool-define", xml_path] ) ;
297
+ let mut cmd = virsh_command ( connect_uri ) ?;
298
+ cmd. args ( & [ "pool-define" , xml_path] ) ;
276
299
let output = cmd. output ( ) . with_context ( || "Failed to define pool" ) ?;
277
300
278
301
if !output. status . success ( ) {
@@ -285,13 +308,13 @@ fn ensure_default_pool(connect_uri: &str) -> Result<()> {
285
308
}
286
309
287
310
// Build the pool (creates directory structure)
288
- let mut cmd = crate :: hostexec :: command ( "virsh" , None ) ?;
289
- cmd. args ( & [ "-c" , connect_uri , " pool-build", "default" ] ) ;
311
+ let mut cmd = virsh_command ( connect_uri ) ?;
312
+ cmd. args ( & [ "pool-build" , "default" ] ) ;
290
313
let _ = cmd. output ( ) ; // Directory might already exist
291
314
292
315
// Start the pool
293
- let mut cmd = crate :: hostexec :: command ( "virsh" , None ) ?;
294
- cmd. args ( & [ "-c" , connect_uri , " pool-start", "default" ] ) ;
316
+ let mut cmd = virsh_command ( connect_uri ) ?;
317
+ cmd. args ( & [ "pool-start" , "default" ] ) ;
295
318
let output = cmd. output ( ) . with_context ( || "Failed to start pool" ) ?;
296
319
297
320
if !output. status . success ( ) {
@@ -304,8 +327,8 @@ fn ensure_default_pool(connect_uri: &str) -> Result<()> {
304
327
}
305
328
306
329
// Autostart the pool
307
- let mut cmd = crate :: hostexec :: command ( "virsh" , None ) ?;
308
- cmd. args ( & [ "-c" , connect_uri , " pool-autostart", "default" ] ) ;
330
+ let mut cmd = virsh_command ( connect_uri ) ?;
331
+ cmd. args ( & [ "pool-autostart" , "default" ] ) ;
309
332
let _ = cmd. output ( ) ; // Not critical if this fails
310
333
311
334
// Clean up temporary XML file
@@ -316,67 +339,27 @@ fn ensure_default_pool(connect_uri: &str) -> Result<()> {
316
339
}
317
340
318
341
/// Get the path of the default libvirt storage pool
319
- pub fn get_libvirt_storage_pool_path ( connect_uri : Option < & String > ) -> Result < Utf8PathBuf > {
320
- // If a specific connection URI is provided, use it
321
- if let Some ( uri) = connect_uri {
322
- // Ensure pool exists before querying
323
- ensure_default_pool ( uri) ?;
342
+ pub fn get_libvirt_storage_pool_path ( connect_uri : Option < & str > ) -> Result < Utf8PathBuf > {
343
+ // Ensure pool exists before querying
344
+ ensure_default_pool ( connect_uri) ?;
324
345
325
- let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
326
- cmd. args ( & [ "-c" , uri, "pool-dumpxml" , "default" ] ) ;
327
- let output = cmd
328
- . output ( )
329
- . with_context ( || "Failed to query libvirt storage pool" ) ?;
330
-
331
- if output. status . success ( ) {
332
- let xml = String :: from_utf8 ( output. stdout )
333
- . with_context ( || "Invalid UTF-8 in virsh output" ) ?;
334
- let dom = xml_utils:: parse_xml_dom ( & xml)
335
- . with_context ( || "Failed to parse storage pool XML" ) ?;
336
-
337
- if let Some ( path_node) = dom. find ( "path" ) {
338
- let path_str = path_node. text_content ( ) . trim ( ) ;
339
- if !path_str. is_empty ( ) {
340
- return Ok ( Utf8PathBuf :: from ( path_str) ) ;
341
- }
342
- }
343
- }
344
- }
345
-
346
- // Try user session first (qemu:///session)
347
- let session_uri = "qemu:///session" ;
348
- ensure_default_pool ( session_uri) ?;
349
-
350
- let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
351
- cmd. args ( & [ "-c" , session_uri, "pool-dumpxml" , "default" ] ) ;
352
- let output = cmd. output ( ) ;
353
-
354
- let ( output, uri_used) = match output {
355
- Ok ( o) if o. status . success ( ) => ( o, session_uri) ,
356
- _ => {
357
- // Try system session (qemu:///system)
358
- let system_uri = "qemu:///system" ;
359
- ensure_default_pool ( system_uri) ?;
360
-
361
- let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
362
- cmd. args ( & [ "-c" , system_uri, "pool-dumpxml" , "default" ] ) ;
363
- let out = cmd
364
- . output ( )
365
- . with_context ( || "Failed to query libvirt storage pool" ) ?;
366
- ( out, system_uri)
367
- }
368
- } ;
346
+ let mut cmd = virsh_command ( connect_uri) ?;
347
+ cmd. args ( & [ "pool-dumpxml" , "default" ] ) ;
348
+ let output = cmd
349
+ . output ( )
350
+ . with_context ( || "Failed to query libvirt storage pool" ) ?;
369
351
370
352
if !output. status . success ( ) {
353
+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
354
+ let uri_desc = connect_uri. unwrap_or ( "default connection" ) ;
371
355
return Err ( color_eyre:: eyre:: eyre!(
372
- "Failed to get default storage pool info for {}" ,
373
- uri_used
356
+ "Failed to get default storage pool info for {}: {}" ,
357
+ uri_desc,
358
+ stderr
374
359
) ) ;
375
360
}
376
361
377
362
let xml = String :: from_utf8 ( output. stdout ) . with_context ( || "Invalid UTF-8 in virsh output" ) ?;
378
-
379
- // Parse XML using DOM parser and extract path element
380
363
let dom = xml_utils:: parse_xml_dom ( & xml) . with_context ( || "Failed to parse storage pool XML" ) ?;
381
364
382
365
if let Some ( path_node) = dom. find ( "path" ) {
@@ -432,7 +415,7 @@ fn generate_unique_vm_name(image: &str, existing_domains: &[String]) -> String {
432
415
}
433
416
434
417
/// List all volumes in the default storage pool
435
- pub fn list_storage_pool_volumes ( connect_uri : Option < & String > ) -> Result < Vec < Utf8PathBuf > > {
418
+ pub fn list_storage_pool_volumes ( connect_uri : Option < & str > ) -> Result < Vec < Utf8PathBuf > > {
436
419
// Get the storage pool path from XML
437
420
let pool_path = get_libvirt_storage_pool_path ( connect_uri) ?;
438
421
0 commit comments