Skip to content

Commit

Permalink
Change StopPool for partially constructed pools
Browse files Browse the repository at this point in the history
This commit makes two changes:

* Switch D-Bus API from D-Bus object path to pool UUID or name to allow
stopping partially constructed pools.

* Modify engine to tear down partially constructed pools for r6 and
later. Otherwise treat partially constructed pools as stopped.
  • Loading branch information
jbaublitz committed Apr 4, 2023
1 parent 8adfe12 commit 2b1e088
Show file tree
Hide file tree
Showing 15 changed files with 397 additions and 221 deletions.
100 changes: 17 additions & 83 deletions src/dbus_api/api/manager_3_2/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@ use futures::executor::block_on;

use crate::{
dbus_api::{
blockdev::create_dbus_blockdev,
api::shared::start_pool_shared,
consts,
filesystem::create_dbus_filesystem,
pool::create_dbus_pool,
types::{DbusErrorEnum, TData, OK_STRING},
util::{engine_to_dbus_err_tuple, get_next_arg, tuple_to_option},
util::{engine_to_dbus_err_tuple, get_next_arg},
},
engine::{Engine, Pool, PoolIdentifier, PoolUuid, StartAction, StopAction, UnlockMethod},
engine::{Engine, Pool, PoolIdentifier, PoolUuid, StopAction},
stratis::StratisError,
};

Expand Down Expand Up @@ -45,84 +43,15 @@ where
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
};
let unlock_method = {
let unlock_method_tup: (bool, &str) = get_next_arg(&mut iter, 1)?;
match tuple_to_option(unlock_method_tup) {
Some(unlock_method_str) => match UnlockMethod::try_from(unlock_method_str) {
Ok(um) => Some(um),
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
},
None => None,
}
};

let ret = match handle_action!(block_on(
dbus_context
.engine
.start_pool(PoolIdentifier::Uuid(pool_uuid), unlock_method)
)) {
Ok(StartAction::Started(_)) => {
let guard = match block_on(
dbus_context
.engine
.get_pool(PoolIdentifier::Uuid(pool_uuid)),
) {
Some(g) => g,
None => {
let (rc, rs) = engine_to_dbus_err_tuple(&StratisError::Msg(
format!("Pool with UUID {pool_uuid} was successfully started but appears to have been removed before it could be exposed on the D-Bus")
));
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
};

let (pool_name, _, pool) = guard.as_tuple();
let pool_path =
create_dbus_pool(dbus_context, base_path.clone(), &pool_name, pool_uuid, pool);
let mut bd_paths = Vec::new();
for (bd_uuid, tier, bd) in pool.blockdevs() {
bd_paths.push(create_dbus_blockdev(
dbus_context,
pool_path.clone(),
bd_uuid,
tier,
bd,
));
}
let mut fs_paths = Vec::new();
for (name, fs_uuid, fs) in pool.filesystems() {
fs_paths.push(create_dbus_filesystem(
dbus_context,
pool_path.clone(),
&pool_name,
&name,
fs_uuid,
fs,
));
}

if pool.is_encrypted() {
dbus_context.push_locked_pools(block_on(dbus_context.engine.locked_pools()));
}
dbus_context.push_stopped_pools(block_on(dbus_context.engine.stopped_pools()));

(true, (pool_path, bd_paths, fs_paths))
}
Ok(StartAction::Identity) => default_return,
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
};

Ok(vec![return_message.append3(
ret,
DbusErrorEnum::OK as u16,
OK_STRING.to_string(),
)])
start_pool_shared(
PoolIdentifier::Uuid(pool_uuid),
base_path,
&mut iter,
dbus_context,
default_return,
return_message,
)
}

pub fn stop_pool<E>(m: &MethodInfo<'_, MTSync<TData<E>>, TData<E>>) -> MethodResult
Expand Down Expand Up @@ -169,7 +98,11 @@ where
})
.unwrap_or(false);

