Skip to content

Commit

Permalink
Add D-Bus interface for setting filesystem size limit
Browse files Browse the repository at this point in the history
  • Loading branch information
jbaublitz committed Sep 29, 2023
1 parent c8a1324 commit 0607394
Show file tree
Hide file tree
Showing 17 changed files with 368 additions and 50 deletions.
1 change: 1 addition & 0 deletions src/dbus_api/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub const FILESYSTEM_DEVNODE_PROP: &str = "Devnode";
pub const FILESYSTEM_POOL_PROP: &str = "Pool";
pub const FILESYSTEM_CREATED_PROP: &str = "Created";
pub const FILESYSTEM_SIZE_PROP: &str = "Size";
pub const FILESYSTEM_SIZE_LIMIT_PROP: &str = "SizeLimit";

pub const BLOCKDEV_INTERFACE_NAME_3_0: &str = "org.storage.stratis3.blockdev.r0";
pub const BLOCKDEV_INTERFACE_NAME_3_1: &str = "org.storage.stratis3.blockdev.r1";
Expand Down
37 changes: 6 additions & 31 deletions src/dbus_api/filesystem/filesystem_3_0/props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,14 @@
use dbus::arg::IterAppend;
use dbus_tree::{MTSync, MethodErr, PropInfo};

use crate::{
dbus_api::{
filesystem::shared::{self, filesystem_operation},
types::TData,
},
engine::{Filesystem, Name},
};

/// Get a filesystem property and place it on the D-Bus. The property is
/// found by means of the getter method which takes a reference to a
/// Filesystem and obtains the property from the filesystem.
fn get_filesystem_property<F, R>(
i: &mut IterAppend<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
getter: F,
) -> Result<(), MethodErr>
where
F: Fn((Name, Name, &dyn Filesystem)) -> Result<R, String>,
R: dbus::arg::Append,
{
i.append(
filesystem_operation(p.tree, p.path.get_name(), getter)
.map_err(|ref e| MethodErr::failed(e))?,
);
Ok(())
}
use crate::dbus_api::{filesystem::shared, types::TData};

