summaryrefslogtreecommitdiff
path: root/src/libvirt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libvirt.rs')
-rw-r--r--src/libvirt.rs75
1 files changed, 70 insertions, 5 deletions
diff --git a/src/libvirt.rs b/src/libvirt.rs
index 0dbc4e3..f0ad2d0 100644
--- a/src/libvirt.rs
+++ b/src/libvirt.rs
@@ -1,11 +1,14 @@
//! An abstraction on top of the libvirt bindings.
+use crate::util::wait_for_ssh;
use log::debug;
use std::path::Path;
use std::thread;
use std::time::Duration;
use virt::connect::Connect;
-use virt::domain::Domain;
+use virt::domain::{
+ Domain, VIR_DOMAIN_AFFECT_CONFIG, VIR_DOMAIN_AFFECT_CURRENT, VIR_DOMAIN_AFFECT_LIVE,
+};
/// Errors from this module.
#[derive(Debug, thiserror::Error)]
@@ -61,9 +64,33 @@ impl Libvirt {
}
}
+ pub fn wait_for_inactive(&self, name: &str) -> Result<(), VirtError> {
+ loop {
+ if !self.is_active(name)? {
+ break;
+ }
+ }
+ Ok(())
+ }
+
+ pub fn detach_cloud_init_iso(&self, name: &str) -> Result<(), VirtError> {
+ if let Some(domain) = self.get_domain(name)? {
+ debug!("detaching cloud-init ISO from {}", name);
+ let xml = domain.get_xml_desc(0)?;
+ let disk = find_iso_xml(&xml);
+ let flags =
+ VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_CURRENT | VIR_DOMAIN_AFFECT_LIVE;
+ if disk.len() > 0 {
+ domain.detach_device_flags(&disk, flags)?;
+ }
+ }
+ Ok(())
+ }
+
pub fn start(&self, name: &str) -> Result<(), VirtError> {
if let Some(domain) = self.get_domain(name)? {
domain.create()?;
+ wait_for_ssh(name);
}
Ok(())
}
@@ -71,6 +98,7 @@ impl Libvirt {
pub fn shutdown(&self, name: &str) -> Result<(), VirtError> {
if let Some(domain) = self.get_domain(name)? {
domain.shutdown()?;
+ wait_until_inactive(&domain, name);
}
Ok(())
}
@@ -78,9 +106,9 @@ impl Libvirt {
pub fn delete(&self, name: &str, image: &Path) -> Result<(), VirtError> {
if let Some(domain) = self.get_domain(name)? {
debug!("shutting down {}", name);
- domain.shutdown()?;
+ domain.shutdown().ok();
- wait_until_inactive(&domain, name)?;
+ wait_until_inactive(&domain, name);
debug!("undefine {}", name);
domain.undefine()?;
@@ -93,7 +121,7 @@ impl Libvirt {
}
}
-fn wait_until_inactive(domain: &Domain, name: &str) -> Result<(), VirtError> {
+fn wait_until_inactive(domain: &Domain, name: &str) {
debug!("waiting for domain {} to become inactive", name);
let briefly = Duration::from_millis(1000);
loop {
@@ -107,5 +135,42 @@ fn wait_until_inactive(domain: &Domain, name: &str) -> Result<(), VirtError> {
}
debug!("domain {} is still running", name);
}
- Ok(())
+}
+
+// This is a HACK. The XML description of a domain contains
+// descriptions of attached virtual disks. We find one that contains
+// ".iso", and return that.
+//
+// <disk type='file' device='disk'>
+// <driver name='qemu' type='raw'/>
+// <source file='/tmp/.tmp2rAiVW/cloudinit.iso'/>
+// <backingStore/>
+// <target dev='vdb' bus='virtio'/>
+// <readonly/>
+// <alias name='virtio-disk1'/>
+// <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
+// </disk>
+
+fn find_iso_xml(xml: &str) -> String {
+ let mut xml = xml;
+ loop {
+ let start = xml.find("<disk ");
+ if start.is_none() {
+ break;
+ }
+ let start = start.unwrap();
+ xml = &xml[start..];
+
+ let end = xml.find("</disk>");
+ if end.is_none() {
+ break;
+ }
+ let end = end.unwrap();
+ let disk = &xml[..end + 7];
+ if let Some(_) = disk.find(".iso") {
+ return disk.to_string();
+ }
+ xml = &xml[end..];
+ }
+ "".to_string()
}