Skip to content

Commit b68c6c7

Browse files
committed
libvirt: Bootstrap default pool
It seems like libvirt doesn't come with any pool by default, and it's actually virt-manager that makes this `default`. Signed-off-by: Colin Walters <[email protected]>
1 parent 7860d8c commit b68c6c7

File tree

1 file changed

+122
-7
lines changed

1 file changed

+122
-7
lines changed

crates/kit/src/libvirt/run.rs

Lines changed: 122 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,116 @@ pub fn run(global_opts: &crate::libvirt::LibvirtOptions, opts: LibvirtRunOpts) -
190190
}
191191
}
192192

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+
193296
/// Get the path of the default libvirt storage pool
194297
pub fn get_libvirt_storage_pool_path(connect_uri: Option<&String>) -> Result<Utf8PathBuf> {
195298
// If a specific connection URI is provided, use it
196299
if let Some(uri) = connect_uri {
300+
// Ensure pool exists before querying
301+
ensure_default_pool(uri)?;
302+
197303
let mut cmd = crate::hostexec::command("virsh", None)?;
198304
cmd.args(&["-c", uri, "pool-dumpxml", "default"]);
199305
let output = cmd
@@ -216,24 +322,33 @@ pub fn get_libvirt_storage_pool_path(connect_uri: Option<&String>) -> Result<Utf
216322
}
217323

218324
// Try user session first (qemu:///session)
325+
let session_uri = "qemu:///session";
326+
ensure_default_pool(session_uri)?;
327+
219328
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"]);
221330
let output = cmd.output();
222331

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),
225334
_ => {
226335
// Try system session (qemu:///system)
336+
let system_uri = "qemu:///system";
337+
ensure_default_pool(system_uri)?;
338+
227339
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)
231345
}
232346
};
233347

234348
if !output.status.success() {
235349
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
237352
));
238353
}
239354

0 commit comments

Comments
 (0)