/// Get the devnode for an object path.
pub fn get_filesystem_devnode(
i: &mut IterAppend<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
) -> Result<(), MethodErr> {
get_filesystem_property(i, p, |(pool_name, fs_name, fs)| {
shared::get_filesystem_property(i, p, |(pool_name, fs_name, fs)| {
Ok(shared::fs_devnode_prop(fs, &pool_name, &fs_name))
})
}
Expand All @@ -46,29 +21,29 @@ pub fn get_filesystem_name(
i: &mut IterAppend<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
) -> Result<(), MethodErr> {
get_filesystem_property(i, p, |(_, fs_name, _)| Ok(shared::fs_name_prop(&fs_name)))
shared::get_filesystem_property(i, p, |(_, fs_name, _)| Ok(shared::fs_name_prop(&fs_name)))
}

/// Get the creation date and time in rfc3339 format.
pub fn get_filesystem_created(
i: &mut IterAppend<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
) -> Result<(), MethodErr> {
get_filesystem_property(i, p, |(_, _, fs)| Ok(shared::fs_created_prop(fs)))
shared::get_filesystem_property(i, p, |(_, _, fs)| Ok(shared::fs_created_prop(fs)))
}

/// Get the size of the filesystem in bytes.
pub fn get_filesystem_size(
i: &mut IterAppend<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
) -> Result<(), MethodErr> {
get_filesystem_property(i, p, |(_, _, fs)| Ok(shared::fs_size_prop(fs)))
shared::get_filesystem_property(i, p, |(_, _, fs)| Ok(shared::fs_size_prop(fs)))
}

/// Get the size of the used portion of the filesystem in bytes.
pub fn get_filesystem_used(
i: &mut IterAppend<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
) -> Result<(), MethodErr> {
get_filesystem_property(i, p, |(_, _, fs)| Ok(shared::fs_used_prop(fs)))
shared::get_filesystem_property(i, p, |(_, _, fs)| Ok(shared::fs_used_prop(fs)))
}
20 changes: 20 additions & 0 deletions src/dbus_api/filesystem/filesystem_3_6/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use dbus_tree::{Access, EmitsChangedSignal, Factory, MTSync, Property};

use crate::dbus_api::{
consts,
filesystem::filesystem_3_6::props::{get_fs_size_limit, set_fs_size_limit},
types::TData,
};

pub fn size_limit_property(f: &Factory<MTSync<TData>, TData>) -> Property<MTSync<TData>, TData> {
f.property::<(bool, String), _>(consts::FILESYSTEM_SIZE_LIMIT_PROP, ())
.access(Access::ReadWrite)
.emits_changed(EmitsChangedSignal::True)
.auto_emit_on_set(false)
.on_get(get_fs_size_limit)
.on_set(set_fs_size_limit)
}
8 changes: 8 additions & 0 deletions src/dbus_api/filesystem/filesystem_3_6/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

mod api;
mod props;

pub use api::size_limit_property;
60 changes: 60 additions & 0 deletions src/dbus_api/filesystem/filesystem_3_6/props.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use dbus::arg::{Iter, IterAppend};
use dbus_tree::{MTSync, MethodErr, PropInfo};

use devicemapper::Bytes;

use crate::{
dbus_api::{
consts,
filesystem::shared::{self, get_filesystem_property},
types::TData,
util::tuple_to_option,
},
engine::PropChangeAction,
};

pub fn get_fs_size_limit(
i: &mut IterAppend<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
) -> Result<(), MethodErr> {
get_filesystem_property(i, p, |(_, _, f)| Ok(shared::fs_size_limit_prop(f)))
}

pub fn set_fs_size_limit(
i: &mut Iter<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
) -> Result<(), MethodErr> {
let size_limit_opt: (bool, &str) = i.get().ok_or_else(|| {
MethodErr::failed("New filesystem limit required as argument to increase it")
})?;
let size_limit_str = tuple_to_option(size_limit_opt);
let size_limit = match size_limit_str {
Some(lim) => Some(
Bytes(lim.parse::<u128>().map_err(|e| {
MethodErr::failed(&format!("Failed to parse {lim} as unsigned integer: {e}"))
})?)
.sectors(),
),
None => None,
};

let res = shared::set_fs_property_to_display(
p,
consts::FILESYSTEM_SIZE_LIMIT_PROP,
|(_, uuid, fs)| shared::set_fs_size_limit_prop(uuid, fs, size_limit),
);
match res {
Ok(PropChangeAction::NewValue(v)) => {
p.tree
.get_data()
.push_fs_size_limit_change(p.path.get_name(), v);
Ok(())
}
Ok(PropChangeAction::Identity) => Ok(()),
Err(e) => Err(e),
}
}
7 changes: 5 additions & 2 deletions src/dbus_api/filesystem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::{
};

mod filesystem_3_0;
mod filesystem_3_6;
pub mod prop_conv;
mod shared;

Expand Down Expand Up @@ -110,7 +111,8 @@ pub fn create_dbus_filesystem<'a>(
.add_p(filesystem_3_0::uuid_property(&f))
.add_p(filesystem_3_0::created_property(&f))
.add_p(filesystem_3_0::size_property(&f))
.add_p(filesystem_3_0::used_property(&f)),
.add_p(filesystem_3_0::used_property(&f))
.add_p(filesystem_3_6::size_limit_property(&f)),
);

let path = object_path.get_name().to_owned();
Expand Down Expand Up @@ -189,7 +191,8 @@ pub fn get_fs_properties(
consts::FILESYSTEM_POOL_PROP => parent,
consts::FILESYSTEM_CREATED_PROP => shared::fs_created_prop(fs),
consts::FILESYSTEM_SIZE_PROP => shared::fs_size_prop(fs),
consts::FILESYSTEM_USED_PROP => shared::fs_used_prop(fs)
consts::FILESYSTEM_USED_PROP => shared::fs_used_prop(fs),
consts::FILESYSTEM_USED_PROP => shared::fs_size_limit_prop(fs)
}
}
}
8 changes: 7 additions & 1 deletion src/dbus_api/filesystem/prop_conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use devicemapper::Bytes;
use devicemapper::{Bytes, Sectors};

use crate::dbus_api::util::option_to_tuple;

