clippy and final missing features

This commit is contained in:
Jędrzej Stuczyński
2023-11-17 14:52:14 +00:00
parent 9b5714b897
commit b10da899a8
9 changed files with 149 additions and 83 deletions
+46 -45
View File
@@ -35,26 +35,25 @@ pub(crate) struct Args {
/// Indicate that this command should only add binary to an *existing* scheduled upgrade
#[arg(long)]
#[deprecated(note = "need to implement")]
add_binary: bool,
/// Force the upgrade to happen immediately
#[arg(long, group = "time")]
#[arg(long, group = "time", conflicts_with = "add_binary")]
now: bool,
/// Specifies the publish date metadata field of this upgrade.
/// If unset, the current time will be used.
#[arg(long, value_parser = parse_rfc3339_upgrade_time)]
#[arg(long, value_parser = parse_rfc3339_upgrade_time, conflicts_with = "add_binary")]
publish_date: Option<OffsetDateTime>,
/// Specifies the time at which the provided upgrade will be performed (RFC3339 formatted).
/// If left unset, the upgrade will be performed in 15min
#[arg(long, value_parser = parse_rfc3339_upgrade_time, group = "time")]
#[arg(long, value_parser = parse_rfc3339_upgrade_time, group = "time", conflicts_with = "add_binary")]
upgrade_time: Option<OffsetDateTime>,
/// Specifies delay until the provided upgrade is going to get performed.
/// If let unset, the upgrade will be performed in 15min
#[arg(long, value_parser = humantime::parse_duration, group = "time")]
#[arg(long, value_parser = humantime::parse_duration, group = "time", conflicts_with = "add_binary")]
upgrade_delay: Option<Duration>,
#[clap(short, long, default_value_t = OutputFormat::default())]
@@ -87,52 +86,54 @@ pub(crate) fn execute(args: Args) -> Result<(), NymvisorError> {
if env.daemon_name.is_none() {
env.daemon_name = Some(bin_info.binary_name.clone());
}
let config = try_load_current_config(&env)?;
let mut current_upgrade_plan = UpgradePlan::try_load(config.upgrade_plan_filepath())?;
let upgrade_time = args.determine_upgrade_time();
let upgrade_info = UpgradeInfo {
manual: false,
name: args.upgrade_name,
notes: "manually added via 'add-upgrade' command".to_string(),
publish_date: Some(args.publish_date.unwrap_or(OffsetDateTime::now_utc())),
version: bin_info.build_version.clone(),
platforms: Default::default(),
upgrade_time,
binary_details: Some(bin_info),
};
let upgrade_info_path = config.upgrade_dir(&upgrade_info.name);
if upgrade_info_path.exists() {
// TODO: maybe just copy binary?
todo!()
}
// TODO: check if upgrade-plan already contains this upgrade
// if upgrade_info_path.exists() && !args.force {
// return Err(NymvisorError::ExistingUpgrade {
// name: upgrade_info.name,
// path: upgrade_info_path,
// });
// }
let upgrade_binary_path = config.upgrade_binary_dir(&upgrade_info.name);
if upgrade_binary_path.exists() && !args.force {
let upgrade_info_path = config.upgrade_info_filepath(&args.upgrade_name);
let bin_path = config.upgrade_binary(&args.upgrade_name);
if bin_path.exists() && !args.force {
return Err(NymvisorError::ExistingUpgrade {
name: upgrade_info.name,
path: upgrade_binary_path,
name: args.upgrade_name,
path: bin_path,
});
}
init_path(upgrade_binary_path)?;
copy_binary(
&args.daemon_binary,
config.upgrade_binary(&upgrade_info.name),
)?;
upgrade_info.save(config.upgrade_info_filepath(&upgrade_info.name))?;
current_upgrade_plan.insert_new_upgrade(upgrade_info)?;
// if we're just adding the binary, the upgrade plan MUST already exist,
// otherwise it MUSTN'T exist (unless --force is used)
if args.add_binary {
let upgrade_info = UpgradeInfo::try_load(upgrade_info_path)?;
upgrade_info.ensure_matches_bin_info(&bin_info)?;
} else {
if upgrade_info_path.exists() && !args.force {
return Err(NymvisorError::ExistingUpgradeInfo {
name: args.upgrade_name,
path: upgrade_info_path,
});
}
let mut current_upgrade_plan = UpgradePlan::try_load(config.upgrade_plan_filepath())?;
let upgrade_info = UpgradeInfo {
manual: false,
name: args.upgrade_name.clone(),
notes: "manually added via 'add-upgrade' command".to_string(),
publish_date: Some(args.publish_date.unwrap_or(OffsetDateTime::now_utc())),
version: bin_info.build_version.clone(),
platforms: Default::default(),
upgrade_time: args.determine_upgrade_time(),
binary_details: Some(bin_info),
};
if current_upgrade_plan.has_planned_by_name(&args.upgrade_name) {
return Err(NymvisorError::UpgradePlanWithNoInfo {
name: args.upgrade_name,
});
}
init_path(config.upgrade_binary_dir(&args.upgrade_name))?;
upgrade_info.save(config.upgrade_info_filepath(&upgrade_info.name))?;
current_upgrade_plan.insert_new_upgrade(upgrade_info)?;
}
copy_binary(&args.daemon_binary, bin_path)?;
Ok(())
}
+2 -2
View File
@@ -43,7 +43,7 @@ impl Cli {
setup_env(&self.config_env_file)?;
match self.command {
Commands::Init(args) => init::execute(args),
Commands::Init(args) => init::execute(*args),
Commands::Run(args) => run::execute(args),
Commands::BuildInfo(args) => build_info::execute(args),
Commands::DaemonBuildInfo(args) => daemon_build_info::execute(args),
@@ -56,7 +56,7 @@ impl Cli {
#[derive(Subcommand, Debug)]
pub(crate) enum Commands {
/// Initialise a nymvisor instance with persistent Config.toml file.
Init(init::Args),
Init(Box<init::Args>),
/// Run the associated daemon with the preconfigured settings.
Run(run::Args),
+16 -6
View File
@@ -8,7 +8,10 @@ use crate::tasks::launcher::DaemonLauncher;
use crate::tasks::upgrade_plan_watcher::start_upgrade_plan_watcher;
use crate::tasks::upstream_poller::UpstreamPoller;
use nym_bin_common::logging::setup_tracing_logger;
use std::future::Future;
use std::time::Duration;
use tokio::runtime;
use tokio::time::timeout;
use tracing::{error, info};
#[derive(clap::Args, Debug)]
@@ -27,8 +30,8 @@ pub(crate) fn execute(args: Args) -> Result<(), NymvisorError> {
info!("starting nymvisor for {}", config.daemon.name);
// TODO: experiment with the minimal runtime
// look at futures::executor::LocalPool
// TODO: experiment with other minimal runtimes, maybe futures::executor::LocalPool
//
// well, if the creation of the runtime failed, there isn't much we could do
#[allow(clippy::expect_used)]
let rt = runtime::Builder::new_current_thread()
@@ -62,11 +65,18 @@ pub(crate) fn execute(args: Args) -> Result<(), NymvisorError> {
upstream_poller_handle.abort();
}
// TODO: add timeouts and error handling here
// TODO2: maybe we need to make those fuse futures?
watcher_handle.await;
upstream_poller_handle.await;
wait_for_task_termination(watcher_handle, "Upgrade plan watcher").await;
wait_for_task_termination(upstream_poller_handle, "Upstream poller").await;
Ok(())
})
}
async fn wait_for_task_termination<F: Future>(task: F, name: &str) {
match timeout(Duration::from_secs(2), task).await {
Ok(_) => info!("{name} has finished execution"),
Err(_timeout) => {
error!("{name} task has timed out and has not shutdown gracefully")
}
}
}
+3 -5
View File
@@ -206,10 +206,6 @@ impl Config {
Self::read_from_path(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
Self::read_from_path(default_config_filepath(id))
}
pub fn default_location(&self) -> PathBuf {
default_config_filepath(&self.nymvisor.id)
}
@@ -223,6 +219,8 @@ impl Config {
save_formatted_config_to_file(self, path)
}
// this code will be needed for config upgrades
#[allow(dead_code)]
pub fn try_save(&self) -> io::Result<()> {
if let Some(save_location) = &self.save_path {
save_formatted_config_to_file(self, save_location)
@@ -253,7 +251,7 @@ impl Config {
// e.g. $HOME/.nym/nym-api/<id>/nymvisor/current-version.json
pub fn current_daemon_version_filepath(&self) -> PathBuf {
todo!()
self.daemon_nymvisor_dir().join(CURRENT_VERSION_FILENAME)
}
// e.g. $HOME/.nym/nymvisors/data/nym-api/
+15 -3
View File
@@ -84,10 +84,17 @@ impl Daemon {
#[instrument(skip(self), fields(self.executable_path = ?self.executable_path))]
pub(crate) fn verify_binary(&self) -> Result<(), NymvisorError> {
let metadata = fs::metadata(&self.executable_path).expect("error handling");
let metadata = fs::metadata(&self.executable_path).map_err(|source| {
NymvisorError::MetadataReadFailure {
path: self.executable_path.clone(),
source,
}
})?;
if !metadata.is_file() {
todo!("error not a file")
return Err(NymvisorError::DaemonNotAFile {
path: self.executable_path.clone(),
});
}
let mut permissions = metadata.permissions();
@@ -100,7 +107,12 @@ impl Daemon {
let new_mode = mode | 0o111; // Set the three execute bits to on (a+x).
permissions.set_mode(new_mode);
fs::set_permissions(&self.executable_path, permissions).expect("error handling");
fs::set_permissions(&self.executable_path, permissions).map_err(|source| {
NymvisorError::DaemonPermissionFailure {
path: self.executable_path.clone(),
source,
}
})?;
}
Ok(())
+29 -6
View File
@@ -130,13 +130,13 @@ While the stored info point to:\n{current_info:#?}"
},
#[error(
"the current daemon build does not match the expected value in `current-version.info.json`.\n\
The daemon version is:\n{daemon_version:#?}\n\
While the stored info point to:\n{current_version_info:#?}"
"the current daemon build information does not match the expected stored value.\n\
The daemon build is:\n{daemon_info:#?}\n\
While the stored info point to:\n{stored_info:#?}"
)]
UnexpectedDaemonBuild {
daemon_version: Box<BinaryBuildInformationOwned>,
current_version_info: Box<BinaryBuildInformationOwned>,
daemon_info: Box<BinaryBuildInformationOwned>,
stored_info: Box<BinaryBuildInformationOwned>,
},
#[error("the daemon for upgrade '{upgrade_name}' has version {daemon_version} while {expected} was expected instead")]
@@ -146,6 +146,23 @@ While the stored info point to:\n{current_version_info:#?}"
expected: String,
},
#[error("the provided daemon at {} is not a file", path.display())]
DaemonNotAFile { path: PathBuf },
#[error("could not read daemon's metadata at {}: {source}", path.display())]
MetadataReadFailure {
path: PathBuf,
#[source]
source: io::Error,
},
#[error("could not adjust permission of the daemon at: {}: {source}", path.display())]
DaemonPermissionFailure {
path: PathBuf,
#[source]
source: io::Error,
},
#[error("could not acquire the lock at {} to perform binary upgrade with error code {libc_code}. It is either held by another process or this nymvisor has experienced a critical failure during previous upgrade attempt", lock_path.display())]
UnableToAcquireUpgradePlanLock {
lock_path: PathBuf,
@@ -304,9 +321,15 @@ While the stored info point to:\n{current_version_info:#?}"
provided_genesis: Box<BinaryBuildInformationOwned>,
},
#[error("there already exist upgrade binary for '{name}' at: {}. if you want to ovewrite its content, use --force flag", path.display())]
#[error("there already exist upgrade binary for '{name}' at: {}. if you want to overwrite its content, use --force flag", path.display())]
ExistingUpgrade { name: String, path: PathBuf },
#[error("there already exist upgrade information for '{name}' at: {}. if you want to overwrite its content, use --force flag", path.display())]
ExistingUpgradeInfo { name: String, path: PathBuf },
#[error("the current upgrade-plan.json has planned upgrade for '{name}', but no corresponding upgrade-info.json file could be found")]
UpgradePlanWithNoInfo { name: String },
#[error("there was already a symlink for the 'current' binary of {daemon_name}. it's pointing to {} while we needed to create one to {}", link.display(), expected_link.display())]
ExistingCurrentSymlink {
daemon_name: String,
+2 -2
View File
@@ -146,8 +146,8 @@ impl DaemonLauncher {
current_info.ensure_matches(&expected_version)?;
if expected_version.binary_details != daemon_info {
return Err(NymvisorError::UnexpectedDaemonBuild {
daemon_version: Box::new(daemon_info),
current_version_info: Box::new(expected_version.binary_details),
daemon_info: Box::new(daemon_info),
stored_info: Box::new(expected_version.binary_details),
});
}
+2 -7
View File
@@ -88,13 +88,7 @@ pub(crate) async fn perform_upgrade(config: &Config) -> Result<UpgradeResult, Ny
tmp_daemon.verify_binary()?;
let new_bin_info = tmp_daemon.get_build_information()?;
if new_bin_info.build_version != next.version {
return Err(NymvisorError::UnexpectedUpgradeDaemonVersion {
upgrade_name,
daemon_version: new_bin_info.build_version,
expected: next.version,
});
}
next.ensure_matches_bin_info(&new_bin_info)?;
// update the 'current-version-history.json'
CurrentVersionInfo {
@@ -106,6 +100,7 @@ pub(crate) async fn perform_upgrade(config: &Config) -> Result<UpgradeResult, Ny
.save(config.current_daemon_version_filepath())?;
// update the 'upgrade-plan.json'
plan.set_current(next.clone());
plan.update_on_disk()?;
// update the 'upgrade-history.json'
+34 -7
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
use super::serde_helpers::{base64, option_offsetdatetime};
use crate::config::GENESIS_DIR;
use crate::error::NymvisorError;
use crate::helpers::{calculate_file_checksum, init_path};
use crate::upgrades::download::os_arch;
@@ -119,9 +118,14 @@ impl UpgradePlan {
false
}
// pub(crate) fn update_current(&mut self) -> Result<(), NymvisorError> {
//
// }
pub(crate) fn has_planned_by_name(&self, upgrade_name: &str) -> bool {
for planned in &self.queued_up {
if planned.name == upgrade_name {
return true;
}
}
false
}
pub(crate) fn save_new<P: AsRef<Path>>(&self, path: P) -> Result<(), NymvisorError> {
debug_assert!(self._save_path.is_none());
@@ -280,9 +284,9 @@ impl UpgradeInfo {
})
}
pub(crate) fn is_genesis(&self) -> bool {
self.name == GENESIS_DIR
}
// pub(crate) fn is_genesis(&self) -> bool {
// self.name == GENESIS_DIR
// }
pub(crate) fn get_download_url(&self) -> Result<&DownloadUrl, NymvisorError> {
if let Some(download_url) = self.platforms.get(&os_arch()) {
@@ -319,6 +323,29 @@ impl UpgradeInfo {
Ok(())
}
pub(crate) fn ensure_matches_bin_info(
&self,
info: &BinaryBuildInformationOwned,
) -> Result<(), NymvisorError> {
if let Some(self_info) = &self.binary_details {
if self_info != info {
return Err(NymvisorError::UnexpectedDaemonBuild {
daemon_info: Box::new(info.clone()),
stored_info: Box::new(self_info.clone()),
});
}
}
if self.version != info.build_version {
return Err(NymvisorError::UnexpectedUpgradeDaemonVersion {
upgrade_name: self.name.clone(),
daemon_version: info.build_version.clone(),
expected: self.version.clone(),
});
}
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug)]