diff options
Diffstat (limited to 'src/libvirt.rs')
-rw-r--r-- | src/libvirt.rs | 75 |
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() } |