Expand All @@ -17,3 +17,9 @@ pub fn fs_size_to_prop(size: Bytes) -> String {
pub fn fs_used_to_prop(used: Option<Bytes>) -> (bool, String) {
option_to_tuple(used.map(|u| (*u).to_string()), String::new())
}

/// Generate D-Bus representation of used property.
#[inline]
pub fn fs_size_limit_to_prop(limit: Option<Sectors>) -> (bool, String) {
option_to_tuple(limit.map(|u| (*u.bytes()).to_string()), String::new())
}
120 changes: 116 additions & 4 deletions src/dbus_api/filesystem/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use chrono::SecondsFormat;
use dbus::Path;
use dbus_tree::{MTSync, Tree};
use dbus::{arg::IterAppend, Path};
use dbus_tree::{MTSync, MethodErr, PropInfo, Tree};
use futures::executor::block_on;

use devicemapper::Sectors;

use crate::{
dbus_api::{filesystem::prop_conv, types::TData},
engine::{Filesystem, Name, PoolIdentifier},
engine::{Filesystem, FilesystemUuid, Name, Pool, PoolIdentifier, PropChangeAction, ToDisplay},
};

/// Get execute a given closure providing a filesystem object and return
/// the calculated value
pub fn filesystem_operation<F, R>(
pub fn filesystem_get_operation<F, R>(
tree: &Tree<MTSync<TData>, TData>,
object_path: &Path<'static>,
closure: F,
Expand Down Expand Up @@ -61,6 +63,116 @@ where
closure((pool_name, fs_name, fs))
}

/// Get a filesystem property and place it on the D-Bus. The property is
/// found by means of the getter method which takes a reference to a
/// Filesystem and obtains the property from the filesystem.
pub fn get_filesystem_property<F, R>(
i: &mut IterAppend<'_>,
p: &PropInfo<'_, MTSync<TData>, TData>,
getter: F,
) -> Result<(), MethodErr>
where
F: Fn((Name, Name, &dyn Filesystem)) -> Result<R, String>,
R: dbus::arg::Append,
{
i.append(
filesystem_get_operation(p.tree, p.path.get_name(), getter)
.map_err(|ref e| MethodErr::failed(e))?,
);
Ok(())
}

/// Set a filesystem property. The property is set by means of
/// the getter method which takes a mutable reference to a
/// Pool for MDV update purposes.
pub fn fs_set_operation<F, R>(
tree: &Tree<MTSync<TData>, TData>,
object_path: &dbus::Path<'static>,
closure: F,
) -> Result<R, String>
where
F: Fn((Name, FilesystemUuid, &mut dyn Pool)) -> Result<R, String>,
{
let dbus_context = tree.get_data();

let fs_path = tree
.get(object_path)
.expect("implicit argument must be in tree");
let fs_uuid = typed_uuid_string_err!(
fs_path
.get_data()
.as_ref()
.ok_or_else(|| format!("no data for object path {object_path}"))?
.uuid;
Fs
);
let pool_path = tree
.get(
&fs_path
.get_data()
.as_ref()
.ok_or_else(|| format!("no data for object path {object_path}"))?
.parent,
)
.ok_or_else(|| "Parent not found in tree".to_string())?;
let pool_uuid = typed_uuid_string_err!(
pool_path
.get_data()
.as_ref()
.ok_or_else(|| format!("no data for object path {object_path}"))?
.uuid;
Pool
);

let mut guard = block_on(
dbus_context
.engine
.get_mut_pool(PoolIdentifier::Uuid(pool_uuid)),
)
.ok_or_else(|| format!("no pool corresponding to uuid {pool_uuid}"))?;
let (name, _) = guard
.get_filesystem(fs_uuid)
.ok_or_else(|| format!("no filesystem corresponding to uuid {fs_uuid}"))?;

closure((name, fs_uuid, &mut *guard))
}

/// Set a filesystem property. The property is found by means of the setter method which
/// takes a mutable reference to a Filesystem and sets the property on the filesystem.
pub fn set_fs_property_to_display<F, R>(
p: &PropInfo<'_, MTSync<TData>, TData>,
prop_name: &str,
setter: F,
) -> Result<R, MethodErr>
where
F: Fn((Name, FilesystemUuid, &mut dyn Pool)) -> Result<R, String>,
R: ToDisplay,
{
info!("Setting property {}", prop_name);
let res =
fs_set_operation(p.tree, p.path.get_name(), setter).map_err(|ref e| MethodErr::failed(e));
let display = res.as_ref().map(|r| r.to_display());
let _ = handle_action!(display);
res
}

/// Set the filesystem size limit for a given filesystem.
#[inline]
pub fn fs_size_limit_prop(fs: &dyn Filesystem) -> (bool, String) {
prop_conv::fs_size_limit_to_prop(fs.size_limit())
}

/// Set the filesystem size limit for a given filesystem.
#[inline]
pub fn set_fs_size_limit_prop(
uuid: FilesystemUuid,
pool: &mut dyn Pool,
limit: Option<Sectors>,
) -> Result<PropChangeAction<Option<Sectors>>, String> {
pool.set_fs_size_limit(uuid, limit)
.map_err(|e| e.to_string())
}

/// Generate D-Bus representation of name property.
#[inline]
pub fn fs_name_prop(name: &Name) -> String {
Expand Down
Loading

0 comments on commit 0607394

Please sign in to comment.