Skip to content

Commit

Permalink
Merge pull request #3297 from jbaublitz/stop-pool-changes
Browse files Browse the repository at this point in the history
Stop pool changes
  • Loading branch information
mulkieran authored May 3, 2023
2 parents c269b2d + ce6bb76 commit 77cc6df
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 55 deletions.
10 changes: 8 additions & 2 deletions src/dbus_api/api/manager_3_2/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ 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) {
Expand Down Expand Up @@ -79,7 +80,7 @@ where
}
};

let (pool_name, _, pool) = guard.as_tuple();
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();
Expand Down Expand Up @@ -169,7 +170,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), false)
)) {
Ok(StopAction::Stopped(_)) => {
dbus_context.push_remove(&pool_path, consts::pool_interface_list());
if send_locked_signal {
Expand All @@ -182,6 +187,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
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;
3 changes: 2 additions & 1 deletion src/dbus_api/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod manager_3_0;
mod manager_3_2;
mod manager_3_4;
mod manager_3_5;
mod manager_3_6;
pub mod prop_conv;
mod report_3_0;
mod shared;
Expand Down Expand Up @@ -135,7 +136,7 @@ where
.add_m(manager_3_0::destroy_pool_method(&f))
.add_m(manager_3_0::engine_state_report_method(&f))
.add_m(manager_3_4::start_pool_method(&f))
.add_m(manager_3_2::stop_pool_method(&f))
.add_m(manager_3_6::stop_pool_method(&f))
.add_m(manager_3_2::refresh_state_method(&f))
.add_p(manager_3_0::version_property(&f))
.add_p(manager_3_2::stopped_pools_property(&f)),
Expand Down
6 changes: 5 additions & 1 deletion src/engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,11 @@ pub trait Engine: Debug + Report + Send + Sync {

/// Stop and tear down a pool, storing the information for it to be started
/// again later.
async fn stop_pool(&self, pool_uuid: PoolUuid) -> StratisResult<StopAction<PoolUuid>>;
async fn stop_pool(
&self,
pool_id: PoolIdentifier<PoolUuid>,
has_partially_constructed: bool,
) -> StratisResult<StopAction<PoolUuid>>;

/// Refresh the state of all pools and liminal devices.
async fn refresh_state(&self) -> StratisResult<()>;
Expand Down
40 changes: 29 additions & 11 deletions src/engine/sim_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,24 +342,42 @@ impl Engine for SimEngine {
}
}

async fn stop_pool(&self, pool_uuid: PoolUuid) -> StratisResult<StopAction<PoolUuid>> {
if self
.stopped_pools
.read()
.await
.get_by_uuid(pool_uuid)
.is_some()
{
Ok(StopAction::Identity)
} else if let Some((name, pool)) = self.pools.write_all().await.remove_by_uuid(pool_uuid) {
async fn stop_pool(
&self,
pool_id: PoolIdentifier<PoolUuid>,
_: bool,
) -> StratisResult<StopAction<PoolUuid>> {
let is_stopped = match pool_id {
PoolIdentifier::Name(ref n) => self.stopped_pools.read().await.get_by_name(n).is_some(),
PoolIdentifier::Uuid(u) => self.stopped_pools.read().await.get_by_uuid(u).is_some(),
};
if is_stopped {
return Ok(StopAction::Identity);
}

let pool_entry = match pool_id {
PoolIdentifier::Name(ref n) => self
.pools
.write_all()
.await
.remove_by_name(n)
.map(|(u, p)| (n.clone(), u, p)),
PoolIdentifier::Uuid(u) => self
.pools
.write_all()
.await
.remove_by_uuid(u)
.map(|(n, p)| (n, u, p)),
};
if let Some((name, pool_uuid, pool)) = pool_entry {
self.stopped_pools
.write()
.await
.insert(name, pool_uuid, pool);
Ok(StopAction::Stopped(pool_uuid))
} else {
Err(StratisError::Msg(format!(
"Pool with UUID {pool_uuid} was not found and cannot be stopped"
"Pool with ID {pool_id} was not found and cannot be stopped"
)))
}
}
Expand Down
60 changes: 42 additions & 18 deletions src/engine/strat_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,29 +657,49 @@ impl Engine for StratEngine {
}
}

async fn stop_pool(&self, pool_uuid: PoolUuid) -> StratisResult<StopAction<PoolUuid>> {
async fn stop_pool(
&self,
pool_id: PoolIdentifier<PoolUuid>,
has_partially_constructed: bool,
) -> StratisResult<StopAction<PoolUuid>> {
let id_str = pool_id.to_string();

let stopped_pools = self.liminal_devices.read().await.stopped_pools();
let pool_uuid = match pool_id {
PoolIdentifier::Name(ref n) => stopped_pools.name_to_uuid.get(n),
PoolIdentifier::Uuid(ref u) => Some(u),
};
if let Some(pool_uuid) = pool_uuid {
if has_partially_constructed {
if stopped_pools.stopped.get(pool_uuid).is_some() {
return Ok(StopAction::Identity);
} else if stopped_pools.partially_constructed.get(pool_uuid).is_some() {
self.liminal_devices
.write()
.await
.stop_partially_constructed_pool(*pool_uuid)?;
return Ok(StopAction::CleanedUp(*pool_uuid));
}
} else if stopped_pools.stopped.get(pool_uuid).is_some()
|| stopped_pools.partially_constructed.get(pool_uuid).is_some()
{
return Ok(StopAction::Identity);
}
}

let mut pools = self.pools.write_all().await;
if let Some((name, pool)) = pools.remove_by_uuid(pool_uuid) {
if let Some((name, pool_uuid, pool)) = match pool_id {
PoolIdentifier::Name(n) => pools.remove_by_name(&n).map(|(u, p)| (n, u, p)),
PoolIdentifier::Uuid(u) => pools.remove_by_uuid(u).map(|(n, p)| (n, u, p)),
} {
self.liminal_devices
.write()
.await
.stop_pool(&mut pools, name, pool_uuid, pool)?;
return Ok(StopAction::Stopped(pool_uuid));
}

drop(pools);

let stopped_pools = self.liminal_devices.read().await.stopped_pools();
if stopped_pools.stopped.get(&pool_uuid).is_some()
|| stopped_pools
.partially_constructed
.get(&pool_uuid)
.is_some()
{
Ok(StopAction::Identity)
Ok(StopAction::Stopped(pool_uuid))
} else {
Err(StratisError::Msg(format!(
"Pool with UUID {pool_uuid} could not be found and cannot be stopped"
"Pool with UUID {id_str} could not be found and cannot be stopped"
)))
}
}
Expand Down Expand Up @@ -938,7 +958,7 @@ mod test {
let res = init_res.and_then(|_| needs_clean_up(&mut pool, fail_device, operation));
drop(pool);

test_async!(engine.stop_pool(uuid))?;
test_async!(engine.stop_pool(PoolIdentifier::Uuid(uuid), true))?;
res?;

test_async!(engine.start_pool(PoolIdentifier::Uuid(uuid), Some(unlock_method)))?;
Expand Down Expand Up @@ -1360,7 +1380,11 @@ mod test {
.unwrap()
.changed()
.unwrap();
assert!(test_async!(engine.stop_pool(uuid)).unwrap().is_changed());
assert!(
test_async!(engine.stop_pool(PoolIdentifier::Uuid(uuid), true))
.unwrap()
.is_changed()
);
assert_eq!(test_async!(engine.stopped_pools()).stopped.len(), 1);
assert_eq!(test_async!(engine.pools()).len(), 0);

Expand Down
14 changes: 14 additions & 0 deletions src/engine/strat_engine/liminal/liminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,20 @@ impl LiminalDevices {
}
}

/// Tear down a partially constructed pool.
pub fn stop_partially_constructed_pool(&mut self, pool_uuid: PoolUuid) -> StratisResult<()> {
if let Some(device_set) = self.partially_constructed_pools.get(&pool_uuid) {
stop_partially_constructed_pool(
pool_uuid,
&device_set
.iter()
.map(|(dev_uuid, _)| *dev_uuid)
.collect::<Vec<_>>(),
)?;
}
Ok(())
}

/// Get a mapping of pool UUIDs from all of the LUKS2 devices that are currently
/// locked to their encryption info in the set of pools that are not yet set up.
pub fn locked_pools(&self) -> LockedPoolsInfo {
Expand Down
Loading

0 comments on commit 77cc6df

Please sign in to comment.