@@ -190,10 +190,116 @@ pub fn run(global_opts: &crate::libvirt::LibvirtOptions, opts: LibvirtRunOpts) -
190
190
}
191
191
}
192
192
193
+ /// Determine the appropriate default storage pool path based on connection type
194
+ fn get_default_pool_path ( connect_uri : & str ) -> Utf8PathBuf {
195
+ if connect_uri. contains ( "/session" ) {
196
+ // User session: use XDG_DATA_HOME or default to ~/.local/share/libvirt/images
197
+ let data_home = std:: env:: var ( "XDG_DATA_HOME" )
198
+ . ok ( )
199
+ . map ( Utf8PathBuf :: from)
200
+ . unwrap_or_else ( || {
201
+ let home = std:: env:: var ( "HOME" ) . unwrap_or_else ( |_| "." . to_string ( ) ) ;
202
+ Utf8PathBuf :: from ( home) . join ( ".local/share" )
203
+ } ) ;
204
+ data_home. join ( "libvirt/images" )
205
+ } else {
206
+ // System session: use /var/lib/libvirt/images
207
+ Utf8PathBuf :: from ( "/var/lib/libvirt/images" )
208
+ }
209
+ }
210
+
211
+ /// Ensure the default libvirt storage pool exists, creating it if necessary
212
+ fn ensure_default_pool ( connect_uri : & str ) -> Result < ( ) > {
213
+ // Check if default pool already exists
214
+ let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
215
+ cmd. args ( & [ "-c" , connect_uri, "pool-info" , "default" ] ) ;
216
+ let output = cmd
217
+ . output ( )
218
+ . with_context ( || "Failed to check for default pool" ) ?;
219
+
220
+ if output. status . success ( ) {
221
+ // Pool exists, make sure it's active
222
+ let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
223
+ cmd. args ( & [ "-c" , connect_uri, "pool-start" , "default" ] ) ;
224
+ let _ = cmd. output ( ) ; // Ignore errors if already started
225
+ return Ok ( ( ) ) ;
226
+ }
227
+
228
+ // Pool doesn't exist, need to create it
229
+ let pool_path = get_default_pool_path ( connect_uri) ;
230
+ info ! ( "Creating default storage pool at {:?}" , pool_path) ;
231
+
232
+ // Create the directory if it doesn't exist
233
+ fs:: create_dir_all ( & pool_path)
234
+ . with_context ( || format ! ( "Failed to create pool directory: {:?}" , pool_path) ) ?;
235
+
236
+ // Create pool XML
237
+ let pool_xml = format ! (
238
+ r#"<pool type='dir'>
239
+ <name>default</name>
240
+ <target>
241
+ <path>{}</path>
242
+ </target>
243
+ </pool>"# ,
244
+ pool_path
245
+ ) ;
246
+
247
+ // Write XML to temporary file
248
+ let xml_path = "/tmp/default-pool.xml" ;
249
+ std:: fs:: write ( xml_path, & pool_xml) . with_context ( || "Failed to write pool XML" ) ?;
250
+
251
+ // Define the pool
252
+ let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
253
+ cmd. args ( & [ "-c" , connect_uri, "pool-define" , xml_path] ) ;
254
+ let output = cmd. output ( ) . with_context ( || "Failed to define pool" ) ?;
255
+
256
+ if !output. status . success ( ) {
257
+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
258
+ let _ = std:: fs:: remove_file ( xml_path) ;
259
+ return Err ( color_eyre:: eyre:: eyre!(
260
+ "Failed to define default pool: {}" ,
261
+ stderr
262
+ ) ) ;
263
+ }
264
+
265
+ // Build the pool (creates directory structure)
266
+ let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
267
+ cmd. args ( & [ "-c" , connect_uri, "pool-build" , "default" ] ) ;
268
+ let _ = cmd. output ( ) ; // Directory might already exist
269
+
270
+ // Start the pool
271
+ let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
272
+ cmd. args ( & [ "-c" , connect_uri, "pool-start" , "default" ] ) ;
273
+ let output = cmd. output ( ) . with_context ( || "Failed to start pool" ) ?;
274
+
275
+ if !output. status . success ( ) {
276
+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
277
+ let _ = std:: fs:: remove_file ( xml_path) ;
278
+ return Err ( color_eyre:: eyre:: eyre!(
279
+ "Failed to start default pool: {}" ,
280
+ stderr
281
+ ) ) ;
282
+ }
283
+
284
+ // Autostart the pool
285
+ let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
286
+ cmd. args ( & [ "-c" , connect_uri, "pool-autostart" , "default" ] ) ;
287
+ let _ = cmd. output ( ) ; // Not critical if this fails
288
+
289
+ // Clean up temporary XML file
290
+ let _ = std:: fs:: remove_file ( xml_path) ;
291
+
292
+ info ! ( "Default storage pool created successfully" ) ;
293
+ Ok ( ( ) )
294
+ }
295
+
193
296
/// Get the path of the default libvirt storage pool
194
297
pub fn get_libvirt_storage_pool_path ( connect_uri : Option < & String > ) -> Result < Utf8PathBuf > {
195
298
// If a specific connection URI is provided, use it
196
299
if let Some ( uri) = connect_uri {
300
+ // Ensure pool exists before querying
301
+ ensure_default_pool ( uri) ?;
302
+
197
303
let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
198
304
cmd. args ( & [ "-c" , uri, "pool-dumpxml" , "default" ] ) ;
199
305
let output = cmd
@@ -216,24 +322,33 @@ pub fn get_libvirt_storage_pool_path(connect_uri: Option<&String>) -> Result<Utf
216
322
}
217
323
218
324
// Try user session first (qemu:///session)
325
+ let session_uri = "qemu:///session" ;
326
+ ensure_default_pool ( session_uri) ?;
327
+
219
328
let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
220
- cmd. args ( & [ "-c" , "qemu:///session" , "pool-dumpxml" , "default" ] ) ;
329
+ cmd. args ( & [ "-c" , session_uri , "pool-dumpxml" , "default" ] ) ;
221
330
let output = cmd. output ( ) ;
222
331
223
- let output = match output {
224
- Ok ( o) if o. status . success ( ) => o ,
332
+ let ( output, uri_used ) = match output {
333
+ Ok ( o) if o. status . success ( ) => ( o , session_uri ) ,
225
334
_ => {
226
335
// Try system session (qemu:///system)
336
+ let system_uri = "qemu:///system" ;
337
+ ensure_default_pool ( system_uri) ?;
338
+
227
339
let mut cmd = crate :: hostexec:: command ( "virsh" , None ) ?;
228
- cmd. args ( & [ "-c" , "qemu:///system" , "pool-dumpxml" , "default" ] ) ;
229
- cmd. output ( )
230
- . with_context ( || "Failed to query libvirt storage pool" ) ?
340
+ cmd. args ( & [ "-c" , system_uri, "pool-dumpxml" , "default" ] ) ;
341
+ let out = cmd
342
+ . output ( )
343
+ . with_context ( || "Failed to query libvirt storage pool" ) ?;
344
+ ( out, system_uri)
231
345
}
232
346
} ;
233
347
234
348
if !output. status . success ( ) {
235
349
return Err ( color_eyre:: eyre:: eyre!(
236
- "Failed to get default storage pool info"
350
+ "Failed to get default storage pool info for {}" ,
351
+ uri_used
237
352
) ) ;
238
353
}
239
354
0 commit comments