Skip to content

Commit

Permalink
updated config load logic
Browse files Browse the repository at this point in the history
  • Loading branch information
jstuczyn committed Dec 4, 2023
1 parent b3927b9 commit bb9b3cd
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 27 deletions.
5 changes: 1 addition & 4 deletions tools/nymvisor/src/cli/add_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
56 changes: 49 additions & 7 deletions tools/nymvisor/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// 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;
Expand Down Expand Up @@ -77,12 +78,19 @@ pub(crate) enum Commands {
fn open_config_file(env: &Env) -> Result<Config, NymvisorError> {
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);
}
Expand All @@ -95,14 +103,48 @@ fn open_config_file(env: &Env) -> Result<Config, NymvisorError> {
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,
})
}
}
}

// 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<PathBuf, NymvisorError> {
let instances_dir = default_instances_directory();
let mut instances = instances_dir
.read_dir()
.map_err(|source| NymvisorError::InstancesReadFailure {
source,
path: instances_dir.clone(),
})?
.collect::<Vec<_>>();

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<Config, NymvisorError> {
let mut config = open_config_file(env)?;
env.override_config(&mut config);
Expand Down
12 changes: 9 additions & 3 deletions tools/nymvisor/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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/<id>/config`
pub fn default_config_directory<P: AsRef<Path>>(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/<id>/config`
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
default_instances_directory()
.join(id)
.join(DEFAULT_CONFIG_DIR)
}
Expand Down
10 changes: 0 additions & 10 deletions tools/nymvisor/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,6 @@ impl Env {
config.daemon.debug.unsafe_skip_backup = daemon_unsafe_skip_backup;
}
}

pub(crate) fn try_nymvisor_id(&self) -> Result<String, NymvisorError> {
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
Expand Down
13 changes: 10 additions & 3 deletions tools/nymvisor/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<ExitStatus> for NymvisorError {
Expand Down

0 comments on commit bb9b3cd

Please sign in to comment.