From 12f297e5261863b099243a6e011d5bac89f2e4f1 Mon Sep 17 00:00:00 2001 From: Sebastiano Tocci Date: Sat, 3 Aug 2024 02:37:49 +0200 Subject: [PATCH] Added orca flag to extend privileged authentication expiry (#2949) --- tools/orca/src/generate.rs | 7 ++++-- tools/orca/src/kani.rs | 18 +++++++++++++++ tools/orca/src/main.rs | 2 ++ tools/orca/src/model.rs | 1 + tools/orca/src/opt.rs | 4 ++++ tools/orca/src/populate.rs | 1 + tools/orca/src/profile.rs | 11 +++++++++ tools/orca/src/run.rs | 10 ++++++--- tools/orca/src/state.rs | 1 + tools/orca/src/stats.rs | 46 ++++++++++++++++++++++++++++++++++---- 10 files changed, 92 insertions(+), 9 deletions(-) diff --git a/tools/orca/src/generate.rs b/tools/orca/src/generate.rs index 3ed97204a..afd779ff2 100644 --- a/tools/orca/src/generate.rs +++ b/tools/orca/src/generate.rs @@ -53,8 +53,11 @@ pub async fn populate(_client: &KanidmOrcaClient, profile: Profile) -> Result Result<(), Error> { + self.idm_admin_client + .group_account_policy_privilege_expiry_set("idm_all_persons", 3600) + .await + .map_err(|err| { + error!(?err, "Unable to modify idm_all_persons policy"); + Error::KanidmClient + })?; + + self.idm_admin_client + .group_account_policy_privilege_expiry_set("idm_all_accounts", 3600) + .await + .map_err(|err| { + error!(?err, "Unable to modify idm_all_accounts policy"); + Error::KanidmClient + }) + } + pub async fn person_exists(&self, username: &str) -> Result { self.idm_admin_client .idm_person_account_get(username) diff --git a/tools/orca/src/main.rs b/tools/orca/src/main.rs index 174d37004..d38a68e8e 100644 --- a/tools/orca/src/main.rs +++ b/tools/orca/src/main.rs @@ -77,6 +77,7 @@ fn main() -> ExitCode { profile_path, threads, model, + dump_raw_data, } => { // For now I hardcoded some dimensions, but we should prompt // the user for these later. @@ -98,6 +99,7 @@ fn main() -> ExitCode { idm_admin_password, model, threads, + dump_raw_data, ) .seed(seed); diff --git a/tools/orca/src/model.rs b/tools/orca/src/model.rs index 96bdb783c..55c3e7990 100644 --- a/tools/orca/src/model.rs +++ b/tools/orca/src/model.rs @@ -32,6 +32,7 @@ impl Transition { } } +#[derive(Eq, PartialEq, Ord, PartialOrd)] pub enum TransitionResult { // Success Ok, diff --git a/tools/orca/src/opt.rs b/tools/orca/src/opt.rs index e813c0eca..41cce4f4b 100644 --- a/tools/orca/src/opt.rs +++ b/tools/orca/src/opt.rs @@ -70,6 +70,10 @@ pub enum OrcaOpt { #[clap(long, default_value_t, value_enum)] // Optional model to run the benchmark, defaults to the `Basic` model model: Model, + + #[clap(long, default_value_t)] + /// Dump raw data to a separate csv file, defaults to false + dump_raw_data: bool, }, #[clap(name = "conntest")] diff --git a/tools/orca/src/populate.rs b/tools/orca/src/populate.rs index 8f239f799..8a87240b7 100644 --- a/tools/orca/src/populate.rs +++ b/tools/orca/src/populate.rs @@ -12,6 +12,7 @@ async fn apply_flags(client: Arc, flags: &[Flag]) -> Res for flag in flags { match flag { Flag::DisableAllPersonsMFAPolicy => client.disable_mfa_requirement().await?, + Flag::ExtendPrivilegedAuthExpiry => client.extend_privilege_expiry().await?, } } Ok(()) diff --git a/tools/orca/src/profile.rs b/tools/orca/src/profile.rs index 01083e3ed..9b080d81d 100644 --- a/tools/orca/src/profile.rs +++ b/tools/orca/src/profile.rs @@ -36,6 +36,8 @@ pub struct Profile { thread_count: Option, model: Model, group: BTreeMap, + #[serde(default)] + dump_raw_data: bool, } impl Profile { @@ -91,6 +93,10 @@ impl Profile { pub fn test_time(&self) -> Option { self.test_time.map(Duration::from_secs) } + + pub fn dump_raw_data(&self) -> bool { + self.dump_raw_data + } } pub struct ProfileBuilder { @@ -106,6 +112,7 @@ pub struct ProfileBuilder { pub person_count: Option, pub thread_count: Option, pub model: Model, + pub dump_raw_data: bool, } fn validate_u64_bound(value: Option, default: u64) -> Result { @@ -129,6 +136,7 @@ impl ProfileBuilder { idm_admin_password: String, model: Model, thread_count: Option, + dump_raw_data: bool, ) -> Self { ProfileBuilder { control_uri, @@ -142,6 +150,7 @@ impl ProfileBuilder { person_count: None, thread_count, model, + dump_raw_data, } } @@ -187,6 +196,7 @@ impl ProfileBuilder { person_count, thread_count, model, + dump_raw_data, } = self; let seed: u64 = seed.unwrap_or_else(|| { @@ -224,6 +234,7 @@ impl ProfileBuilder { thread_count, group, model, + dump_raw_data, }) } } diff --git a/tools/orca/src/run.rs b/tools/orca/src/run.rs index da441139f..393e6981f 100644 --- a/tools/orca/src/run.rs +++ b/tools/orca/src/run.rs @@ -11,6 +11,7 @@ use crossbeam::queue::{ArrayQueue, SegQueue}; use kanidm_client::{KanidmClient, KanidmClientBuilder}; +use serde::Serialize; use tokio::sync::broadcast; use std::time::{Duration, Instant}; @@ -48,7 +49,7 @@ pub struct EventRecord { pub details: EventDetail, } -#[derive(Debug)] +#[derive(Debug, Serialize, Clone)] pub enum EventDetail { Login, Logout, @@ -145,8 +146,11 @@ pub async fn execute(state: State, control_rx: broadcast::Receiver) -> R let mut dyn_data_collector = BasicStatistics::new(state.persons.len(), state.groups.len(), node_count); - let stats_task = - tokio::task::spawn_blocking(move || dyn_data_collector.run(c_stats_queue, c_stats_ctrl)); + let dump_raw_data = state.profile.dump_raw_data(); + + let stats_task = tokio::task::spawn_blocking(move || { + dyn_data_collector.run(c_stats_queue, c_stats_ctrl, dump_raw_data) + }); // Create clients. Note, we actually seed these deterministically too, so that // or persons are spread over the clients that exist, in a way that is also diff --git a/tools/orca/src/state.rs b/tools/orca/src/state.rs index ba8dd1100..9fff187ef 100644 --- a/tools/orca/src/state.rs +++ b/tools/orca/src/state.rs @@ -58,6 +58,7 @@ impl TryFrom<&Path> for State { #[derive(Debug, Serialize, Deserialize)] pub enum Flag { DisableAllPersonsMFAPolicy, + ExtendPrivilegedAuthExpiry, } #[derive(Default, Debug, Serialize, Deserialize)] diff --git a/tools/orca/src/stats.rs b/tools/orca/src/stats.rs index 4557b5e12..2b7e39410 100644 --- a/tools/orca/src/stats.rs +++ b/tools/orca/src/stats.rs @@ -22,6 +22,7 @@ pub trait DataCollector { &mut self, stats_queue: Arc>, ctrl: Arc>, + dump_raw_data: bool, ) -> Result<(), Error>; } @@ -30,6 +31,7 @@ enum OpKind { ReadOp, ReplicationDelay, Auth, //TODO! does this make sense? + Error, } impl From for OpKind { @@ -42,11 +44,9 @@ impl From for OpKind { | EventDetail::PersonSetSelfPassword | EventDetail::PersonCreateGroup | EventDetail::PersonAddGroupMembers => OpKind::WriteOp, - EventDetail::Error - | EventDetail::Login - | EventDetail::Logout - | EventDetail::PersonReauth => OpKind::Auth, + EventDetail::Login | EventDetail::Logout | EventDetail::PersonReauth => OpKind::Auth, EventDetail::GroupReplicationDelay => OpKind::ReplicationDelay, + EventDetail::Error => OpKind::Error, } } } @@ -76,6 +76,7 @@ impl DataCollector for BasicStatistics { &mut self, stats_queue: Arc>, ctrl: Arc>, + dump_raw_data: bool, ) -> Result<(), Error> { debug!("Started statistics collector"); @@ -123,6 +124,7 @@ impl DataCollector for BasicStatistics { let mut readop_times = Vec::new(); let mut writeop_times = Vec::new(); let mut replication_delays = Vec::new(); + let mut raw_stats = Vec::new(); // We will drain this now. while let Some(event_record) = stats_queue.pop() { @@ -131,6 +133,13 @@ impl DataCollector for BasicStatistics { continue; } + if dump_raw_data { + raw_stats.push(SerializableEventRecord::from_event_record( + &event_record, + start, + )); + } + match OpKind::from(event_record.details) { OpKind::ReadOp => { readop_times.push(event_record.duration.as_secs_f64()); @@ -142,6 +151,7 @@ impl DataCollector for BasicStatistics { replication_delays.push(event_record.duration.as_secs_f64()) } OpKind::Auth => {} + OpKind::Error => {} } } @@ -196,12 +206,40 @@ impl DataCollector for BasicStatistics { let mut wrt = Writer::from_path(filepath).map_err(|_| Error::Io)?; wrt.serialize(stats).map_err(|_| Error::Io)?; + if dump_raw_data { + let raw_data_filepath = format!("orca-run-{}-raw.csv", now.to_rfc3339()); + info!("Now saving raw data as '{raw_data_filepath}'"); + + let mut wrt = Writer::from_path(raw_data_filepath).map_err(|_| Error::Io)?; + + for record in raw_stats.iter() { + wrt.serialize(record).map_err(|_| Error::Io)?; + } + } + debug!("Ended statistics collector"); Ok(()) } } +#[derive(Serialize)] +struct SerializableEventRecord { + time_from_start_ms: u128, + duration_ms: u128, + details: EventDetail, +} + +impl SerializableEventRecord { + fn from_event_record(event_record: &EventRecord, test_start: Instant) -> Self { + SerializableEventRecord { + time_from_start_ms: event_record.start.duration_since(test_start).as_millis(), + duration_ms: event_record.duration.as_millis(), + details: event_record.details.clone(), + } + } +} + #[derive(Serialize)] struct StatsContainer { node_count: usize,