From e853e8ffc1e02ae5ed9fbaed1103afe9965eae62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 6 Nov 2023 10:28:51 +0000 Subject: [PATCH] added upstream url to config --- tools/nymvisor/Cargo.toml | 1 + tools/nymvisor/src/cli/init.rs | 20 +++++++++++++ tools/nymvisor/src/config/mod.rs | 42 ++++++++++++++++++++++++--- tools/nymvisor/src/config/template.rs | 13 +++++++++ tools/nymvisor/src/env.rs | 28 ++++++++++++++++++ tools/nymvisor/src/error.rs | 8 +++++ 6 files changed, 108 insertions(+), 4 deletions(-) diff --git a/tools/nymvisor/Cargo.toml b/tools/nymvisor/Cargo.toml index 5ecc560c91..6ff660e071 100644 --- a/tools/nymvisor/Cargo.toml +++ b/tools/nymvisor/Cargo.toml @@ -24,6 +24,7 @@ serde_json = { workspace = true } tokio = { workspace = true, features = ["rt", "macros", "signal", "process", "sync"] } thiserror = { workspace = true } tracing = { workspace = true } +url = { workspace = true, features = ["serde"] } async-file-watcher = { path = "../../common/async-file-watcher" } nym-bin-common = { path = "../../common/bin-common", features = ["output_format", "basic_tracing"] } diff --git a/tools/nymvisor/src/cli/init.rs b/tools/nymvisor/src/cli/init.rs index cab2b9d8f7..df578f288f 100644 --- a/tools/nymvisor/src/cli/init.rs +++ b/tools/nymvisor/src/cli/init.rs @@ -12,6 +12,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::time::Duration; use tracing::{debug, error, info, trace, warn}; +use url::Url; #[derive(clap::Args, Debug)] pub(crate) struct Args { @@ -23,6 +24,12 @@ pub(crate) struct Args { #[arg(long)] id: Option, + /// Sets the base url of the upstream source for obtaining upgrade information for the deaemon. + /// It will be used fo constructing the full url, i.e. $NYMVISOR_UPSTREAM_BASE_UPGRADE_URL/$DAEMON_NAME/upgrade-info.json + /// Can be overridden with $NYMVISOR_UPSTREAM_BASE_UPGRADE_URL environmental variable. + #[arg(long)] + upstream_base_upgrade_url: Option, + /// If enabled, this will disable `nymvisor` logs (but not the underlying process) /// Can be overridden with $NYMVISOR_DISABLE_LOGS environmental variable. #[arg(long)] @@ -41,6 +48,13 @@ pub(crate) struct Args { #[arg(long)] daemon_home: Option, + /// Override url to the upstream source for upgrade plans for this daeamon. + /// The Url has to point to an endpoint containing a valid [`UpgradeInfo`] json. + /// Note: if set this takes precedence over `upstream_base_upgrade_url` + /// Can be overridden with $DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL environmental variable. + #[arg(long)] + daemon_absolute_upstream_upgrade_url: Option, + /// If set to true, this will enable auto-downloading of new binaries using the url provided in the `upgrade-info.json` /// Can be overridden with $DAEMON_ALLOW_BINARIES_DOWNLOAD environmental variable. #[arg(long)] @@ -108,6 +122,9 @@ impl Args { if let Some(nymvisor_id) = &self.id { config.nymvisor.id = nymvisor_id.clone(); } + if let Some(upstream) = &self.upstream_base_upgrade_url { + config.nymvisor.debug.upstream_base_upgrade_url = upstream.clone() + } if self.disable_nymvisor_logs { config.nymvisor.debug.disable_logs = self.disable_nymvisor_logs; } @@ -118,6 +135,9 @@ impl Args { if let Some(daemon_home) = &self.daemon_home { config.daemon.home = daemon_home.clone(); } + if let Some(upstream) = &self.daemon_absolute_upstream_upgrade_url { + config.daemon.debug.absolute_upstream_upgrade_url = Some(upstream.clone()) + } if let Some(daemon_allow_binaries_download) = self.allow_download_upgrade_binaries { config.daemon.debug.allow_binaries_download = daemon_allow_binaries_download; } diff --git a/tools/nymvisor/src/config/mod.rs b/tools/nymvisor/src/config/mod.rs index 68828653d4..30d33c7356 100644 --- a/tools/nymvisor/src/config/mod.rs +++ b/tools/nymvisor/src/config/mod.rs @@ -2,8 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::template::CONFIG_TEMPLATE; -use crate::env::Env; -use nym_config::serde_helpers::de_maybe_path; +use nym_config::serde_helpers::de_maybe_stringified; use nym_config::{ must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR, @@ -14,6 +13,7 @@ use std::io; use std::path::{Path, PathBuf}; use std::time::Duration; use tracing::{debug, warn}; +use url::Url; mod template; @@ -22,6 +22,9 @@ pub(crate) const DEFAULT_STARTUP_PERIOD: Duration = Duration::from_secs(120); pub(crate) const DEFAULT_MAX_STARTUP_FAILURES: usize = 10; pub(crate) const DEFAULT_SHUTDOWN_GRACE_PERIOD: Duration = Duration::from_secs(10); +pub(crate) const DEFAULT_BASE_UPSTREAM_UPGRADE_INFO_SOURCE: &str = + "https://nymtech.net/.wellknown/"; + pub(crate) const UPGRADE_PLAN_FILENAME: &str = "upgrade-plan.json"; pub(crate) const UPGRADE_INFO_FILENAME: &str = "upgrade-info.json"; pub(crate) const NYMVISOR_DIR: &str = "nymvisor"; @@ -261,6 +264,17 @@ impl Config { pub fn upgrade_plan_filepath(&self) -> PathBuf { self.upgrade_data_dir().join(UPGRADE_PLAN_FILENAME) } + + pub fn upstream_upgrade_url(&self) -> Url { + if let Some(absolute_url) = &self.daemon.debug.absolute_upstream_upgrade_url { + absolute_url.clone() + } else { + let mut base = self.nymvisor.debug.upstream_base_upgrade_url.clone(); + base.set_path(&*format!("{}/{UPGRADE_INFO_FILENAME}", self.daemon.name)); + + base + } + } } #[derive(Debug, Deserialize, PartialEq, Serialize)] @@ -278,6 +292,12 @@ pub struct Nymvisor { #[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct NymvisorDebug { + /// Sets the base url of the upstream source for obtaining upgrade information for the deaemon. + /// default: "https://nymtech.net/.wellknown/" + /// It will be used fo constructing the full url, i.e. $NYMVISOR_UPSTREAM_BASE_UPGRADE_URL/$DAEMON_NAME/upgrade-info.json + /// Can be overridden with $NYMVISOR_UPSTREAM_BASE_UPGRADE_URL environmental variable. + pub upstream_base_upgrade_url: Url, + /// If set to true, this will disable `nymvisor` logs (but not the underlying process) /// default: false /// Can be overridden with $NYMVISOR_DISABLE_LOGS environmental variable. @@ -286,7 +306,7 @@ pub struct NymvisorDebug { /// Set custom directory for upgrade data - binaries and upgrade plans. /// If not set, the global nymvisors' data directory will be used instead. /// Can be overridden with $NYMVISOR_UPGRADE_DATA_DIRECTORY environmental variable. - #[serde(deserialize_with = "de_maybe_path")] + #[serde(deserialize_with = "de_maybe_stringified")] pub upgrade_data_directory: Option, } @@ -294,6 +314,11 @@ pub struct NymvisorDebug { impl Default for NymvisorDebug { fn default() -> Self { NymvisorDebug { + // this expect is fine as we're parsing a constant, hardcoded value that should always be valid + #[allow(clippy::expect_used)] + upstream_base_upgrade_url: DEFAULT_BASE_UPSTREAM_UPGRADE_INFO_SOURCE + .parse() + .expect("default upstream url was malformed"), disable_logs: false, upgrade_data_directory: None, } @@ -321,6 +346,14 @@ pub struct Daemon { #[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct DaemonDebug { + /// Override url to the upstream source for upgrade plans for this daeamon. + /// The Url has to point to an endpoint containing a valid [`UpgradeInfo`] json. + /// Note: if set this takes precedence over .nymvisor.debug.upstream_base_upgrade_url + /// default: None + /// Can be overridden with $DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL environmental variable. + #[serde(deserialize_with = "de_maybe_stringified")] + pub absolute_upstream_upgrade_url: Option, + /// If set to true, this will enable auto-downloading of new binaries using the url provided in the `upgrade-info.json` /// default: true /// Can be overridden with $DAEMON_ALLOW_BINARIES_DOWNLOAD environmental variable. @@ -375,7 +408,7 @@ pub struct DaemonDebug { /// Set custom backup directory for daemon data. If not set, the daemon's home directory will be used instead. /// Can be overridden with $DAEMON_BACKUP_DATA_DIRECTORY environmental variable. - #[serde(deserialize_with = "de_maybe_path")] + #[serde(deserialize_with = "de_maybe_stringified")] pub backup_data_directory: Option, /// If enabled, `nymvisor` will perform upgrades directly without performing any backups. @@ -387,6 +420,7 @@ pub struct DaemonDebug { impl Default for DaemonDebug { fn default() -> Self { DaemonDebug { + absolute_upstream_upgrade_url: None, allow_binaries_download: true, enforce_download_checksum: true, restart_after_upgrade: true, diff --git a/tools/nymvisor/src/config/template.rs b/tools/nymvisor/src/config/template.rs index a317a110ed..bbc9c946b3 100644 --- a/tools/nymvisor/src/config/template.rs +++ b/tools/nymvisor/src/config/template.rs @@ -14,6 +14,12 @@ id = '{{ nymvisor.id }}' ##### further optional configuration nymvisor options ##### +# Sets the base url of the upstream source for obtaining upgrade information for the deaemon. +# default: "https://nymtech.net/.wellknown/" +# It will be used fo constructing the full url, i.e. $NYMVISOR_UPSTREAM_BASE_UPGRADE_URL/$DAEMON_NAME/upgrade-info.json +# Can be overridden with $NYMVISOR_UPSTREAM_BASE_UPGRADE_URL environmental variable. +upstream_base_upgrade_url = '{{ nymvisor.upstream_base_upgrade_url }}' + # If set to true, this will disable `nymvisor` logs (but not the underlying process) # default: false # Can be overridden with $NYMVISOR_DISABLE_LOGS environmental variable. @@ -40,6 +46,13 @@ home = '{{ daemon.home }}' ##### further optional configuration daemon options ##### +# Override url to the upstream source for upgrade plans for this daeamon. +# The Url has to point to an endpoint containing a valid [`UpgradeInfo`] json. +# Note: if set this takes precedence over .nymvisor.debug.upstream_base_upgrade_url +# default: None +# Can be overridden with $DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL environmental variable. +absolute_upstream_upgrade_url = '{{ daemon.absolute_upstream_upgrade_url }}' + # If set to true, this will enable auto-downloading of new binaries using the url provided in the `upgrade-info.json` # default: true # Can be overridden with $DAEMON_ALLOW_BINARIES_DOWNLOAD environmental variable. diff --git a/tools/nymvisor/src/env.rs b/tools/nymvisor/src/env.rs index 50e6e3a5ea..75e3ad1c01 100644 --- a/tools/nymvisor/src/env.rs +++ b/tools/nymvisor/src/env.rs @@ -6,6 +6,7 @@ use crate::error::NymvisorError; use std::env::VarError; use std::path::PathBuf; use std::time::Duration; +use url::Url; const TRUTHY_BOOLS: &[&str] = &["true", "t", "1"]; const FALSY_BOOLS: &[&str] = &["false", "f", "0"]; @@ -13,11 +14,13 @@ const FALSY_BOOLS: &[&str] = &["false", "f", "0"]; pub mod vars { pub const NYMVISOR_ID: &str = "NYMVISOR_ID"; pub const NYMVISOR_CONFIG_PATH: &str = "NYMVISOR_CONFIG_PATH"; + pub const NYMVISOR_UPSTREAM_BASE_UPGRADE_URL: &str = "NYMVISOR_UPSTREAM_BASE_UPGRADE_URL"; pub const NYMVISOR_DISABLE_LOGS: &str = "NYMVISOR_DISABLE_LOGS"; pub const NYMVISOR_UPGRADE_DATA_DIRECTORY: &str = "NYMVISOR_UPGRADE_DATA_DIRECTORY"; pub const DAEMON_NAME: &str = "DAEMON_NAME"; pub const DAEMON_HOME: &str = "DAEMON_HOME"; + pub const DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL: &str = "DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL"; pub const DAEMON_ALLOW_BINARIES_DOWNLOAD: &str = "DAEMON_ALLOW_BINARIES_DOWNLOAD"; pub const DAEMON_ENFORCE_DOWNLOAD_CHECKSUM: &str = "DAEMON_ENFORCE_DOWNLOAD_CHECKSUM"; pub const DAEMON_RESTART_AFTER_UPGRADE: &str = "DAEMON_RESTART_AFTER_UPGRADE"; @@ -41,11 +44,13 @@ pub(crate) fn setup_env(config_env_file: &Option) -> Result<(), Nymviso pub(crate) struct Env { pub(crate) nymvisor_id: Option, pub(crate) nymvisor_config_path: Option, + pub(crate) nymvisor_upstream_base_upgrade_url: Option, pub(crate) nymvisor_disable_logs: Option, pub(crate) nymvisor_upgrade_data_directory: Option, pub(crate) daemon_name: Option, pub(crate) daemon_home: Option, + pub(crate) daemon_absolute_upstream_upgrade_url: Option, pub(crate) daemon_allow_binaries_download: Option, pub(crate) daemon_enforce_download_checksum: Option, pub(crate) daemon_restart_after_upgrade: Option, @@ -63,6 +68,9 @@ impl Env { if let Some(nymvisor_id) = &self.nymvisor_id { config.nymvisor.id = nymvisor_id.clone(); } + if let Some(upstream) = &self.nymvisor_upstream_base_upgrade_url { + config.nymvisor.debug.upstream_base_upgrade_url = upstream.clone() + } if let Some(nymvisor_disable_logs) = self.nymvisor_disable_logs { config.nymvisor.debug.disable_logs = nymvisor_disable_logs; } @@ -76,6 +84,9 @@ impl Env { if let Some(daemon_home) = &self.daemon_home { config.daemon.home = daemon_home.clone(); } + if let Some(upstream) = &self.daemon_absolute_upstream_upgrade_url { + config.daemon.debug.absolute_upstream_upgrade_url = Some(upstream.clone()) + } if let Some(daemon_allow_binaries_download) = self.daemon_allow_binaries_download { config.daemon.debug.allow_binaries_download = daemon_allow_binaries_download; } @@ -167,6 +178,19 @@ fn read_pathbuf(var: &str) -> Result, NymvisorError> { Ok(read_string(var)?.map(PathBuf::from)) } +fn read_url(var: &str) -> Result, NymvisorError> { + read_string(var)? + .map(|raw| { + raw.parse() + .map_err(|source| NymvisorError::MalformedUrlEnvVariable { + variable: var.to_string(), + value: raw.to_string(), + source, + }) + }) + .transpose() +} + fn read_usize(var: &str) -> Result, NymvisorError> { read_string(var)? .map(|raw| { @@ -187,10 +211,14 @@ impl Env { Ok(Env { nymvisor_id: read_string(vars::NYMVISOR_ID)?, nymvisor_config_path: read_pathbuf(vars::NYMVISOR_CONFIG_PATH)?, + nymvisor_upstream_base_upgrade_url: read_url(vars::NYMVISOR_UPSTREAM_BASE_UPGRADE_URL)?, nymvisor_disable_logs: read_bool(vars::NYMVISOR_DISABLE_LOGS)?, nymvisor_upgrade_data_directory: read_pathbuf(vars::NYMVISOR_UPGRADE_DATA_DIRECTORY)?, daemon_name: read_string(vars::DAEMON_NAME)?, daemon_home: read_pathbuf(vars::DAEMON_HOME)?, + daemon_absolute_upstream_upgrade_url: read_url( + vars::DAEMON_ABSOLUTE_UPSTREAM_UPGRADE_URL, + )?, daemon_allow_binaries_download: read_bool(vars::DAEMON_ALLOW_BINARIES_DOWNLOAD)?, daemon_enforce_download_checksum: read_bool(vars::DAEMON_ENFORCE_DOWNLOAD_CHECKSUM)?, daemon_restart_after_upgrade: read_bool(vars::DAEMON_RESTART_AFTER_UPGRADE)?, diff --git a/tools/nymvisor/src/error.rs b/tools/nymvisor/src/error.rs index 69a856d2ad..c99ad0a5a1 100644 --- a/tools/nymvisor/src/error.rs +++ b/tools/nymvisor/src/error.rs @@ -68,6 +68,14 @@ pub(crate) enum NymvisorError { source: ParseIntError, }, + #[error("the value provided for environmental Url '{variable}': '{value}' is not a valid number: {source}")] + MalformedUrlEnvVariable { + variable: String, + value: String, + #[source] + source: url::ParseError, + }, + #[error("failed to copy daemon binary from '{}' to '{}': {source}", source_path.display(), target_path.display())] DaemonBinaryCopyFailure { source_path: PathBuf,