Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions quickwit/quickwit-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,14 +230,25 @@ pub fn start_actor_runtimes(
}

/// Loads a node config located at `config_uri` with the default storage configuration.
async fn load_node_config(config_uri: &Uri) -> anyhow::Result<NodeConfig> {
///
/// When `service_override` is provided, it is applied before config validation so that
/// service-dependent validation reflects the actual runtime service set (e.g. `--service
/// searcher`).
async fn load_node_config(
config_uri: &Uri,
service_override: Option<&HashSet<QuickwitService>>,
) -> anyhow::Result<NodeConfig> {
let config_content = load_file(&StorageResolver::unconfigured(), config_uri)
.await
.context("failed to load node config")?;
let config_format = ConfigFormat::sniff_from_uri(config_uri)?;
let config = NodeConfig::load(config_format, config_content.as_slice())
.await
.with_context(|| format!("failed to parse node config `{config_uri}`"))?;
let config = NodeConfig::load_with_service_override(
config_format,
config_content.as_slice(),
service_override,
)
.await
.with_context(|| format!("failed to parse node config `{config_uri}`"))?;
info!(config_uri=%config_uri, config=?config, "loaded node config");
Ok(config)
}
Expand Down
45 changes: 39 additions & 6 deletions quickwit/quickwit-cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use futures::future::select;
use itertools::Itertools;
use quickwit_common::runtimes::RuntimesConfig;
use quickwit_common::uri::Uri;
use quickwit_config::NodeConfig;
use quickwit_config::service::QuickwitService;
use quickwit_serve::tcp_listener::DefaultTcpListenerResolver;
use quickwit_serve::{BuildInfo, EnvFilterReloadFn, reload_tls_cert, serve_quickwit};
Expand Down Expand Up @@ -92,6 +93,10 @@ async fn listen_sighup() {
}

impl RunCliCommand {
async fn load_node_config(&self) -> anyhow::Result<NodeConfig> {
load_node_config(&self.config_uri, self.services.as_ref()).await
}

pub fn parse_cli_args(mut matches: ArgMatches) -> anyhow::Result<Self> {
let config_uri = matches
.remove_one::<String>("config")
Expand All @@ -117,15 +122,13 @@ impl RunCliCommand {
debug!(args = ?self, "run-service");
let version_text = BuildInfo::get_version_text();
info!("quickwit version: {version_text}");
let mut node_config = load_node_config(&self.config_uri).await?;
let node_config = self.load_node_config().await?;
if let Some(services) = &self.services {
info!(services = %services.iter().join(", "), "services set from CLI override");
}
let (storage_resolver, metastore_resolver) =
get_resolvers(&node_config.storage_configs, &node_config.metastore_configs);
crate::busy_detector::set_enabled(true);

if let Some(services) = &self.services {
info!(services = %services.iter().join(", "), "setting services from override");
node_config.enabled_services.clone_from(services);
}
// TODO move in serve quickwit?
let runtimes_config = RuntimesConfig::default();
start_actor_runtimes(runtimes_config, &node_config.enabled_services)?;
Expand All @@ -152,9 +155,39 @@ impl RunCliCommand {
#[cfg(test)]
mod tests {

use tempfile::tempdir;

use super::*;
use crate::cli::{CliCommand, build_cli};

#[tokio::test]
async fn test_run_command_forwards_service_override_before_validation() -> anyhow::Result<()> {
let temp_dir = tempdir()?;
let config_path = temp_dir.path().join("quickwit.yaml");
let config = format!(
r#"
version: 0.8
data_dir: "{}"
enabled_services:
- compactor
"#,
temp_dir.path().display()
);
std::fs::write(&config_path, config)?;
let run_command = RunCliCommand {
config_uri: Uri::from_str(&format!("file://{}", config_path.display()))?,
services: Some(HashSet::from([QuickwitService::Searcher])),
};

let node_config = run_command.load_node_config().await?;

assert_eq!(
node_config.enabled_services,
HashSet::from([QuickwitService::Searcher])
);
Ok(())
}

#[test]
fn test_parse_service_run_args_all_services() -> anyhow::Result<()> {
let command = build_cli().no_binary_name(true);
Expand Down
10 changes: 5 additions & 5 deletions quickwit/quickwit-cli/src/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ pub async fn local_ingest_docs_cli(args: LocalIngestDocsArgs) -> anyhow::Result<
debug!(args=?args, "local-ingest-docs");
println!("❯ Ingesting documents locally...");

let config = load_node_config(&args.config_uri).await?;
let config = load_node_config(&args.config_uri, None).await?;
let (storage_resolver, metastore_resolver) =
get_resolvers(&config.storage_configs, &config.metastore_configs);
let mut metastore = metastore_resolver.resolve(&config.metastore_uri).await?;
Expand Down Expand Up @@ -536,7 +536,7 @@ pub async fn local_ingest_docs_cli(args: LocalIngestDocsArgs) -> anyhow::Result<
pub async fn local_search_cli(args: LocalSearchArgs) -> anyhow::Result<()> {
debug!(args=?args, "local-search");
println!("❯ Searching directly on the index storage (without calling REST API)...");
let config = load_node_config(&args.config_uri).await?;
let config = load_node_config(&args.config_uri, None).await?;
let (storage_resolver, metastore_resolver) =
get_resolvers(&config.storage_configs, &config.metastore_configs);
let metastore: MetastoreServiceClient =
Expand Down Expand Up @@ -574,7 +574,7 @@ pub async fn local_search_cli(args: LocalSearchArgs) -> anyhow::Result<()> {
pub async fn merge_cli(args: MergeArgs) -> anyhow::Result<()> {
debug!(args=?args, "run-merge-operations");
println!("❯ Merging splits locally...");
let config = load_node_config(&args.config_uri).await?;
let config = load_node_config(&args.config_uri, None).await?;
let (storage_resolver, metastore_resolver) =
get_resolvers(&config.storage_configs, &config.metastore_configs);
let mut metastore = metastore_resolver.resolve(&config.metastore_uri).await?;
Expand Down Expand Up @@ -662,7 +662,7 @@ pub async fn garbage_collect_index_cli(args: GarbageCollectIndexArgs) -> anyhow:
debug!(args=?args, "garbage-collect-index");
println!("❯ Garbage collecting index...");

let config = load_node_config(&args.config_uri).await?;
let config = load_node_config(&args.config_uri, None).await?;
let (storage_resolver, metastore_resolver) =
get_resolvers(&config.storage_configs, &config.metastore_configs);
let metastore = metastore_resolver.resolve(&config.metastore_uri).await?;
Expand Down Expand Up @@ -792,7 +792,7 @@ async fn extract_split_cli(args: ExtractSplitArgs) -> anyhow::Result<()> {
debug!(args=?args, "extract-split");
println!("❯ Extracting split...");

let config = load_node_config(&args.config_uri).await?;
let config = load_node_config(&args.config_uri, None).await?;
let (storage_resolver, metastore_resolver) =
get_resolvers(&config.storage_configs, &config.metastore_configs);
let metastore = metastore_resolver.resolve(&config.metastore_uri).await?;
Expand Down
6 changes: 4 additions & 2 deletions quickwit/quickwit-cli/tests/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use quickwit_cli::service::RunCliCommand;
use quickwit_common::net::find_available_tcp_port;
use quickwit_common::test_utils::wait_for_server_ready;
use quickwit_common::uri::Uri;
use quickwit_config::service::QuickwitService;
use quickwit_metastore::{IndexMetadata, IndexMetadataResponseExt, MetastoreResolver};
use quickwit_proto::metastore::{IndexMetadataRequest, MetastoreService, MetastoreServiceClient};
use quickwit_proto::types::IndexId;
Expand Down Expand Up @@ -155,9 +154,12 @@ impl TestEnv {
}

pub async fn start_server(&self) -> anyhow::Result<()> {
// Use the default all-in-one service set, which excludes the standalone compactor.
// `QuickwitService::supported_services()` includes the compactor and would make this
// config invalid unless `enable_standalone_compactors` was explicitly enabled.
let run_command = RunCliCommand {
config_uri: self.resource_files.config.clone(),
services: Some(QuickwitService::supported_services()),
services: None,
};
let server_handle = tokio::spawn(async move {
if let Err(error) = run_command
Expand Down
23 changes: 19 additions & 4 deletions quickwit/quickwit-common/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,20 @@ pub fn get_cache_directory_path(data_dir_path: &Path) -> PathBuf {
data_dir_path.join("indexer-split-cache").join("splits")
}

/// Get the total size of the disk containing the given directory, or `None` if
/// it couldn't be determined.
pub fn get_disk_size(dir_path: &Path) -> Option<ByteSize> {
/// Information about the disk containing a directory.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DiskInfo {
/// Name reported by the operating system for the backing device.
pub device_name: String,
/// Canonical mount point of the backing device.
pub mount_point: PathBuf,
/// Total capacity of the backing device.
pub total_space: ByteSize,
}

/// Returns information about the disk containing the given directory, or `None` if it couldn't be
/// determined.
pub fn get_disk_info(dir_path: &Path) -> Option<DiskInfo> {
let disks = sysinfo::Disks::new_with_refreshed_list_specifics(
DiskRefreshKind::nothing().with_storage(),
);
Expand All @@ -65,7 +76,11 @@ pub fn get_disk_size(dir_path: &Path) -> Option<ByteSize> {
return None;
}
}
best_match.map(|(disk, _)| ByteSize::b(disk.total_space()))
best_match.map(|(disk, mount_point)| DiskInfo {
device_name: disk.name().to_string_lossy().into_owned(),
mount_point,
total_space: ByteSize::b(disk.total_space()),
})
}

#[cfg(test)]
Expand Down
15 changes: 14 additions & 1 deletion quickwit/quickwit-config/src/node_config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -911,8 +911,21 @@ impl NodeConfig {

/// Parses and validates a [`NodeConfig`] from a given URI and config content.
pub async fn load(config_format: ConfigFormat, config_content: &[u8]) -> anyhow::Result<Self> {
Self::load_with_service_override(config_format, config_content, None).await
}

/// Parses and validates a [`NodeConfig`], applying `service_override` before validation so
/// service-dependent validation uses the actual runtime service set rather than the
/// pre-override default (e.g. when `--service searcher` is passed via the CLI).
pub async fn load_with_service_override(
config_format: ConfigFormat,
config_content: &[u8],
service_override: Option<&HashSet<QuickwitService>>,
) -> anyhow::Result<Self> {
let env_vars = env::vars().collect::<HashMap<_, _>>();
let config = load_node_config_with_env(config_format, config_content, &env_vars).await?;
let config =
load_node_config_with_env(config_format, config_content, service_override, &env_vars)
.await?;
if !config.data_dir_path.try_exists()? {
bail!(
"data dir `{}` does not exist",
Expand Down
Loading
Loading