From bb9b3cdb648cb5232a4a9abcbc6c8c3fb639b183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 27 Nov 2023 16:48:36 +0000 Subject: [PATCH] updated config load logic --- tools/nymvisor/src/cli/add_upgrade.rs | 5 +-- tools/nymvisor/src/cli/mod.rs | 56 +++++++++++++++++++++++---- tools/nymvisor/src/config/mod.rs | 12 ++++-- tools/nymvisor/src/env.rs | 10 ----- tools/nymvisor/src/error.rs | 13 +++++-- 5 files changed, 69 insertions(+), 27 deletions(-) diff --git a/tools/nymvisor/src/cli/add_upgrade.rs b/tools/nymvisor/src/cli/add_upgrade.rs index 3504faf59f8..06e1717ebd6 100644 --- a/tools/nymvisor/src/cli/add_upgrade.rs +++ b/tools/nymvisor/src/cli/add_upgrade.rs @@ -77,15 +77,12 @@ impl Args { } pub(crate) fn execute(args: Args) -> Result<(), NymvisorError> { - let mut env = Env::try_read()?; + let env = Env::try_read()?; let tmp_daemon = Daemon::new(&args.daemon_binary); tmp_daemon.verify_binary()?; let bin_info = tmp_daemon.get_build_information()?; - if env.daemon_name.is_none() { - env.daemon_name = Some(bin_info.binary_name.clone()); - } let config = try_load_current_config(&env)?; let upgrade_info_path = config.upgrade_info_filepath(&args.upgrade_name); diff --git a/tools/nymvisor/src/cli/mod.rs b/tools/nymvisor/src/cli/mod.rs index bfe175739f2..f530b39fa88 100644 --- a/tools/nymvisor/src/cli/mod.rs +++ b/tools/nymvisor/src/cli/mod.rs @@ -1,14 +1,15 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::config::{default_config_filepath, Config}; +use crate::config::{default_config_filepath, default_instances_directory, Config}; use crate::env::{setup_env, Env}; use crate::error::NymvisorError; use clap::{Parser, Subcommand}; use lazy_static::lazy_static; use nym_bin_common::bin_info; -use std::path::Path; -use tracing::error; +use nym_config::{DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME}; +use std::path::{Path, PathBuf}; +use tracing::{debug, error}; mod add_upgrade; mod build_info; @@ -77,12 +78,19 @@ pub(crate) enum Commands { fn open_config_file(env: &Env) -> Result { let config_load_location = if let Some(config_path) = &env.nymvisor_config_path { config_path.clone() + } else if let Some(nymvisor_id) = &env.nymvisor_id { + // if no explicit path was provided in the environment, try to use the default one based on the nymvisor id + default_config_filepath(nymvisor_id) } else { - // if no explicit path was provided in the environment, try to infer it with other vars - let id = env.try_nymvisor_id()?; - default_config_filepath(id) + // finally, if all else fails, see if this is a singleton -> if so try to load the only instance + try_get_singleton_nymvisor_config_path()? }; + debug!( + "attempting to load configuration file from {}", + config_load_location.display() + ); + if let Ok(cfg) = Config::read_from_toml_file(&config_load_location) { return Ok(cfg); } @@ -95,7 +103,7 @@ fn open_config_file(env: &Env) -> Result { Err(source) => { error!("Failed to load config from {}. Are you sure you have run `init` before? (Error was: {source})", config_load_location.display()); Err(NymvisorError::ConfigLoadFailure { - id: env.try_nymvisor_id().unwrap_or_default(), + id: env.nymvisor_id.clone().unwrap_or("UNKNOWN".to_string()), path: config_load_location, source, }) @@ -103,6 +111,40 @@ fn open_config_file(env: &Env) -> Result { } } +// attempt to get a path to nymvisor's config path if there is only a single instance +pub(crate) fn try_get_singleton_nymvisor_config_path() -> Result { + let instances_dir = default_instances_directory(); + let mut instances = instances_dir + .read_dir() + .map_err(|source| NymvisorError::InstancesReadFailure { + source, + path: instances_dir.clone(), + })? + .collect::>(); + + if instances.len() != 1 { + return Err(NymvisorError::NotSingleton { + instances: instances.len(), + }); + } + + // safety: that unwrap is fine as we've just checked we have 1 entry in the vector + #[allow(clippy::unwrap_used)] + let instance_dir = instances + .pop() + .unwrap() + .map_err(|source| NymvisorError::InstancesReadFailure { + source, + path: instances_dir, + })? + .path(); + + // join the instance directory with `/config/config.toml` + Ok(instance_dir + .join(DEFAULT_CONFIG_DIR) + .join(DEFAULT_CONFIG_FILENAME)) +} + pub(crate) fn try_load_current_config(env: &Env) -> Result { let mut config = open_config_file(env)?; env.override_config(&mut config); diff --git a/tools/nymvisor/src/config/mod.rs b/tools/nymvisor/src/config/mod.rs index febea3a5bb5..cd907841b22 100644 --- a/tools/nymvisor/src/config/mod.rs +++ b/tools/nymvisor/src/config/mod.rs @@ -40,13 +40,19 @@ pub(crate) const UPGRADES_DIR: &str = "upgrades"; pub(crate) const DEFAULT_NYMVISORS_DIR: &str = "nymvisors"; pub(crate) const DEFAULT_NYMVISORS_INSTANCES_DIR: &str = "instances"; -/// Derive default path to the nymvisor's config directory. -/// It should get resolved to `$HOME/.nym/nymvisor/instances//config` -pub fn default_config_directory>(id: P) -> PathBuf { +/// Derive default path top the nymvisors instance directory. +/// It should get resolved to `$HOME/.nym/nymvisor/instances` +pub fn default_instances_directory() -> PathBuf { must_get_home() .join(NYM_DIR) .join(DEFAULT_NYMVISORS_DIR) .join(DEFAULT_NYMVISORS_INSTANCES_DIR) +} + +/// Derive default path to the nymvisor's config directory. +/// It should get resolved to `$HOME/.nym/nymvisor/instances//config` +pub fn default_config_directory>(id: P) -> PathBuf { + default_instances_directory() .join(id) .join(DEFAULT_CONFIG_DIR) } diff --git a/tools/nymvisor/src/env.rs b/tools/nymvisor/src/env.rs index e09ed071d41..24357e13ae2 100644 --- a/tools/nymvisor/src/env.rs +++ b/tools/nymvisor/src/env.rs @@ -123,16 +123,6 @@ impl Env { config.daemon.debug.unsafe_skip_backup = daemon_unsafe_skip_backup; } } - - pub(crate) fn try_nymvisor_id(&self) -> Result { - if let Some(nymvisor_id) = &self.nymvisor_id { - Ok(nymvisor_id.clone()) - } else if let Some(daemon_name) = &self.daemon_name { - Ok(Config::default_id(daemon_name)) - } else { - Err(NymvisorError::UnknownNymvisorInstance) - } - } } // TODO: all of those seem like they could be moved to some common crate if we ever needed similar functionality elsewhere diff --git a/tools/nymvisor/src/error.rs b/tools/nymvisor/src/error.rs index 75da67ee05c..99c85598f48 100644 --- a/tools/nymvisor/src/error.rs +++ b/tools/nymvisor/src/error.rs @@ -282,9 +282,6 @@ While the stored info point to:\n{stored_info:#?}" #[error("the value of daemon home has to be provided by either `--daemon-home` flag or `$DAEMON_HOME` environmental variable")] DaemonHomeUnavailable, - #[error("could not identify nymvisor instance. please specify either $NYMVISOR_CONFIG_PATH, $NYMVISOR_ID or $DAEMON_NAME")] - UnknownNymvisorInstance, - #[error("failed to obtain build information from the daemon executable ('{}'): {source}", binary_path.display())] DaemonBuildInformationFailure { binary_path: PathBuf, @@ -409,6 +406,16 @@ While the stored info point to:\n{stored_info:#?}" #[error("the daemon restart on failure is disabled")] DisabledRestartOnFailure, + + #[error("failed to read directory content of nymvisor instances at {}: {source}", path.display())] + InstancesReadFailure { + path: PathBuf, + #[source] + source: io::Error, + }, + + #[error("could not load the default config file as there isn't a single nymvisor instance initiated (there are {instances}). please specify either $NYMVISOR_CONFIG_PATH or $NYMVISOR_ID")] + NotSingleton { instances: usize }, } impl From for NymvisorError {