Skip to content

Commit

Permalink
Add ability to specify size limit at filesystem creation time
Browse files Browse the repository at this point in the history
  • Loading branch information
jbaublitz committed Oct 19, 2023
1 parent 56e6b20 commit 6db9394
Show file tree
Hide file tree
Showing 15 changed files with 259 additions and 49 deletions.
3 changes: 2 additions & 1 deletion src/dbus_api/pool/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod pool_3_0;
mod pool_3_1;
mod pool_3_3;
mod pool_3_5;
mod pool_3_6;
pub mod prop_conv;
mod shared;

Expand Down Expand Up @@ -213,7 +214,7 @@ pub fn create_dbus_pool<'a>(
)
.add(
f.interface(consts::POOL_INTERFACE_NAME_3_6, ())
.add_m(pool_3_0::create_filesystems_method(&f))
.add_m(pool_3_6::create_filesystems_method(&f))
.add_m(pool_3_0::destroy_filesystems_method(&f))
.add_m(pool_3_0::snapshot_filesystem_method(&f))
.add_m(pool_3_0::add_blockdevs_method(&f))
Expand Down
4 changes: 2 additions & 2 deletions src/dbus_api/pool/pool_3_0/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ pub fn create_filesystems(m: &MethodInfo<'_, MTSync<TData>, TData>) -> MethodRes
})
})
.transpose()
.map(|size_opt| (name, size_opt.map(Bytes)))
.map(|size_opt| (name, size_opt.map(Bytes), None))
})
.collect::<Result<Vec<(&str, Option<Bytes>)>, String>>()
.collect::<Result<Vec<(&str, Option<Bytes>, Option<Bytes>)>, String>>()
{
Ok(val) => val,
Err(err) => {
Expand Down
21 changes: 21 additions & 0 deletions src/dbus_api/pool/pool_3_6/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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::{Factory, MTSync, Method};

use crate::dbus_api::{pool::pool_3_6::methods::create_filesystems, types::TData};

pub fn create_filesystems_method(
f: &Factory<MTSync<TData>, TData>,
) -> Method<MTSync<TData>, TData> {
f.method("CreateFilesystems", (), create_filesystems)
.in_arg(("specs", "a(s(bs)(bs))"))
// b: true if filesystems were created
// a(os): Array of tuples with object paths and names
//
// Rust representation: (bool, Vec<(dbus::Path, String)>)
.out_arg(("results", "(ba(os))"))
.out_arg(("return_code", "q"))
.out_arg(("return_string", "s"))
}
130 changes: 130 additions & 0 deletions src/dbus_api/pool/pool_3_6/methods.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// 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::Array, Message};
use dbus_tree::{MTSync, MethodInfo, MethodResult};

use devicemapper::Bytes;

use crate::{
dbus_api::{
filesystem::create_dbus_filesystem,
types::{DbusErrorEnum, TData, OK_STRING},
util::{engine_to_dbus_err_tuple, get_next_arg, tuple_to_option},
},
engine::{EngineAction, Name},
};

type FilesystemSpec<'a> = (&'a str, (bool, &'a str), (bool, &'a str));

pub fn create_filesystems(m: &MethodInfo<'_, MTSync<TData>, TData>) -> MethodResult {
let message: &Message = m.msg;
let mut iter = message.iter_init();

let filesystems: Array<'_, FilesystemSpec<'_>, _> = get_next_arg(&mut iter, 0)?;
let dbus_context = m.tree.get_data();

let object_path = m.path.get_name();
let return_message = message.method_return();
let default_return: (bool, Vec<(dbus::Path<'_>, &str)>) = (false, Vec::new());

if filesystems.count() > 1 {
let error_message = "only 1 filesystem per request allowed";
let (rc, rs) = (DbusErrorEnum::ERROR as u16, error_message);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}

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 guard = get_mut_pool!(dbus_context.engine; pool_uuid; default_return; return_message);
let (pool_name, _, pool) = guard.as_mut_tuple();

let filesystem_specs = match filesystems
.map(|(name, size_opt, size_limit_opt)| {
let size = tuple_to_option(size_opt)
.map(|val| {
val.parse::<u128>().map_err(|_| {
format!("Could not parse filesystem size string {val} to integer value")
})
})
.transpose()?;
let size_limit = tuple_to_option(size_limit_opt)
.map(|val| {
val.parse::<u128>().map_err(|_| {
format!(
"Could not parse filesystem size limit string {val} to integer value"
)
})
})
.transpose()?;
Ok((name, size.map(Bytes), size_limit.map(Bytes)))
})
.collect::<Result<Vec<(&str, Option<Bytes>, Option<Bytes>)>, String>>()
{
Ok(val) => val,
Err(err) => {
let (rc, rs) = (DbusErrorEnum::ERROR as u16, err);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
};

let result = handle_action!(
pool.create_filesystems(&pool_name, pool_uuid, &filesystem_specs),
dbus_context,
pool_path.get_name()
);

let infos = match result {
Ok(created_set) => created_set.changed(),
Err(err) => {
let (rc, rs) = engine_to_dbus_err_tuple(&err);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
};

let return_value = match infos {
Some(ref newly_created_filesystems) => {
let v = newly_created_filesystems
.iter()
.map(|&(name, uuid, _)| {
let filesystem = pool
.get_filesystem(uuid)
.expect("just inserted by create_filesystems")
.1;
// FIXME: To avoid this expect, modify create_filesystem
// so that it returns a mutable reference to the
// filesystem created.
(
create_dbus_filesystem(
dbus_context,
object_path.clone(),
&pool_name,
&Name::new(name.to_string()),
uuid,
filesystem,
),
name,
)
})
.collect::<Vec<_>>();
(true, v)
}
None => default_return,
};

Ok(vec![return_message.append3(
return_value,
DbusErrorEnum::OK as u16,
OK_STRING.to_string(),
)])
}
8 changes: 8 additions & 0 deletions src/dbus_api/pool/pool_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 methods;

pub use api::create_filesystems_method;
2 changes: 1 addition & 1 deletion src/engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ pub trait Pool: Debug + Send + Sync {
&mut self,
pool_name: &str,
pool_uuid: PoolUuid,
specs: &[(&'b str, Option<Bytes>)],
specs: &[(&'b str, Option<Bytes>, Option<Bytes>)],
) -> StratisResult<SetCreateAction<(&'b str, FilesystemUuid, Sectors)>>;

/// Adds blockdevs specified by paths to pool.
Expand Down
11 changes: 6 additions & 5 deletions src/engine/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,17 @@ pub fn validate_filesystem_size(
}

pub fn validate_filesystem_size_specs<'a>(
specs: &[(&'a str, Option<Bytes>)],
) -> StratisResult<HashMap<&'a str, Sectors>> {
specs: &[(&'a str, Option<Bytes>, Option<Bytes>)],
) -> StratisResult<HashMap<&'a str, (Sectors, Option<Sectors>)>> {
specs
.iter()
.map(|&(name, size_opt)| {
.map(|&(name, size_opt, size_limit_opt)| {
let size = validate_filesystem_size(name, size_opt)
.map(|size_opt| size_opt.unwrap_or(DEFAULT_THIN_DEV_SIZE))?;
Ok((name, size))
let size_limit = validate_filesystem_size(name, size_limit_opt)?;
Ok((name, (size, size_limit)))
})
.collect::<StratisResult<HashMap<_, Sectors>>>()
.collect::<StratisResult<HashMap<_, (Sectors, Option<Sectors>)>>>()
}

/// Gather a collection of information from block devices that may or may not
Expand Down
2 changes: 1 addition & 1 deletion src/engine/sim_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ mod tests {
.unwrap();
{
let mut pool = test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(uuid))).unwrap();
pool.create_filesystems(pool_name, uuid, &[("test", None)])
pool.create_filesystems(pool_name, uuid, &[("test", None, None)])
.unwrap();
}
assert!(test_async!(engine.destroy_pool(uuid)).is_err());
Expand Down
15 changes: 11 additions & 4 deletions src/engine/sim_engine/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ pub struct SimFilesystem {
}

impl SimFilesystem {
pub fn new(size: Sectors) -> SimFilesystem {
SimFilesystem {
pub fn new(size: Sectors, size_limit: Option<Sectors>) -> StratisResult<SimFilesystem> {
if let Some(limit) = size_limit {
if limit < size {
return Err(StratisError::Msg(format!(
"Limit of {limit} is less than requested size {size}"
)));
}
}
Ok(SimFilesystem {
rand: rand::random::<u32>(),
created: Utc::now(),
size,
size_limit: None,
}
size_limit,
})
}

pub fn size(&self) -> Sectors {
Expand Down
32 changes: 20 additions & 12 deletions src/engine/sim_engine/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,13 @@ impl Pool for SimPool {
&mut self,
_pool_name: &str,
_pool_uuid: PoolUuid,
specs: &[(&'b str, Option<Bytes>)],
specs: &[(&'b str, Option<Bytes>, Option<Bytes>)],
) -> StratisResult<SetCreateAction<(&'b str, FilesystemUuid, Sectors)>> {
self.check_fs_limit(specs.len())?;

let spec_map = validate_filesystem_size_specs(specs)?;

spec_map.iter().try_fold((), |_, (name, size)| {
spec_map.iter().try_fold((), |_, (name, (size, _))| {
validate_name(name)
.and_then(|()| {
if let Some((_, fs)) = self.filesystems.get_by_name(name) {
Expand All @@ -240,10 +240,10 @@ impl Pool for SimPool {
})?;

let mut result = Vec::new();
for (name, size) in spec_map {
for (name, (size, size_limit)) in spec_map {
if !self.filesystems.contains_name(name) {
let uuid = FilesystemUuid::new_v4();
let new_filesystem = SimFilesystem::new(size);
let new_filesystem = SimFilesystem::new(size, size_limit)?;
self.filesystems
.insert(Name::new((name).to_owned()), uuid, new_filesystem);
result.push((name, uuid, size));
Expand Down Expand Up @@ -533,7 +533,7 @@ impl Pool for SimPool {
return Ok(CreateAction::Identity);
}
}
SimFilesystem::new(filesystem.size())
SimFilesystem::new(filesystem.size(), filesystem.size_limit())?
}
None => {
return Err(StratisError::Msg(origin_uuid.to_string()));
Expand Down Expand Up @@ -759,7 +759,7 @@ mod tests {
.unwrap();
let mut pool = test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(uuid))).unwrap();
let infos = pool
.create_filesystems(pool_name, uuid, &[("old_name", None)])
.create_filesystems(pool_name, uuid, &[("old_name", None, None)])
.unwrap()
.changed()
.unwrap();
Expand Down Expand Up @@ -787,7 +787,11 @@ mod tests {
.unwrap();
let mut pool = test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(uuid))).unwrap();
let results = pool
.create_filesystems(pool_name, uuid, &[(old_name, None), (new_name, None)])
.create_filesystems(
pool_name,
uuid,
&[(old_name, None, None), (new_name, None, None)],
)
.unwrap()
.changed()
.unwrap();
Expand Down Expand Up @@ -874,7 +878,7 @@ mod tests {
.unwrap();
let mut pool = test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(uuid))).unwrap();
let fs_results = pool
.create_filesystems(pool_name, uuid, &[("fs_name", None)])
.create_filesystems(pool_name, uuid, &[("fs_name", None, None)])
.unwrap()
.changed()
.unwrap();
Expand Down Expand Up @@ -918,7 +922,7 @@ mod tests {
.unwrap();
let mut pool = test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(uuid))).unwrap();
assert!(match pool
.create_filesystems(pool_name, uuid, &[("name", None)])
.create_filesystems(pool_name, uuid, &[("name", None, None)])
.ok()
.and_then(|fs| fs.changed())
{
Expand All @@ -942,10 +946,10 @@ mod tests {
.changed()
.unwrap();
let mut pool = test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(uuid))).unwrap();
pool.create_filesystems(pool_name, uuid, &[(fs_name, None)])
pool.create_filesystems(pool_name, uuid, &[(fs_name, None, None)])
.unwrap();
let set_create_action = pool
.create_filesystems(pool_name, uuid, &[(fs_name, None)])
.create_filesystems(pool_name, uuid, &[(fs_name, None, None)])
.unwrap();
assert!(!set_create_action.is_changed());
}
Expand All @@ -966,7 +970,11 @@ mod tests {
.unwrap();
let mut pool = test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(uuid))).unwrap();
assert!(match pool
.create_filesystems(pool_name, uuid, &[(fs_name, None), (fs_name, None)])
.create_filesystems(
pool_name,
uuid,
&[(fs_name, None, None), (fs_name, None, None)]
)
.ok()
.and_then(|fs| fs.changed())
{
Expand Down
4 changes: 2 additions & 2 deletions src/engine/strat_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,12 +788,12 @@ mod test {
let (fs_uuid1, fs_uuid2) = {
let mut pool = test_async!(engine.get_mut_pool(PoolIdentifier::Uuid(uuid1))).unwrap();
let fs_uuid1 = pool
.create_filesystems(name1, uuid1, &[(fs_name1, None)])
.create_filesystems(name1, uuid1, &[(fs_name1, None, None)])
.unwrap()
.changed()
.unwrap();
let fs_uuid2 = pool
.create_filesystems(name1, uuid1, &[(fs_name2, None)])
.create_filesystems(name1, uuid1, &[(fs_name2, None, None)])
.unwrap()
.changed()
.unwrap();
Expand Down
Loading

0 comments on commit 6db9394

Please sign in to comment.