let msg = match handle_action!(block_on(dbus_context.engine.stop_pool(pool_uuid))) {
let msg = match handle_action!(block_on(
dbus_context
.engine
.stop_pool(PoolIdentifier::Uuid(pool_uuid), true)
)) {
Ok(StopAction::Stopped(_)) => {
dbus_context.push_remove(&pool_path, consts::pool_interface_list());
if send_locked_signal {
Expand All @@ -182,6 +115,7 @@ where
OK_STRING.to_string(),
)
}
Ok(StopAction::CleanedUp(_)) => unreachable!("!has_partially_constructed above"),
Ok(StopAction::Identity) => return_message.append3(
default_return,
DbusErrorEnum::OK as u16,
Expand Down
90 changes: 12 additions & 78 deletions src/dbus_api/api/manager_3_4/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@

use dbus::{Message, Path};
use dbus_tree::{MTSync, MethodInfo, MethodResult};
use futures::executor::block_on;

use crate::{
dbus_api::{
blockdev::create_dbus_blockdev,
filesystem::create_dbus_filesystem,
pool::create_dbus_pool,
types::{DbusErrorEnum, TData, OK_STRING},
util::{engine_to_dbus_err_tuple, get_next_arg, tuple_to_option},
api::shared::start_pool_shared,
types::TData,
util::{engine_to_dbus_err_tuple, get_next_arg},
},
engine::{Engine, Name, Pool, PoolIdentifier, PoolUuid, StartAction, UnlockMethod},
engine::{Engine, Name, PoolIdentifier, PoolUuid},
stratis::StratisError,
};

Expand Down Expand Up @@ -52,76 +49,13 @@ where
}
}
};
let unlock_method = {
let unlock_method_tup: (bool, &str) = get_next_arg(&mut iter, 2)?;
match tuple_to_option(unlock_method_tup) {
Some(unlock_method_str) => match UnlockMethod::try_from(unlock_method_str) {
Ok(um) => Some(um),
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
},
None => None,
}
};

let ret = match handle_action!(block_on(
dbus_context.engine.start_pool(id.clone(), unlock_method)
)) {
Ok(StartAction::Started(_)) => {
let guard = match block_on(dbus_context.engine.get_pool(id.clone())) {
Some(g) => g,
None => {
let (rc, rs) = engine_to_dbus_err_tuple(&StratisError::Msg(
format!("Pool with {id:?} was successfully started but appears to have been removed before it could be exposed on the D-Bus")
));
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
};

let (pool_name, pool_uuid, pool) = guard.as_tuple();
let pool_path =
create_dbus_pool(dbus_context, base_path.clone(), &pool_name, pool_uuid, pool);
let mut bd_paths = Vec::new();
for (bd_uuid, tier, bd) in pool.blockdevs() {
bd_paths.push(create_dbus_blockdev(
dbus_context,
pool_path.clone(),
bd_uuid,
tier,
bd,
));
}
let mut fs_paths = Vec::new();
for (name, fs_uuid, fs) in pool.filesystems() {
fs_paths.push(create_dbus_filesystem(
dbus_context,
pool_path.clone(),
&pool_name,
&name,
fs_uuid,
fs,
));
}

if pool.is_encrypted() {
dbus_context.push_locked_pools(block_on(dbus_context.engine.locked_pools()));
}
dbus_context.push_stopped_pools(block_on(dbus_context.engine.stopped_pools()));

(true, (pool_path, bd_paths, fs_paths))
}
Ok(StartAction::Identity) => default_return,
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
};

Ok(vec![return_message.append3(
ret,
DbusErrorEnum::OK as u16,
OK_STRING.to_string(),
)])
start_pool_shared(
id,
base_path,
&mut iter,
dbus_context,
default_return,
return_message,
)
}
29 changes: 29 additions & 0 deletions src/dbus_api/api/manager_3_6/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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::{api::manager_3_6::methods::stop_pool, types::TData},
engine::Engine,
};

