From 5acae53e5be529b76e72913634e6f4e06c6a28c7 Mon Sep 17 00:00:00 2001 From: mulhern Date: Wed, 24 Jul 2024 17:10:11 -0400 Subject: [PATCH] Add D-Bus method to get filesystem metadata Signed-off-by: mulhern --- src/dbus_api/pool/mod.rs | 1 + src/dbus_api/pool/pool_3_7/api.rs | 15 ++++++- src/dbus_api/pool/pool_3_7/methods.rs | 46 +++++++++++++++++++- src/dbus_api/pool/pool_3_7/mod.rs | 5 ++- src/engine/engine.rs | 6 +++ src/engine/sim_engine/filesystem.rs | 28 +++++++++++- src/engine/sim_engine/pool.rs | 28 ++++++++++++ src/engine/strat_engine/pool/dispatch.rs | 14 ++++++ src/engine/strat_engine/pool/v1.rs | 19 ++++++++ src/engine/strat_engine/pool/v2.rs | 19 ++++++++ src/engine/strat_engine/thinpool/thinpool.rs | 16 +++++++ 11 files changed, 193 insertions(+), 4 deletions(-) diff --git a/src/dbus_api/pool/mod.rs b/src/dbus_api/pool/mod.rs index 9bce858b2a..1667b58f63 100644 --- a/src/dbus_api/pool/mod.rs +++ b/src/dbus_api/pool/mod.rs @@ -260,6 +260,7 @@ pub fn create_dbus_pool<'a>( .add_m(pool_3_0::rename_method(&f)) .add_m(pool_3_3::grow_physical_device_method(&f)) .add_m(pool_3_7::get_metadata_method(&f)) + .add_m(pool_3_7::get_fs_metadata_method(&f)) .add_p(pool_3_0::name_property(&f)) .add_p(pool_3_0::uuid_property(&f)) .add_p(pool_3_0::encrypted_property(&f)) diff --git a/src/dbus_api/pool/pool_3_7/api.rs b/src/dbus_api/pool/pool_3_7/api.rs index 59603f4e34..d6e4f4cfb8 100644 --- a/src/dbus_api/pool/pool_3_7/api.rs +++ b/src/dbus_api/pool/pool_3_7/api.rs @@ -7,7 +7,7 @@ use dbus_tree::{Access, EmitsChangedSignal, Factory, MTSync, Method, Property}; use crate::dbus_api::{ consts, pool::pool_3_7::{ - methods::{destroy_filesystems, metadata}, + methods::{destroy_filesystems, fs_metadata, metadata}, props::get_pool_metadata_version, }, types::TData, @@ -47,3 +47,16 @@ pub fn metadata_version_property( .emits_changed(EmitsChangedSignal::Const) .on_get(get_pool_metadata_version) } + +pub fn get_fs_metadata_method(f: &Factory, TData>) -> Method, TData> { + f.method("FilesystemMetadata", (), fs_metadata) + .in_arg(("fs_name", "(bs)")) + .in_arg(("current", "b")) + // A string representing the pool's filesystem metadata in serialized + // JSON format. + // + // Rust representation: String + .out_arg(("results", "s")) + .out_arg(("return_code", "q")) + .out_arg(("return_string", "s")) +} diff --git a/src/dbus_api/pool/pool_3_7/methods.rs b/src/dbus_api/pool/pool_3_7/methods.rs index 1d3bbfbb48..6508e974be 100644 --- a/src/dbus_api/pool/pool_3_7/methods.rs +++ b/src/dbus_api/pool/pool_3_7/methods.rs @@ -11,7 +11,7 @@ use crate::{ dbus_api::{ consts::filesystem_interface_list, types::{DbusErrorEnum, TData, OK_STRING}, - util::{engine_to_dbus_err_tuple, get_next_arg}, + util::{engine_to_dbus_err_tuple, get_next_arg, tuple_to_option}, }, engine::{EngineAction, FilesystemUuid, StratisUuid}, }; @@ -148,3 +148,47 @@ pub fn metadata(m: &MethodInfo<'_, MTSync, TData>) -> MethodResult { }; Ok(vec![msg]) } + +pub fn fs_metadata(m: &MethodInfo<'_, MTSync, TData>) -> MethodResult { + let default_return = String::new(); + + let message: &Message = m.msg; + + let return_message = message.method_return(); + + let dbus_context = m.tree.get_data(); + let object_path = m.path.get_name(); + + let pool_path = m + .tree + .get(object_path) + .expect("implicit argument must be in tree"); + let pool_uuid = typed_uuid!( + get_data!(pool_path; default_return; return_message).uuid; + Pool; + default_return; + return_message + ); + + let mut iter = message.iter_init(); + let filesystem_name: Option<&str> = tuple_to_option(get_next_arg(&mut iter, 0)?); + let current: bool = get_next_arg(&mut iter, 1)?; + + let guard = get_pool!(dbus_context.engine; pool_uuid; default_return; return_message); + let (_, _, pool) = guard.as_tuple(); + + let result = if current { + pool.current_fs_metadata(filesystem_name) + } else { + pool.last_fs_metadata(filesystem_name) + }; + + let msg = match result { + Ok(v) => return_message.append3(v, DbusErrorEnum::OK as u16, OK_STRING.to_string()), + Err(err) => { + let (rc, rs) = engine_to_dbus_err_tuple(&err); + return_message.append3(default_return, rc, rs) + } + }; + Ok(vec![msg]) +} diff --git a/src/dbus_api/pool/pool_3_7/mod.rs b/src/dbus_api/pool/pool_3_7/mod.rs index 834df4053d..037c6a6758 100644 --- a/src/dbus_api/pool/pool_3_7/mod.rs +++ b/src/dbus_api/pool/pool_3_7/mod.rs @@ -6,4 +6,7 @@ mod api; mod methods; mod props; -pub use api::{destroy_filesystems_method, get_metadata_method, metadata_version_property}; +pub use api::{ + destroy_filesystems_method, get_fs_metadata_method, get_metadata_method, + metadata_version_property, +}; diff --git a/src/engine/engine.rs b/src/engine/engine.rs index 66d01ef8fb..5a72a6d9bb 100644 --- a/src/engine/engine.rs +++ b/src/engine/engine.rs @@ -350,6 +350,12 @@ pub trait Pool: Debug + Send + Sync { /// Get the metadata version for a given pool. fn metadata_version(&self) -> StratSigblockVersion; + + /// Get the filesystem metadata that would be written if written now. + fn current_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult; + + /// Get the last written filesystem metadata. + fn last_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult; } pub type HandleEvents

