@@ -17,6 +17,15 @@ use crate::libvirt::domain::VirtiofsFilesystem;
1717use crate :: utils:: parse_memory_to_mb;
1818use crate :: xml_utils;
1919
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+
2029/// Firmware type for virtual machines
2130#[ derive( Debug , Clone , Copy , PartialEq , Eq , ValueEnum ) ]
2231#[ clap( rename_all = "kebab-case" ) ]
@@ -117,8 +126,8 @@ pub fn run(global_opts: &crate::libvirt::LibvirtOptions, opts: LibvirtRunOpts) -
117126 // Validate labels don't contain commas
118127 opts. validate_labels ( ) ?;
119128
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 ( ) {
122131 Some ( uri) => DomainLister :: with_connection ( uri. clone ( ) ) ,
123132 None => DomainLister :: new ( ) ,
124133 } ;
@@ -231,24 +240,38 @@ fn get_default_pool_path(connect_uri: &str) -> Utf8PathBuf {
231240}
232241
233242/// 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 < ( ) > {
235244 // 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" ] ) ;
238247 let output = cmd
239248 . output ( )
240249 . with_context ( || "Failed to check for default pool" ) ?;
241250
242251 if output. status . success ( ) {
243252 // 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" ] ) ;
246255 let _ = cmd. output ( ) ; // Ignore errors if already started
247256 return Ok ( ( ) ) ;
248257 }
249258
250259 // 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+ } ;
252275 info ! ( "Creating default storage pool at {:?}" , pool_path) ;
253276
254277 // Create the directory if it doesn't exist
@@ -271,8 +294,8 @@ fn ensure_default_pool(connect_uri: &str) -> Result<()> {
271294 std:: fs:: write ( xml_path, & pool_xml) . with_context ( || "Failed to write pool XML" ) ?;
272295
273296 // 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] ) ;
276299 let output = cmd. output ( ) . with_context ( || "Failed to define pool" ) ?;
277300
278301 if !output. status . success ( ) {
@@ -285,13 +308,13 @@ fn ensure_default_pool(connect_uri: &str) -> Result<()> {
285308 }
286309
287310 // 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" ] ) ;
290313 let _ = cmd. output ( ) ; // Directory might already exist
291314
292315 // 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" ] ) ;
295318 let output = cmd. output ( ) . with_context ( || "Failed to start pool" ) ?;
296319
297320 if !output. status . success ( ) {
@@ -304,8 +327,8 @@ fn ensure_default_pool(connect_uri: &str) -> Result<()> {
304327 }
305328
306329 // 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" ] ) ;
309332 let _ = cmd. output ( ) ; // Not critical if this fails
310333
311334 // Clean up temporary XML file
@@ -316,67 +339,27 @@ fn ensure_default_pool(connect_uri: &str) -> Result<()> {
316339}
317340
318341/// 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) ?;
324345
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" ) ?;
369351
370352 if !output. status . success ( ) {
353+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
354+ let uri_desc = connect_uri. unwrap_or ( "default connection" ) ;
371355 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
374359 ) ) ;
375360 }
376361
377362 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
380363 let dom = xml_utils:: parse_xml_dom ( & xml) . with_context ( || "Failed to parse storage pool XML" ) ?;
381364
382365 if let Some ( path_node) = dom. find ( "path" ) {
@@ -432,7 +415,7 @@ fn generate_unique_vm_name(image: &str, existing_domains: &[String]) -> String {
432415}
433416
434417/// 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 > > {
436419 // Get the storage pool path from XML
437420 let pool_path = get_libvirt_storage_pool_path ( connect_uri) ?;
438421
0 commit comments