From a00fad3e7e8be719b6bcfc9441e591a033499e2b Mon Sep 17 00:00:00 2001 From: John Baublitz Date: Tue, 17 Sep 2024 15:32:38 -0400 Subject: [PATCH] Add online reencrypt ability for Stratis pools --- src/dbus_api/pool/mod.rs | 1 + src/dbus_api/pool/pool_3_8/api.rs | 12 +- src/dbus_api/pool/pool_3_8/methods.rs | 33 ++++++ src/dbus_api/pool/pool_3_8/mod.rs | 4 +- src/engine/engine.rs | 7 +- src/engine/sim_engine/pool.rs | 8 +- .../strat_engine/backstore/backstore/v1.rs | 20 ++++ .../strat_engine/backstore/backstore/v2.rs | 14 +++ .../strat_engine/backstore/blockdev/v1.rs | 10 ++ src/engine/strat_engine/crypt/handle/v1.rs | 7 +- src/engine/strat_engine/crypt/handle/v2.rs | 65 ++--------- src/engine/strat_engine/crypt/shared.rs | 108 +++++++++++++++++- src/engine/strat_engine/pool/dispatch.rs | 11 +- src/engine/strat_engine/pool/v1.rs | 7 +- src/engine/strat_engine/pool/v2.rs | 10 +- src/engine/types/actions.rs | 9 ++ src/engine/types/mod.rs | 2 +- 17 files changed, 255 insertions(+), 73 deletions(-) diff --git a/src/dbus_api/pool/mod.rs b/src/dbus_api/pool/mod.rs index 339869e984..ac7d47227b 100644 --- a/src/dbus_api/pool/mod.rs +++ b/src/dbus_api/pool/mod.rs @@ -295,6 +295,7 @@ pub fn create_dbus_pool<'a>( .add_m(pool_3_7::get_metadata_method(&f)) .add_m(pool_3_7::get_fs_metadata_method(&f)) .add_m(pool_3_8::encrypt_pool_method(&f)) + .add_m(pool_3_8::reencrypt_pool_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_8/api.rs b/src/dbus_api/pool/pool_3_8/api.rs index ec4db87dd8..b3789a3617 100644 --- a/src/dbus_api/pool/pool_3_8/api.rs +++ b/src/dbus_api/pool/pool_3_8/api.rs @@ -10,7 +10,7 @@ use crate::dbus_api::{ pool_3_8::{ methods::{ bind_clevis, bind_keyring, encrypt_pool, rebind_clevis, rebind_keyring, - unbind_clevis, unbind_keyring, + reencrypt_pool, unbind_clevis, unbind_keyring, }, props::{get_pool_clevis_infos, get_pool_key_descs}, }, @@ -128,3 +128,13 @@ pub fn encrypt_pool_method(f: &Factory, TData>) -> Method, TData>) -> Method, TData> { + f.method("ReencryptPool", (), reencrypt_pool) + // b: true if successful + // + // Rust representation: bool + .out_arg(("results", "b")) + .out_arg(("return_code", "q")) + .out_arg(("return_string", "s")) +} diff --git a/src/dbus_api/pool/pool_3_8/methods.rs b/src/dbus_api/pool/pool_3_8/methods.rs index 7f3519d5b6..898512c893 100644 --- a/src/dbus_api/pool/pool_3_8/methods.rs +++ b/src/dbus_api/pool/pool_3_8/methods.rs @@ -513,3 +513,36 @@ pub fn encrypt_pool(m: &MethodInfo<'_, MTSync, TData>) -> MethodResult { }; Ok(vec![msg]) } + +pub fn reencrypt_pool(m: &MethodInfo<'_, MTSync, TData>) -> MethodResult { + let message: &Message = m.msg; + + let dbus_context = m.tree.get_data(); + let object_path = m.path.get_name(); + let return_message = message.method_return(); + let default_return = false; + + 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) = guard.as_mut_tuple(); + + let result = handle_action!(pool.reencrypt_pool(), dbus_context, pool_path.get_name()); + let msg = match result { + Ok(_) => return_message.append3(true, 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_8/mod.rs b/src/dbus_api/pool/pool_3_8/mod.rs index 28f1a2588b..7515193f9d 100644 --- a/src/dbus_api/pool/pool_3_8/mod.rs +++ b/src/dbus_api/pool/pool_3_8/mod.rs @@ -8,6 +8,6 @@ mod props; pub use api::{ bind_clevis_method, bind_keyring_method, clevis_infos_property, encrypt_pool_method, - key_descs_property, rebind_clevis_method, rebind_keyring_method, unbind_clevis_method, - unbind_keyring_method, + key_descs_property, rebind_clevis_method, rebind_keyring_method, reencrypt_pool_method, + unbind_clevis_method, unbind_keyring_method, }; diff --git a/src/engine/engine.rs b/src/engine/engine.rs index 216d452eb3..9bdc247a35 100644 --- a/src/engine/engine.rs +++ b/src/engine/engine.rs @@ -25,8 +25,8 @@ use crate::{ EncryptedDevice, EncryptionInfo, FilesystemUuid, GrowAction, InputEncryptionInfo, IntegritySpec, Key, KeyDescription, LockedPoolsInfo, MappingCreateAction, MappingDeleteAction, Name, OptionalTokenSlotInput, PoolDiff, PoolEncryptionInfo, - PoolIdentifier, PoolUuid, PropChangeAction, RegenAction, RenameAction, ReportType, - SetCreateAction, SetDeleteAction, SetUnlockAction, StartAction, StopAction, + PoolIdentifier, PoolUuid, PropChangeAction, Reencrypt, RegenAction, RenameAction, + ReportType, SetCreateAction, SetDeleteAction, SetUnlockAction, StartAction, StopAction, StoppedPoolsInfo, StratBlockDevDiff, StratFilesystemDiff, StratSigblockVersion, TokenUnlockMethod, UdevEngineEvent, UnlockMethod, }, @@ -396,6 +396,9 @@ pub trait Pool: Debug + Send + Sync { encryption_info: &InputEncryptionInfo, ) -> StratisResult>; + /// Reencrypt an encrypted pool. + fn reencrypt_pool(&mut self) -> StratisResult; + /// Return the metadata that would be written if metadata were written. fn current_metadata(&self, pool_name: &Name) -> StratisResult; diff --git a/src/engine/sim_engine/pool.rs b/src/engine/sim_engine/pool.rs index 454ef55c0c..36849af89c 100644 --- a/src/engine/sim_engine/pool.rs +++ b/src/engine/sim_engine/pool.rs @@ -28,8 +28,8 @@ use crate::{ ActionAvailability, BlockDevTier, Clevis, CreateAction, DeleteAction, DevUuid, EncryptedDevice, EncryptionInfo, FilesystemUuid, GrowAction, InputEncryptionInfo, Key, KeyDescription, Name, OptionalTokenSlotInput, PoolDiff, PoolEncryptionInfo, PoolUuid, - PropChangeAction, RegenAction, RenameAction, SetCreateAction, SetDeleteAction, - StratSigblockVersion, UnlockMechanism, ValidatedIntegritySpec, + PropChangeAction, Reencrypt, RegenAction, RenameAction, SetCreateAction, + SetDeleteAction, StratSigblockVersion, UnlockMechanism, ValidatedIntegritySpec, }, }, stratis::{StratisError, StratisResult}, @@ -854,6 +854,10 @@ impl Pool for SimPool { Ok(CreateAction::Created(EncryptedDevice)) } + fn reencrypt_pool(&mut self) -> StratisResult { + Ok(Reencrypt) + } + fn current_metadata(&self, pool_name: &Name) -> StratisResult { serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into()) } diff --git a/src/engine/strat_engine/backstore/backstore/v1.rs b/src/engine/strat_engine/backstore/backstore/v1.rs index d61c5ae45a..4e3299d09a 100644 --- a/src/engine/strat_engine/backstore/backstore/v1.rs +++ b/src/engine/strat_engine/backstore/backstore/v1.rs @@ -862,6 +862,26 @@ impl Backstore { } } + /// Reencrypt all encrypted devices in the pool. + /// + /// Returns: + /// * Ok(()) if successful + /// * Err(_) if an operation fails while reencrypting the devices. + pub fn reencrypt(&mut self) -> StratisResult<()> { + if self.encryption_info().is_none() { + return Err(StratisError::Msg( + "Requested pool does not appear to be encrypted".to_string(), + )); + }; + + // Keys are not the same but key description is present + operation_loop( + self.blockdevs_mut().into_iter().map(|(_, _, bd)| bd), + |blockdev| blockdev.reencrypt(), + )?; + Ok(()) + } + /// Regenerate the Clevis bindings with the block devices in this pool using /// the same configuration. /// diff --git a/src/engine/strat_engine/backstore/backstore/v2.rs b/src/engine/strat_engine/backstore/backstore/v2.rs index f25fa9c20c..9788cf5d93 100644 --- a/src/engine/strat_engine/backstore/backstore/v2.rs +++ b/src/engine/strat_engine/backstore/backstore/v2.rs @@ -1258,6 +1258,20 @@ impl Backstore { Ok(()) } + pub fn reencrypt(&self) -> StratisResult<()> { + match self.enc { + Some(Either::Left(_)) => { + Err(StratisError::Msg("Encrypted pool where the encrypted device has not yet been created cannot be reencrypted".to_string())) + } + Some(Either::Right(ref handle)) => { + handle.reencrypt() + } + None => { + Err(StratisError::Msg("Unencrypted device cannot be reencrypted".to_string())) + } + } + } + /// A summary of block sizes pub fn block_size_summary(&self, tier: BlockDevTier) -> Option { match tier { diff --git a/src/engine/strat_engine/backstore/blockdev/v1.rs b/src/engine/strat_engine/backstore/blockdev/v1.rs index dd628fca0f..5f346de826 100644 --- a/src/engine/strat_engine/backstore/blockdev/v1.rs +++ b/src/engine/strat_engine/backstore/blockdev/v1.rs @@ -416,6 +416,16 @@ impl StratBlockDev { } } } + + /// Reencrypt an individual block device in a pool. + pub fn reencrypt(&self) -> StratisResult<()> { + let crypt_handle = self + .underlying_device + .crypt_handle() + .expect("Checked that pool is encrypted"); + crypt_handle.reencrypt() + } + #[cfg(test)] pub fn invariant(&self) { assert!(self.total_size() == self.used.size()); diff --git a/src/engine/strat_engine/crypt/handle/v1.rs b/src/engine/strat_engine/crypt/handle/v1.rs index 43af0cf138..0ae49cb529 100644 --- a/src/engine/strat_engine/crypt/handle/v1.rs +++ b/src/engine/strat_engine/crypt/handle/v1.rs @@ -45,7 +45,7 @@ use crate::{ check_luks2_token, clevis_decrypt, device_from_physical_path, encryption_info_from_metadata, ensure_inactive, ensure_wiped, get_keyslot_number, interpret_clevis_config, luks2_token_type_is_valid, - read_key, wipe_fallback, + read_key, reencrypt_shared, wipe_fallback, }, }, dm::DEVICEMAPPER_PATH, @@ -981,6 +981,11 @@ impl CryptHandle { Ok(()) } + /// Encrypt an unencrypted pool. + pub fn reencrypt(&self) -> StratisResult<()> { + reencrypt_shared(self.luks2_device_path(), self.encryption_info()) + } + /// Rename the pool in the LUKS2 token. pub fn rename_pool_in_metadata(&mut self, pool_name: Name) -> StratisResult<()> { let mut device = self.acquire_crypt_device()?; diff --git a/src/engine/strat_engine/crypt/handle/v2.rs b/src/engine/strat_engine/crypt/handle/v2.rs index cbb178e482..8018d13fc1 100644 --- a/src/engine/strat_engine/crypt/handle/v2.rs +++ b/src/engine/strat_engine/crypt/handle/v2.rs @@ -43,9 +43,10 @@ use crate::{ }, shared::{ acquire_crypt_device, activate, activate_by_token, add_keyring_keyslot, - clevis_decrypt, clevis_info_from_json, device_from_physical_path, + clevis_info_from_json, device_from_physical_path, encryption_info_from_metadata, ensure_wiped, get_keyslot_number, - interpret_clevis_config, read_key, wipe_fallback, + get_passphrase, interpret_clevis_config, read_key, reencrypt_shared, + wipe_fallback, }, }, device::blkdev_size, @@ -182,61 +183,6 @@ fn setup_crypt_handle( ))) } -/// Get one of the passphrases for the encrypted device. -fn get_passphrase( - device: &mut CryptDevice, - encryption_info: &EncryptionInfo, -) -> StratisResult<(c_uint, SizedKeyMemory)> { - for (ts, mech) in encryption_info.all_infos() { - match mech { - UnlockMechanism::KeyDesc(kd) => match read_key(kd) { - Ok(Some(pass)) => { - let keyslot = match get_keyslot_number(device, *ts) { - Ok(Some(ks)) => ks, - Ok(None) => { - warn!("Failed to find keyslot associated with the given token"); - continue; - } - Err(e) => { - warn!("Failure while finding keyslot associated with the given token: {e}"); - continue; - } - }; - return Ok((keyslot, pass)); - } - Ok(None) => { - info!("Key description was not in keyring; trying next unlock mechanism") - } - Err(e) => info!("Error searching keyring: {e}"), - }, - UnlockMechanism::ClevisInfo(_) => match clevis_decrypt(device, *ts) { - Ok(Some(pass)) => { - let keyslot = match get_keyslot_number(device, *ts) { - Ok(Some(ks)) => ks, - Ok(None) => { - warn!("Failed to find keyslot associated with the given token"); - continue; - } - Err(e) => { - warn!("Failure while finding keyslot associated with the given token: {e}"); - continue; - } - }; - return Ok((keyslot, pass)); - } - Ok(None) => { - info!("Key description was not in keyring; trying next unlock mechanism") - } - Err(e) => info!("Error searching keyring: {e}"), - }, - } - } - - Err(StratisError::Msg( - "Unable to get passphrase for any available token slots".to_string(), - )) -} - /// Handle for performing all operations on an encrypted device. /// /// `Clone` is derived for this data structure because `CryptHandle` acquires @@ -856,6 +802,11 @@ impl CryptHandle { .map(|h| h.expect("should have crypt device after online encrypt")) } + /// Encrypt an unencrypted pool. + pub fn reencrypt(&self) -> StratisResult<()> { + reencrypt_shared(self.luks2_device_path(), self.encryption_info()) + } + /// Deactivate the device referenced by the current device handle. #[cfg(test)] pub fn deactivate(&self) -> StratisResult<()> { diff --git a/src/engine/strat_engine/crypt/shared.rs b/src/engine/strat_engine/crypt/shared.rs index 4f4e547816..0510c3d4f4 100644 --- a/src/engine/strat_engine/crypt/shared.rs +++ b/src/engine/strat_engine/crypt/shared.rs @@ -21,12 +21,14 @@ use devicemapper::{Bytes, DevId, DmName, DmOptions}; use libcryptsetup_rs::{ c_uint, consts::{ - flags::{CryptActivate, CryptVolumeKey, CryptWipe}, + flags::{CryptActivate, CryptReencrypt, CryptVolumeKey, CryptWipe}, vals::{ - CryptDebugLevel, CryptLogLevel, CryptStatusInfo, CryptWipePattern, EncryptionFormat, + CryptDebugLevel, CryptLogLevel, CryptReencryptDirectionInfo, CryptReencryptModeInfo, + CryptStatusInfo, CryptWipePattern, EncryptionFormat, }, }, - register, set_debug_level, set_log_callback, CryptDevice, CryptInit, + get_sector_size, register, set_debug_level, set_log_callback, CryptDevice, CryptInit, + CryptParamsLuks2, CryptParamsReencrypt, }; use crate::{ @@ -969,6 +971,106 @@ pub fn clevis_decrypt( cmd::clevis_decrypt(&jwe).map(Some) } +/// Get one of the passphrases for the encrypted device. +pub fn get_passphrase( + device: &mut CryptDevice, + encryption_info: &EncryptionInfo, +) -> StratisResult<(c_uint, SizedKeyMemory)> { + for (ts, mech) in encryption_info.all_infos() { + match mech { + UnlockMechanism::KeyDesc(kd) => match read_key(kd) { + Ok(Some(pass)) => { + let keyslot = match get_keyslot_number(device, *ts) { + Ok(Some(ks)) => ks, + Ok(None) => { + warn!("Failed to find keyslot associated with the given token"); + continue; + } + Err(e) => { + warn!("Failure while finding keyslot associated with the given token: {e}"); + continue; + } + }; + return Ok((keyslot, pass)); + } + Ok(None) => { + info!("Key description was not in keyring; trying next unlock mechanism") + } + Err(e) => info!("Error searching keyring: {e}"), + }, + UnlockMechanism::ClevisInfo(_) => match clevis_decrypt(device, *ts) { + Ok(Some(pass)) => { + let keyslot = match get_keyslot_number(device, *ts) { + Ok(Some(ks)) => ks, + Ok(None) => { + warn!("Failed to find keyslot associated with the given token"); + continue; + } + Err(e) => { + warn!("Failure while finding keyslot associated with the given token: {e}"); + continue; + } + }; + return Ok((keyslot, pass)); + } + Ok(None) => { + info!("Key description was not in keyring; trying next unlock mechanism") + } + Err(e) => info!("Error searching keyring: {e}"), + }, + } + } + + Err(StratisError::Msg( + "Unable to get passphrase for any available token slots".to_string(), + )) +} + +pub fn reencrypt_shared(luks2_path: &Path, encryption_info: &EncryptionInfo) -> StratisResult<()> { + let mut device = CryptInit::init(luks2_path)?; + + let (keyslot, key) = get_passphrase(&mut device, encryption_info)?; + let new_keyslot = + device + .keyslot_handle() + .add_by_key(None, None, key.as_ref(), CryptVolumeKey::NO_SEGMENT)?; + + let cipher = device.status_handle().get_cipher()?; + let cipher_mode = device.status_handle().get_cipher_mode()?; + let sector_size = convert_int!(get_sector_size(Some(&mut device)), i32, u32)?; + device.reencrypt_handle().reencrypt_init_by_passphrase( + None, + key.as_ref(), + Some(keyslot), + new_keyslot, + (&cipher, &cipher_mode), + CryptParamsReencrypt { + mode: CryptReencryptModeInfo::Reencrypt, + direction: CryptReencryptDirectionInfo::Forward, + resilience: "checksum".to_string(), + hash: "sha256".to_string(), + data_shift: 0, + max_hotzone_size: 0, + device_size: 0, + luks2: CryptParamsLuks2 { + data_alignment: 0, + data_device: None, + integrity: None, + integrity_params: None, + pbkdf: None, + label: None, + sector_size, + subsystem: None, + }, + flags: CryptReencrypt::INITIALIZE_ONLY, + }, + )?; + + device.reencrypt_handle().reencrypt2::<()>(None, None)?; + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/engine/strat_engine/pool/dispatch.rs b/src/engine/strat_engine/pool/dispatch.rs index 244a328606..4034e1bdcc 100644 --- a/src/engine/strat_engine/pool/dispatch.rs +++ b/src/engine/strat_engine/pool/dispatch.rs @@ -17,8 +17,8 @@ use crate::{ ActionAvailability, BlockDevTier, Clevis, CreateAction, DeleteAction, DevUuid, EncryptedDevice, EncryptionInfo, FilesystemUuid, GrowAction, InputEncryptionInfo, Key, KeyDescription, Name, OptionalTokenSlotInput, PoolDiff, PoolEncryptionInfo, PoolUuid, - PropChangeAction, RegenAction, RenameAction, SetCreateAction, SetDeleteAction, - StratSigblockVersion, + PropChangeAction, Reencrypt, RegenAction, RenameAction, SetCreateAction, + SetDeleteAction, StratSigblockVersion, }, }, stratis::StratisResult, @@ -353,6 +353,13 @@ impl Pool for AnyPool { } } + fn reencrypt_pool(&mut self) -> StratisResult { + match self { + AnyPool::V1(p) => p.reencrypt_pool(), + AnyPool::V2(p) => p.reencrypt_pool(), + } + } + fn current_metadata(&self, pool_name: &Name) -> StratisResult { match self { AnyPool::V1(p) => p.current_metadata(pool_name), diff --git a/src/engine/strat_engine/pool/v1.rs b/src/engine/strat_engine/pool/v1.rs index 92c23a0114..d876608fec 100644 --- a/src/engine/strat_engine/pool/v1.rs +++ b/src/engine/strat_engine/pool/v1.rs @@ -47,7 +47,7 @@ use crate::{ ActionAvailability, BlockDevTier, Clevis, Compare, CreateAction, DeleteAction, DevUuid, Diff, EncryptedDevice, EncryptionInfo, FilesystemUuid, GrowAction, InputEncryptionInfo, Key, KeyDescription, Name, OffsetDirection, OptionalTokenSlotInput, PoolDiff, - PoolEncryptionInfo, PoolUuid, PropChangeAction, RegenAction, RenameAction, + PoolEncryptionInfo, PoolUuid, PropChangeAction, Reencrypt, RegenAction, RenameAction, SetCreateAction, SetDeleteAction, StratFilesystemDiff, StratPoolDiff, StratSigblockVersion, }, @@ -1306,6 +1306,11 @@ impl Pool for StratPool { )) } + fn reencrypt_pool(&mut self) -> StratisResult { + self.backstore.reencrypt()?; + Ok(Reencrypt) + } + fn current_metadata(&self, pool_name: &Name) -> StratisResult { serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into()) } diff --git a/src/engine/strat_engine/pool/v2.rs b/src/engine/strat_engine/pool/v2.rs index 602a989f6b..b9fc9fc004 100644 --- a/src/engine/strat_engine/pool/v2.rs +++ b/src/engine/strat_engine/pool/v2.rs @@ -40,7 +40,7 @@ use crate::{ ActionAvailability, BlockDevTier, Clevis, Compare, CreateAction, DeleteAction, DevUuid, Diff, EncryptedDevice, EncryptionInfo, FilesystemUuid, GrowAction, InputEncryptionInfo, Key, KeyDescription, Name, OffsetDirection, OptionalTokenSlotInput, PoolDiff, - PoolEncryptionInfo, PoolUuid, PropChangeAction, RegenAction, RenameAction, + PoolEncryptionInfo, PoolUuid, PropChangeAction, Reencrypt, RegenAction, RenameAction, SetCreateAction, SetDeleteAction, SizedKeyMemory, StratFilesystemDiff, StratPoolDiff, StratSigblockVersion, TokenUnlockMethod, ValidatedIntegritySpec, }, @@ -1199,6 +1199,14 @@ impl Pool for StratPool { } } + #[pool_mutating_action("NoRequests")] + fn reencrypt_pool(&mut self) -> StratisResult { + self.thin_pool.suspend()?; + let encrypt_res = self.backstore.reencrypt(); + self.thin_pool.resume()?; + encrypt_res.map(|_| Reencrypt) + } + fn current_metadata(&self, pool_name: &Name) -> StratisResult { serde_json::to_string(&self.record(pool_name)).map_err(|e| e.into()) } diff --git a/src/engine/types/actions.rs b/src/engine/types/actions.rs index a4ea0ff733..d7e73bb18d 100644 --- a/src/engine/types/actions.rs +++ b/src/engine/types/actions.rs @@ -851,3 +851,12 @@ impl EngineAction for PropChangeAction { } } } + +/// Return value indicating a successful reencrypt operation on the pool +pub struct Reencrypt; + +impl Display for Reencrypt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Reencryption operation was completed successfully") + } +} diff --git a/src/engine/types/mod.rs b/src/engine/types/mod.rs index 18a7f2d55a..f7a53919ee 100644 --- a/src/engine/types/mod.rs +++ b/src/engine/types/mod.rs @@ -28,7 +28,7 @@ pub use crate::{ types::{ actions::{ Clevis, CreateAction, DeleteAction, EncryptedDevice, EngineAction, GrowAction, Key, - MappingCreateAction, MappingDeleteAction, PropChangeAction, RegenAction, + MappingCreateAction, MappingDeleteAction, PropChangeAction, Reencrypt, RegenAction, RenameAction, SetCreateAction, SetDeleteAction, SetUnlockAction, StartAction, StopAction, ToDisplay, },