= ( diff --git a/src/engine/sim_engine/filesystem.rs b/src/engine/sim_engine/filesystem.rs index 5198f234bf..b6661bab3a 100644 --- a/src/engine/sim_engine/filesystem.rs +++ b/src/engine/sim_engine/filesystem.rs @@ -10,10 +10,25 @@ use serde_json::{Map, Value}; use devicemapper::{Bytes, Sectors}; use crate::{ - engine::{types::FilesystemUuid, Filesystem}, + engine::{ + types::{FilesystemUuid, Name}, + Filesystem, + }, stratis::{StratisError, StratisResult}, }; +#[derive(Debug, Eq, PartialEq, Serialize)] +pub struct FilesystemSave { + name: String, + uuid: FilesystemUuid, + size: Sectors, + created: u64, + #[serde(skip_serializing_if = "Option::is_none")] + fs_size_limit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + origin: Option, +} + #[derive(Debug)] pub struct SimFilesystem { rand: u32, @@ -73,6 +88,17 @@ impl SimFilesystem { self.origin = None; changed } + + pub fn record(&self, name: &Name, uuid: FilesystemUuid) -> FilesystemSave { + FilesystemSave { + name: name.to_owned(), + uuid, + size: self.size, + created: self.created.timestamp() as u64, + fs_size_limit: self.size_limit, + origin: self.origin, + } + } } impl Filesystem for SimFilesystem { diff --git a/src/engine/sim_engine/pool.rs b/src/engine/sim_engine/pool.rs index 45f45eb0f6..68a72db74f 100644 --- a/src/engine/sim_engine/pool.rs +++ b/src/engine/sim_engine/pool.rs @@ -758,6 +758,34 @@ impl Pool for SimPool { fn metadata_version(&self) -> StratSigblockVersion { StratSigblockVersion::V2 } + + fn current_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + self.filesystems + .iter() + .filter_map(|(name, uuid, fs)| { + if fs_name.map(|n| *n == **name).unwrap_or(true) { + Some(serde_json::to_string(&fs.record(name, *uuid)).map_err(|e| e.into())) + } else { + None + } + }) + .collect::>>() + .map(|v| v.join("\n")) + } + + fn last_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + self.filesystems + .iter() + .filter_map(|(name, uuid, fs)| { + if fs_name.map(|n| *n == **name).unwrap_or(true) { + Some(serde_json::to_string(&fs.record(name, *uuid)).map_err(|e| e.into())) + } else { + None + } + }) + .collect::>>() + .map(|v| v.join("\n")) + } } #[cfg(test)] diff --git a/src/engine/strat_engine/pool/dispatch.rs b/src/engine/strat_engine/pool/dispatch.rs index 3c17b2e361..c1baf3d45f 100644 --- a/src/engine/strat_engine/pool/dispatch.rs +++ b/src/engine/strat_engine/pool/dispatch.rs @@ -348,4 +348,18 @@ impl Pool for AnyPool { AnyPool::V2(p) => p.metadata_version(), } } + + fn current_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + match self { + AnyPool::V1(p) => p.current_fs_metadata(fs_name), + AnyPool::V2(p) => p.current_fs_metadata(fs_name), + } + } + + fn last_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + match self { + AnyPool::V1(p) => p.last_fs_metadata(fs_name), + AnyPool::V2(p) => p.last_fs_metadata(fs_name), + } + } } diff --git a/src/engine/strat_engine/pool/v1.rs b/src/engine/strat_engine/pool/v1.rs index 932dbe3849..64bd1f2a78 100644 --- a/src/engine/strat_engine/pool/v1.rs +++ b/src/engine/strat_engine/pool/v1.rs @@ -1293,6 +1293,25 @@ impl Pool for StratPool { fn metadata_version(&self) -> StratSigblockVersion { StratSigblockVersion::V1 } + + fn current_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + self.thin_pool + .filesystems() + .iter() + .filter_map(|(name, uuid, fs)| { + if fs_name.map(|n| *n == **name).unwrap_or(true) { + Some(serde_json::to_string(&fs.record(name, *uuid)).map_err(|e| e.into())) + } else { + None + } + }) + .collect::>>() + .map(|v| v.join("\n")) + } + + fn last_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + self.thin_pool.fs_metadata(fs_name) + } } pub struct StratPoolState { diff --git a/src/engine/strat_engine/pool/v2.rs b/src/engine/strat_engine/pool/v2.rs index e82c6cfbca..d0a32bc3e5 100644 --- a/src/engine/strat_engine/pool/v2.rs +++ b/src/engine/strat_engine/pool/v2.rs @@ -1200,6 +1200,25 @@ impl Pool for StratPool { fn metadata_version(&self) -> StratSigblockVersion { StratSigblockVersion::V2 } + + fn current_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + self.thin_pool + .filesystems() + .iter() + .filter_map(|(name, uuid, fs)| { + if fs_name.map(|n| *n == **name).unwrap_or(true) { + Some(serde_json::to_string(&fs.record(name, *uuid)).map_err(|e| e.into())) + } else { + None + } + }) + .collect::>>() + .map(|v| v.join("\n")) + } + + fn last_fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + self.thin_pool.fs_metadata(fs_name) + } } pub struct StratPoolState { diff --git a/src/engine/strat_engine/thinpool/thinpool.rs b/src/engine/strat_engine/thinpool/thinpool.rs index 1dcfb5e389..0aa978ac0f 100644 --- a/src/engine/strat_engine/thinpool/thinpool.rs +++ b/src/engine/strat_engine/thinpool/thinpool.rs @@ -728,6 +728,22 @@ impl ThinPool { pub fn clear_out_of_meta_flag(&mut self) { self.out_of_meta_space = false; } + + /// Read filesystem metadata from mdvs + pub fn fs_metadata(&self, fs_name: Option<&str>) -> StratisResult { + self.mdv + .filesystems()? + .iter() + .filter_map(|fssave| { + if fs_name.map(|n| *n == fssave.name).unwrap_or(true) { + Some(serde_json::to_string(fssave).map_err(|e| e.into())) + } else { + None + } + }) + .collect::>>() + .map(|v| v.join("\n")) + } } impl ThinPool {