This is an automated email from the ASF dual-hosted git repository.
hgruszecki pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/master by this push:
new 4107de263 feat(bench): add --username/--password and reuse admin
client (#2778)
4107de263 is described below
commit 4107de263aafc5f19d2b5debbc8a9e68c7483115
Author: Hubert Gruszecki <[email protected]>
AuthorDate: Thu Feb 19 10:18:07 2026 +0100
feat(bench): add --username/--password and reuse admin client (#2778)
Authentication was hardcoded to default root credentials and
post-benchmark operations created throwaway clients. Propagate
-u/-p credentials through ClientFactory, reuse a single admin
client in the runner. Reassign -p from --messages-per-batch
(now -P) to --password for iggy CLI compatibility.
---
.../bench/src/actors/consumer/client/high_level.rs | 9 ++-
core/bench/src/actors/consumer/client/low_level.rs | 9 ++-
.../bench/src/actors/producer/client/high_level.rs | 9 ++-
core/bench/src/actors/producer/client/low_level.rs | 9 ++-
core/bench/src/analytics/report_builder.rs | 8 +--
core/bench/src/args/common.rs | 23 +++++++-
core/bench/src/args/examples.rs | 11 +++-
core/bench/src/benchmarks/benchmark.rs | 16 +++++-
core/bench/src/benchmarks/common.rs | 9 ++-
core/bench/src/runner.rs | 21 ++++---
core/bench/src/utils/client_factory.rs | 65 +++++++++++++++++++---
core/bench/src/utils/mod.rs | 24 ++------
12 files changed, 157 insertions(+), 56 deletions(-)
diff --git a/core/bench/src/actors/consumer/client/high_level.rs
b/core/bench/src/actors/consumer/client/high_level.rs
index 22b04679f..d2a63425a 100644
--- a/core/bench/src/actors/consumer/client/high_level.rs
+++ b/core/bench/src/actors/consumer/client/high_level.rs
@@ -24,7 +24,7 @@ use crate::actors::{
},
};
-use crate::utils::{ClientFactory, login_root};
+use crate::utils::{ClientFactory, authenticate};
use futures_util::StreamExt;
use iggy::prelude::*;
use std::{sync::Arc, time::Duration};
@@ -104,7 +104,12 @@ impl BenchmarkInit for HighLevelConsumerClient {
let topic_id_str = "topic-1";
let client = self.client_factory.create_client().await;
let client = IggyClient::create(client, None, None);
- login_root(&client).await;
+ authenticate(
+ &client,
+ self.client_factory.username(),
+ self.client_factory.password(),
+ )
+ .await;
let stream_id_str = self.config.stream_id.clone();
diff --git a/core/bench/src/actors/consumer/client/low_level.rs
b/core/bench/src/actors/consumer/client/low_level.rs
index b501942a0..0e4bf1358 100644
--- a/core/bench/src/actors/consumer/client/low_level.rs
+++ b/core/bench/src/actors/consumer/client/low_level.rs
@@ -20,7 +20,7 @@ use crate::actors::consumer::client::BenchmarkConsumerClient;
use crate::actors::consumer::client::interface::{BenchmarkConsumerConfig,
ConsumerClient};
use crate::actors::{ApiLabel, BatchMetrics, BenchmarkInit};
use crate::benchmarks::common::create_consumer;
-use crate::utils::{ClientFactory, login_root};
+use crate::utils::{ClientFactory, authenticate};
use crate::utils::{batch_total_size_bytes, batch_user_size_bytes};
use iggy::prelude::*;
use std::sync::Arc;
@@ -121,7 +121,12 @@ impl BenchmarkInit for LowLevelConsumerClient {
let client = self.client_factory.create_client().await;
let client = IggyClient::create(client, None, None);
- login_root(&client).await;
+ authenticate(
+ &client,
+ self.client_factory.username(),
+ self.client_factory.password(),
+ )
+ .await;
let stream_id: Identifier =
self.config.stream_id.as_str().try_into().unwrap();
let topic_id = topic_id_str.try_into().unwrap();
diff --git a/core/bench/src/actors/producer/client/high_level.rs
b/core/bench/src/actors/producer/client/high_level.rs
index 7fdf923b1..c532518f1 100644
--- a/core/bench/src/actors/producer/client/high_level.rs
+++ b/core/bench/src/actors/producer/client/high_level.rs
@@ -16,7 +16,7 @@
* under the License.
*/
-use crate::utils::{ClientFactory, login_root};
+use crate::utils::{ClientFactory, authenticate};
use crate::{
actors::{
ApiLabel, BatchMetrics, BenchmarkInit,
@@ -84,7 +84,12 @@ impl BenchmarkInit for HighLevelProducerClient {
let client = self.client_factory.create_client().await;
let client = IggyClient::create(client, None, None);
- login_root(&client).await;
+ authenticate(
+ &client,
+ self.client_factory.username(),
+ self.client_factory.password(),
+ )
+ .await;
let stream_id_str = self.config.stream_id.clone();
diff --git a/core/bench/src/actors/producer/client/low_level.rs
b/core/bench/src/actors/producer/client/low_level.rs
index b132f9a97..d2f9e07f5 100644
--- a/core/bench/src/actors/producer/client/low_level.rs
+++ b/core/bench/src/actors/producer/client/low_level.rs
@@ -18,7 +18,7 @@
use std::sync::Arc;
-use crate::utils::{ClientFactory, login_root};
+use crate::utils::{ClientFactory, authenticate};
use crate::{
actors::{
ApiLabel, BatchMetrics, BenchmarkInit,
@@ -92,7 +92,12 @@ impl BenchmarkInit for LowLevelProducerClient {
let client = self.client_factory.create_client().await;
let client = IggyClient::create(client, None, None);
- login_root(&client).await;
+ authenticate(
+ &client,
+ self.client_factory.username(),
+ self.client_factory.password(),
+ )
+ .await;
let partitioning = match partitions {
0 => panic!("Partition count must be greater than 0"),
diff --git a/core/bench/src/analytics/report_builder.rs
b/core/bench/src/analytics/report_builder.rs
index 2ec001091..48383f95d 100644
--- a/core/bench/src/analytics/report_builder.rs
+++ b/core/bench/src/analytics/report_builder.rs
@@ -19,7 +19,6 @@
use std::{collections::HashMap, thread};
use super::metrics::group::{from_individual_metrics,
from_producers_and_consumers_statistics};
-use crate::utils::ClientFactory;
use crate::utils::get_server_stats;
use bench_report::{
actor_kind::ActorKind,
@@ -31,8 +30,7 @@ use bench_report::{
server_stats::{BenchmarkCacheMetrics, BenchmarkCacheMetricsKey,
BenchmarkServerStats},
};
use chrono::{DateTime, Utc};
-use iggy::prelude::{CacheMetrics, CacheMetricsKey, IggyTimestamp, Stats};
-use std::sync::Arc;
+use iggy::prelude::{CacheMetrics, CacheMetricsKey, IggyClient, IggyTimestamp,
Stats};
pub struct BenchmarkReportBuilder;
@@ -43,7 +41,7 @@ impl BenchmarkReportBuilder {
mut params: BenchmarkParams,
mut individual_metrics: Vec<BenchmarkIndividualMetrics>,
moving_average_window: u32,
- client_factory: &Arc<dyn ClientFactory>,
+ admin_client: &IggyClient,
) -> BenchmarkReport {
let uuid = uuid::Uuid::new_v4();
@@ -51,7 +49,7 @@ impl BenchmarkReportBuilder {
DateTime::<Utc>::from_timestamp_micros(IggyTimestamp::now().as_micros() as i64)
.map_or_else(|| String::from("unknown"), |dt| dt.to_rfc3339());
- let server_stats = get_server_stats(client_factory)
+ let server_stats = get_server_stats(admin_client)
.await
.expect("Failed to get server stats");
diff --git a/core/bench/src/args/common.rs b/core/bench/src/args/common.rs
index be983c209..8c1c535a5 100644
--- a/core/bench/src/args/common.rs
+++ b/core/bench/src/args/common.rs
@@ -30,7 +30,10 @@ use bench_report::benchmark_kind::BenchmarkKind;
use bench_report::numeric_parameter::BenchmarkNumericParameter;
use clap::error::ErrorKind;
use clap::{CommandFactory, Parser};
-use iggy::prelude::{IggyByteSize, IggyDuration, IggyExpiry, TransportProtocol};
+use iggy::prelude::{
+ DEFAULT_ROOT_PASSWORD, DEFAULT_ROOT_USERNAME, IggyByteSize, IggyDuration,
IggyExpiry,
+ TransportProtocol,
+};
use std::num::NonZeroU32;
use std::str::FromStr;
@@ -47,7 +50,7 @@ pub struct IggyBenchArgs {
pub message_size: BenchmarkNumericParameter,
/// Number of messages per batch
- #[arg(long, short = 'p', value_parser =
BenchmarkNumericParameter::from_str, default_value_t =
BenchmarkNumericParameter::Value(DEFAULT_MESSAGES_PER_BATCH.get()))]
+ #[arg(long, short = 'P', value_parser =
BenchmarkNumericParameter::from_str, default_value_t =
BenchmarkNumericParameter::Value(DEFAULT_MESSAGES_PER_BATCH.get()))]
pub messages_per_batch: BenchmarkNumericParameter,
/// Number of message batches per actor (producer / consumer / producing
consumer).
@@ -80,6 +83,14 @@ pub struct IggyBenchArgs {
/// Use high-level API for actors
#[arg(long, short = 'H', default_value_t = false)]
pub high_level_api: bool,
+
+ /// Username for server authentication
+ #[arg(long, short = 'u', default_value_t =
DEFAULT_ROOT_USERNAME.to_string())]
+ pub username: String,
+
+ /// Password for server authentication
+ #[arg(long, short = 'p', default_value_t =
DEFAULT_ROOT_PASSWORD.to_string())]
+ pub password: String,
}
impl IggyBenchArgs {
@@ -303,6 +314,14 @@ impl IggyBenchArgs {
self.high_level_api
}
+ pub fn username(&self) -> &str {
+ &self.username
+ }
+
+ pub fn password(&self) -> &str {
+ &self.password
+ }
+
/// Generates the output directory name based on benchmark parameters.
pub fn generate_dir_name(&self) -> String {
let benchmark_kind = match &self.benchmark_kind {
diff --git a/core/bench/src/args/examples.rs b/core/bench/src/args/examples.rs
index 95cb9f9d9..40c63ced3 100644
--- a/core/bench/src/args/examples.rs
+++ b/core/bench/src/args/examples.rs
@@ -50,7 +50,7 @@ const EXAMPLES: &str = r#"EXAMPLES:
You can customize various parameters for any benchmark mode:
Global options (before the benchmark command):
- --messages-per-batch (-p): Number of messages per batch [default: 1000]
+ --messages-per-batch (-P): Number of messages per batch [default: 1000]
For random batch sizes, use range format:
"100..1000"
--message-batches (-b): Total number of batches [default: 1000]
--total-messages-size (-T): Total size of messages to send (e.g., "1GB",
"500MB")
@@ -61,6 +61,8 @@ const EXAMPLES: &str = r#"EXAMPLES:
--warmup-time (-w): Warmup duration [default: 0s]
--sampling-time (-t): Metrics sampling interval [default: 10ms]
--moving-average-window (-W): Window size for moving average [default: 20]
+ --username (-u): Username for server authentication [default: iggy]
+ --password (-p): Password for server authentication [default: iggy]
Benchmark-specific options (after the benchmark command):
--streams (-s): Number of streams
@@ -122,6 +124,13 @@ const EXAMPLES: &str = r#"EXAMPLES:
--streams 5 --producers 5 \
tcp --server-address 192.168.1.100:8090
+ With custom credentials:
+
+ $ cargo r -r --bin iggy-bench -- \
+ --username admin --password secret \
+ pinned-producer --streams 5 --producers 5 \
+ tcp --server-address 192.168.1.100:8090
+
6) Output Data and Results:
The benchmark tool can store detailed results for analysis and comparison:
diff --git a/core/bench/src/benchmarks/benchmark.rs
b/core/bench/src/benchmarks/benchmark.rs
index 594a00101..7a00c6528 100644
--- a/core/bench/src/benchmarks/benchmark.rs
+++ b/core/bench/src/benchmarks/benchmark.rs
@@ -17,7 +17,7 @@
*/
use crate::args::kind::BenchmarkKindCommand;
-use crate::utils::{ClientFactory, login_root};
+use crate::utils::{ClientFactory, authenticate};
use crate::{args::common::IggyBenchArgs,
utils::client_factory::create_client_factory};
use async_trait::async_trait;
use bench_report::benchmark_kind::BenchmarkKind;
@@ -99,7 +99,12 @@ pub trait Benchmarkable: Send {
let partitions_count: u32 = self.args().number_of_partitions();
let client = self.client_factory().create_client().await;
let client = IggyClient::create(client, None, None);
- login_root(&client).await;
+ authenticate(
+ &client,
+ self.client_factory().username(),
+ self.client_factory().password(),
+ )
+ .await;
let streams = client.get_streams().await?;
for i in 1..=number_of_streams {
let stream_name = format!("bench-stream-{i}");
@@ -139,7 +144,12 @@ pub trait Benchmarkable: Send {
let number_of_streams = self.args().streams();
let client = self.client_factory().create_client().await;
let client = IggyClient::create(client, None, None);
- login_root(&client).await;
+ authenticate(
+ &client,
+ self.client_factory().username(),
+ self.client_factory().password(),
+ )
+ .await;
let streams = client.get_streams().await?;
for i in 1..=number_of_streams {
let stream_name = format!("bench-stream-{i}");
diff --git a/core/bench/src/benchmarks/common.rs
b/core/bench/src/benchmarks/common.rs
index 7858f6fca..69a20cc62 100644
--- a/core/bench/src/benchmarks/common.rs
+++ b/core/bench/src/benchmarks/common.rs
@@ -17,7 +17,7 @@
*/
use super::{CONSUMER_GROUP_BASE_ID, CONSUMER_GROUP_NAME_PREFIX};
-use crate::utils::{ClientFactory, login_root};
+use crate::utils::{ClientFactory, authenticate};
use crate::{
actors::{
consumer::typed_benchmark_consumer::TypedBenchmarkConsumer,
@@ -76,7 +76,12 @@ pub async fn init_consumer_groups(
let client = IggyClient::create(client, None, None);
let cg_count = args.number_of_consumer_groups();
- login_root(&client).await;
+ authenticate(
+ &client,
+ client_factory.username(),
+ client_factory.password(),
+ )
+ .await;
for i in 1..=cg_count {
let consumer_group_id = CONSUMER_GROUP_BASE_ID + i;
let stream_name = format!("bench-stream-{i}");
diff --git a/core/bench/src/runner.rs b/core/bench/src/runner.rs
index d9007bfd7..40daf2bf1 100644
--- a/core/bench/src/runner.rs
+++ b/core/bench/src/runner.rs
@@ -23,7 +23,7 @@ use crate::plot::{ChartType, plot_chart};
use crate::utils::cpu_name::append_cpu_name_lowercase;
use crate::utils::{collect_server_logs_and_save_to_file,
params_from_args_and_metrics};
use bench_report::hardware::BenchmarkHardware;
-use iggy::prelude::IggyError;
+use iggy::prelude::{Client, IggyClient, IggyError, UserClient};
use std::path::Path;
use std::time::Duration;
use tokio::time::sleep;
@@ -62,6 +62,15 @@ impl BenchmarkRunner {
}
info!("All actors joined!");
+
+ let client_factory = benchmark.client_factory();
+ let admin_client_wrapper = client_factory.create_client().await;
+ let admin_client = IggyClient::create(admin_client_wrapper, None,
None);
+ admin_client.connect().await?;
+ admin_client
+ .login_user(client_factory.username(), client_factory.password())
+ .await?;
+
let hardware =
BenchmarkHardware::get_system_info_with_identifier(benchmark.args().identifier());
let params = params_from_args_and_metrics(benchmark.args(),
&individual_metrics);
@@ -71,7 +80,7 @@ impl BenchmarkRunner {
params,
individual_metrics,
benchmark.args().moving_average_window(),
- benchmark.client_factory(),
+ &admin_client,
)
.await;
@@ -92,11 +101,9 @@ impl BenchmarkRunner {
// Dump the report to JSON
report.dump_to_json(&full_output_path);
- if let Err(e) = collect_server_logs_and_save_to_file(
- benchmark.client_factory(),
- Path::new(&full_output_path),
- )
- .await
+ if let Err(e) =
+ collect_server_logs_and_save_to_file(&admin_client,
Path::new(&full_output_path))
+ .await
{
error!("Failed to collect server logs: {e}");
}
diff --git a/core/bench/src/utils/client_factory.rs
b/core/bench/src/utils/client_factory.rs
index 3fda38d77..171c05240 100644
--- a/core/bench/src/utils/client_factory.rs
+++ b/core/bench/src/utils/client_factory.rs
@@ -21,9 +21,8 @@ use crate::args::transport::BenchmarkTransportCommand;
use async_trait::async_trait;
use iggy::http::http_client::HttpClient;
use iggy::prelude::{
- Client, ClientWrapper, DEFAULT_ROOT_PASSWORD, DEFAULT_ROOT_USERNAME,
HttpClientConfig,
- IdentityInfo, IggyClient, QuicClientConfig, TcpClient, TcpClientConfig,
TransportProtocol,
- UserClient, WebSocketClientConfig,
+ Client, ClientWrapper, HttpClientConfig, IdentityInfo, IggyClient,
QuicClientConfig, TcpClient,
+ TcpClientConfig, TransportProtocol, UserClient, WebSocketClientConfig,
};
use iggy::quic::quic_client::QuicClient;
use iggy::websocket::websocket_client::WebSocketClient;
@@ -34,18 +33,19 @@ pub trait ClientFactory: Sync + Send {
async fn create_client(&self) -> ClientWrapper;
fn transport(&self) -> TransportProtocol;
fn server_addr(&self) -> String;
+ fn username(&self) -> &str;
+ fn password(&self) -> &str;
}
-pub async fn login_root(client: &IggyClient) -> IdentityInfo {
- client
- .login_user(DEFAULT_ROOT_USERNAME, DEFAULT_ROOT_PASSWORD)
- .await
- .unwrap()
+pub async fn authenticate(client: &IggyClient, username: &str, password: &str)
-> IdentityInfo {
+ client.login_user(username, password).await.unwrap()
}
#[derive(Debug, Clone)]
pub struct HttpClientFactory {
pub server_addr: String,
+ pub username: String,
+ pub password: String,
}
#[async_trait]
@@ -66,6 +66,14 @@ impl ClientFactory for HttpClientFactory {
fn server_addr(&self) -> String {
self.server_addr.clone()
}
+
+ fn username(&self) -> &str {
+ &self.username
+ }
+
+ fn password(&self) -> &str {
+ &self.password
+ }
}
#[derive(Debug, Clone, Default)]
@@ -76,6 +84,8 @@ pub struct TcpClientFactory {
pub tls_domain: String,
pub tls_ca_file: Option<String>,
pub tls_validate_certificate: bool,
+ pub username: String,
+ pub password: String,
}
#[async_trait]
@@ -122,11 +132,21 @@ impl ClientFactory for TcpClientFactory {
fn server_addr(&self) -> String {
self.server_addr.clone()
}
+
+ fn username(&self) -> &str {
+ &self.username
+ }
+
+ fn password(&self) -> &str {
+ &self.password
+ }
}
#[derive(Debug, Clone)]
pub struct QuicClientFactory {
pub server_addr: String,
+ pub username: String,
+ pub password: String,
}
#[async_trait]
@@ -149,11 +169,21 @@ impl ClientFactory for QuicClientFactory {
fn server_addr(&self) -> String {
self.server_addr.clone()
}
+
+ fn username(&self) -> &str {
+ &self.username
+ }
+
+ fn password(&self) -> &str {
+ &self.password
+ }
}
#[derive(Debug, Clone)]
pub struct WebSocketClientFactory {
pub server_addr: String,
+ pub username: String,
+ pub password: String,
}
#[async_trait]
@@ -175,12 +205,25 @@ impl ClientFactory for WebSocketClientFactory {
fn server_addr(&self) -> String {
self.server_addr.clone()
}
+
+ fn username(&self) -> &str {
+ &self.username
+ }
+
+ fn password(&self) -> &str {
+ &self.password
+ }
}
pub fn create_client_factory(args: &IggyBenchArgs) -> Arc<dyn ClientFactory> {
+ let username = args.username().to_owned();
+ let password = args.password().to_owned();
+
match &args.transport() {
TransportProtocol::Http => Arc::new(HttpClientFactory {
server_addr: args.server_address().to_owned(),
+ username,
+ password,
}),
TransportProtocol::Tcp => {
let transport_command = args.transport_command();
@@ -192,6 +235,8 @@ pub fn create_client_factory(args: &IggyBenchArgs) ->
Arc<dyn ClientFactory> {
tls_domain: tcp_args.tls_domain.clone(),
tls_ca_file: tcp_args.tls_ca_file.clone(),
tls_validate_certificate:
tcp_args.tls_validate_certificate,
+ username,
+ password,
})
} else {
unreachable!("Transport is TCP but transport command is not
TcpArgs")
@@ -199,9 +244,13 @@ pub fn create_client_factory(args: &IggyBenchArgs) ->
Arc<dyn ClientFactory> {
}
TransportProtocol::Quic => Arc::new(QuicClientFactory {
server_addr: args.server_address().to_owned(),
+ username,
+ password,
}),
TransportProtocol::WebSocket => Arc::new(WebSocketClientFactory {
server_addr: args.server_address().to_owned(),
+ username,
+ password,
}),
}
}
diff --git a/core/bench/src/utils/mod.rs b/core/bench/src/utils/mod.rs
index e8ee8ebd3..82fdc9b3f 100644
--- a/core/bench/src/utils/mod.rs
+++ b/core/bench/src/utils/mod.rs
@@ -22,7 +22,7 @@ use bench_report::{
transport::BenchmarkTransport,
};
use iggy::prelude::*;
-use std::{fs, path::Path, sync::Arc};
+use std::{fs, path::Path};
use tracing::{error, info};
use crate::args::{
@@ -37,7 +37,7 @@ use crate::args::{
},
};
-pub use client_factory::{ClientFactory, login_root};
+pub use client_factory::{ClientFactory, authenticate};
pub mod batch_generator;
pub mod client_factory;
@@ -61,30 +61,14 @@ pub fn batch_user_size_bytes(polled_messages:
&PolledMessages) -> u64 {
.sum()
}
-pub async fn get_server_stats(client_factory: &Arc<dyn ClientFactory>) ->
Result<Stats, IggyError> {
- let client = client_factory.create_client().await;
- let client = IggyClient::create(client, None, None);
-
- client.connect().await?;
- client
- .login_user(DEFAULT_ROOT_USERNAME, DEFAULT_ROOT_PASSWORD)
- .await?;
-
+pub async fn get_server_stats(client: &IggyClient) -> Result<Stats, IggyError>
{
client.get_stats().await
}
pub async fn collect_server_logs_and_save_to_file(
- client_factory: &Arc<dyn ClientFactory>,
+ client: &IggyClient,
output_dir: &Path,
) -> Result<(), IggyError> {
- let client = client_factory.create_client().await;
- let client = IggyClient::create(client, None, None);
-
- client.connect().await?;
- client
- .login_user(DEFAULT_ROOT_USERNAME, DEFAULT_ROOT_PASSWORD)
- .await?;
-
let snapshot = client
.snapshot(
SnapshotCompression::Deflated,