pub fn stop_pool_method<E>(
f: &Factory<MTSync<TData<E>>, TData<E>>,
) -> Method<MTSync<TData<E>>, TData<E>>
where
E: 'static + Engine,
{
f.method("StopPool", (), stop_pool)
.in_arg(("id", "s"))
.in_arg(("id_type", "s"))
// In order from left to right:
// b: true if the pool was newly stopped
// s: string representation of UUID of stopped pool
//
// Rust representation: (bool, String)
.out_arg(("result", "(bs)"))
.out_arg(("return_code", "q"))
.out_arg(("return_string", "s"))
}
116 changes: 116 additions & 0 deletions src/dbus_api/api/manager_3_6/methods.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// 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::Message;
use dbus_tree::{MTSync, MethodInfo, MethodResult};
use futures::executor::block_on;

use crate::{
dbus_api::{
consts,
types::{DbusErrorEnum, TData, OK_STRING},
util::{engine_to_dbus_err_tuple, get_next_arg},
},
engine::{Engine, Name, Pool, PoolIdentifier, PoolUuid, StopAction, StratisUuid},
stratis::StratisError,
};

pub fn stop_pool<E>(m: &MethodInfo<'_, MTSync<TData<E>>, TData<E>>) -> MethodResult
where
E: 'static + Engine,
{
let message: &Message = m.msg;
let mut iter = message.iter_init();
let dbus_context = m.tree.get_data();
let default_return = (false, String::new());
let return_message = message.method_return();

let id_str: &str = get_next_arg(&mut iter, 0)?;
let pool_id = {
let id_type_str: &str = get_next_arg(&mut iter, 1)?;
match id_type_str {
"uuid" => match PoolUuid::parse_str(id_str) {
Ok(u) => PoolIdentifier::Uuid(u),
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
},
"name" => PoolIdentifier::Name(Name::new(id_str.to_string())),
_ => {
let (rc, rs) = engine_to_dbus_err_tuple(&StratisError::Msg(format!(
"ID type {id_type_str} not recognized"
)));
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
}
};

// If Some(_), send a locked pool property change signal only if the pool is
// encrypted. If None, the pool may already be stopped or not exist at all.
// Both of these cases are handled by stop_pool and the value we provide
// for send_locked_signal does not matter as send_locked_signal is only
// used when a pool is newly stopped which can only occur if the pool is found
// here.
let send_locked_signal = block_on(dbus_context.engine.get_pool(pool_id.clone()))
.map(|g| {
let (_, _, p) = g.as_tuple();
p.is_encrypted()
})
.unwrap_or(false);

let msg = match handle_action!(block_on(dbus_context.engine.stop_pool(pool_id, true))) {
Ok(StopAction::Stopped(pool_uuid)) => {
match m.tree.iter().find_map(|opath| {
opath
.get_data()
.as_ref()
.and_then(|op_cxt| match op_cxt.uuid {
StratisUuid::Pool(u) => {
if u == pool_uuid {
Some(opath.get_name())
} else {
None
}
}
StratisUuid::Fs(_) => None,
StratisUuid::Dev(_) => None,
})
}) {
Some(pool_path) => {
dbus_context.push_remove(pool_path, consts::pool_interface_list());
if send_locked_signal {
dbus_context
.push_locked_pools(block_on(dbus_context.engine.locked_pools()));
}
dbus_context.push_stopped_pools(block_on(dbus_context.engine.stopped_pools()));
}
None => {
warn!("Could not find pool D-Bus path for the pool that was just stopped");
}
}
return_message.append3(
(true, uuid_to_string!(pool_uuid)),
DbusErrorEnum::OK as u16,
OK_STRING.to_string(),
)
}
Ok(StopAction::CleanedUp(pool_uuid)) => return_message.append3(
(true, uuid_to_string!(pool_uuid)),
DbusErrorEnum::OK as u16,
OK_STRING.to_string(),
),
Ok(StopAction::Identity) => return_message.append3(
default_return,
DbusErrorEnum::OK as u16,
OK_STRING.to_string(),
),
Err(e) => {
let (rc, rs) = engine_to_dbus_err_tuple(&e);
return Ok(vec![return_message.append3(default_return, rc, rs)]);
}
};

Ok(vec![msg])
}
4 changes: 4 additions & 0 deletions src/dbus_api/api/manager_3_6/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod api;
mod methods;

pub use api::stop_pool_method;
Loading

0 comments on commit 2b1e088

Please sign in to comment.