/
githubmirror
/
afterburn
Обзор
Документация
Войти
/
githubmirror
/
afterburn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/providers/cloudstack/configdrive.rs
139 строк
4 KB
Benjamin Gilbert
Inline variables into format strings
19 фев 2023, 01:50
19 фев 2023, 01:50
46b5580
Код
Авторство
О чём код?
//! configdrive metadata fetcher for cloudstack use std::collections::HashMap; use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; use openssh_keys::PublicKey; use slog_scope::error; use tempfile::TempDir; use crate::providers::MetadataProvider; const CONFIG_DRIVE_LABEL_1: &str = "config-2"; const CONFIG_DRIVE_LABEL_2: &str = "CONFIG-2"; /// CloudStack config-drive. #[derive(Debug)] pub struct ConfigDrive { /// Path to the top directory of the mounted config-drive. drive_path: PathBuf, /// Temporary directory for own mountpoint (if any). temp_dir: Option<TempDir>, } impl ConfigDrive { /// Try to build a new provider client. /// /// This internally tries to mount (and own) the config-drive. pub fn try_new() -> Result<Self> { // Short-circuit if the config-drive is already mounted. let path = Path::new("/media/ConfigDrive/cloudstack/metadata/"); if path.exists() { return Ok(ConfigDrive { temp_dir: None, drive_path: PathBuf::from("/media/ConfigDrive/"), }); } // Otherwise, try and mount with each of the labels. let target = tempfile::Builder::new() .prefix("afterburn-") .tempdir() .context("failed to create temporary directory")?; crate::util::mount_ro( &Path::new("/dev/disk/by-label/").join(CONFIG_DRIVE_LABEL_1), target.path(), "iso9660", 3, ) .or_else(|_| { crate::util::mount_ro( &Path::new("/dev/disk/by-label/").join(CONFIG_DRIVE_LABEL_2), target.path(), "iso9660", 3, ) })?; let cd = ConfigDrive { drive_path: target.path().to_owned(), temp_dir: Some(target), }; Ok(cd) } /// Return the path to the metadata directory. fn metadata_dir(&self) -> PathBuf { self.drive_path.clone().join("cloudstack").join("metadata") } fn fetch_value(&self, key: &str) -> Result<Option<String>> { let filename = self.metadata_dir().join(format!("{key}.txt")); if !filename.exists() { return Ok(None); } let mut file = File::open(&filename).with_context(|| format!("failed to open file '{filename:?}'"))?; let mut contents = String::new(); file.read_to_string(&mut contents) .with_context(|| format!("failed to read from file '{filename:?}'"))?; Ok(Some(contents)) } fn fetch_publickeys(&self) -> Result<Vec<PublicKey>> { let filename = self.metadata_dir().join("public_keys.txt"); let file = File::open(&filename).with_context(|| format!("failed to open file '{filename:?}'"))?; PublicKey::read_keys(file).context("failed to read public keys from config drive file") } } impl MetadataProvider for ConfigDrive { fn attributes(&self) -> Result<HashMap<String, String>> { let mut out = HashMap::with_capacity(6); let add_value = |map: &mut HashMap<_, _>, key: &str, name| -> Result<()> { let value = self.fetch_value(name)?; if let Some(value) = value { map.insert(key.to_string(), value); } Ok(()) }; add_value( &mut out, "CLOUDSTACK_AVAILABILITY_ZONE", "availability_zone", )?; add_value(&mut out, "CLOUDSTACK_CLOUD_IDENTIFIER", "cloud_identifier")?; add_value(&mut out, "CLOUDSTACK_INSTANCE_ID", "instance_id")?; add_value(&mut out, "CLOUDSTACK_LOCAL_HOSTNAME", "local_hostname")?; add_value(&mut out, "CLOUDSTACK_SERVICE_OFFERING", "service_offering")?; add_value(&mut out, "CLOUDSTACK_VM_ID", "vm_id")?; Ok(out) } fn ssh_keys(&self) -> Result<Vec<PublicKey>> { self.fetch_publickeys() } } impl Drop for ConfigDrive { fn drop(&mut self) { if self.temp_dir.is_some() { if let Err(e) = crate::util::unmount(&self.metadata_dir(), 3) { error!("failed to cleanup CloudStack config-drive: {}", e); }; } } }