From a60f37ae88c27007c2d850d9849eff08ba1a8bd5 Mon Sep 17 00:00:00 2001 From: Fran Arbanas Date: Fri, 18 Oct 2024 12:23:25 +0200 Subject: [PATCH] feat: add dockerfile and env variables --- nym-node-status-api/Cargo.toml | 11 ++++-- nym-node-status-api/Dockerfile | 13 +++++++ nym-node-status-api/src/cli/mod.rs | 60 +++++++++++++++++++++++++++++- nym-node-status-api/src/config.rs | 21 ++++++----- nym-node-status-api/src/db/mod.rs | 5 +-- nym-node-status-api/src/main.rs | 10 ++--- 6 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 nym-node-status-api/Dockerfile diff --git a/nym-node-status-api/Cargo.toml b/nym-node-status-api/Cargo.toml index 03e6fe60a7..056271e41d 100644 --- a/nym-node-status-api/Cargo.toml +++ b/nym-node-status-api/Cargo.toml @@ -16,7 +16,7 @@ rust-version.workspace = true anyhow = { workspace = true } axum = { workspace = true, features = ["tokio"] } chrono = { workspace = true } -clap = { workspace = true, features = ["cargo", "derive"] } +clap = { workspace = true, features = ["cargo", "derive", "env", "string"] } cosmwasm-std = { workspace = true } envy = { workspace = true } futures-util = { workspace = true } @@ -53,5 +53,10 @@ utoipauto = { workspace = true } [build-dependencies] anyhow = { workspace = true } -tokio = { workspace = true, features = ["macros" ] } -sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] } +tokio = { workspace = true, features = ["macros"] } +sqlx = { workspace = true, features = [ + "runtime-tokio-rustls", + "sqlite", + "macros", + "migrate", +] } diff --git a/nym-node-status-api/Dockerfile b/nym-node-status-api/Dockerfile new file mode 100644 index 0000000000..28a15d22ba --- /dev/null +++ b/nym-node-status-api/Dockerfile @@ -0,0 +1,13 @@ +FROM rust:latest AS builder + +COPY ./ /usr/src/nym +WORKDIR /usr/src/nym/nym-node-status-api + +RUN cargo build --release + +FROM ubuntu:24.04 + +WORKDIR /nym + +COPY --from=builder /usr/src/nym/target/release/nym-node-status-api ./ +ENTRYPOINT [ "/nym/nym-node-status-api" ] diff --git a/nym-node-status-api/src/cli/mod.rs b/nym-node-status-api/src/cli/mod.rs index 7f46578863..b830c56fc5 100644 --- a/nym-node-status-api/src/cli/mod.rs +++ b/nym-node-status-api/src/cli/mod.rs @@ -1,6 +1,7 @@ use clap::Parser; use nym_bin_common::bin_info; -use std::sync::OnceLock; +use reqwest::Url; +use std::{sync::OnceLock, time::Duration}; // Helper for passing LONG_VERSION to clap fn pretty_build_info_static() -> &'static str { @@ -12,6 +13,61 @@ fn pretty_build_info_static() -> &'static str { #[clap(author = "Nymtech", version, long_version = pretty_build_info_static(), about)] pub(crate) struct Cli { /// Path pointing to an env file that configures the Nym API. - #[clap(short, long)] + #[clap(short, long, env = "NYM_NODE_STATUS_API_ENV_FILE")] pub(crate) config_env_file: Option, + + /// Network name for the network to which we're connecting. + #[clap(long, env = "NYM_NODE_STATUS_API_NETWORK_NAME")] + pub(crate) network_name: String, + + /// Explorer api url. + #[clap(short, long, env = "NYM_NODE_STATUS_API_EXPLORER_API")] + pub(crate) explorer_api: String, + + /// Nym api url. + #[clap(short, long, env = "NYM_NODE_STATUS_API_NYM_API")] + pub(crate) nym_api: String, + + /// TTL for the http cache. + #[clap( + long, + default_value_t = 30, + env = "NYM_NODE_STATUS_API_NYM_HTTP_CACHE_TTL" + )] + pub(crate) nym_http_cache_ttl: u64, + + /// HTTP port on which to run node status api. + #[clap(long, default_value_t = 8000, env = "NYM_NODE_STATUS_API_HTTP_PORT")] + pub(crate) http_port: u16, + + /// Nyxd address. + #[clap(long, env = "NYM_NODE_STATUS_API_NYXD_ADDR")] + pub(crate) nyxd_addr: Url, + + /// Nym api client timeout. + #[clap( + long, + default_value = "15", + env = "NYM_NODE_STATUS_API_NYM_API_CLIENT_TIMEOUT" + )] + #[arg(value_parser = parse_duration)] + pub(crate) nym_api_client_timeout: Duration, + + /// Explorer api client timeout. + #[clap( + long, + default_value = "15", + env = "NYM_NODE_STATUS_API_EXPLORER_CLIENT_TIMEOUT" + )] + #[arg(value_parser = parse_duration)] + pub(crate) explorer_client_timeout: Duration, + + /// Connection url for the database. + #[clap(long, env = "NYM_NODE_STATUS_API_CONNECTION_URL")] + pub(crate) connection_url: String, +} + +fn parse_duration(arg: &str) -> Result { + let seconds = arg.parse()?; + Ok(std::time::Duration::from_secs(seconds)) } diff --git a/nym-node-status-api/src/config.rs b/nym-node-status-api/src/config.rs index c499ef3c65..cc532f298a 100644 --- a/nym-node-status-api/src/config.rs +++ b/nym-node-status-api/src/config.rs @@ -1,8 +1,9 @@ -use anyhow::anyhow; use reqwest::Url; use serde::Deserialize; use std::time::Duration; +use crate::cli::Cli; + #[derive(Debug, Clone, Deserialize)] pub(crate) struct Config { #[serde(default = "Config::default_http_cache_seconds")] @@ -17,6 +18,15 @@ pub(crate) struct Config { } impl Config { + pub(crate) fn from_args(args: Cli) -> Self { + Config { + nym_http_cache_ttl: args.nym_http_cache_ttl, + http_port: args.http_port, + nyxd_addr: args.nyxd_addr, + explorer_client_timeout: args.explorer_client_timeout, + } + } + pub(crate) fn from_env() -> anyhow::Result { envy::from_env::().map_err(|e| { tracing::error!("Failed to load config from env: {e}"); @@ -61,12 +71,3 @@ where let secs: u64 = s.parse().map_err(serde::de::Error::custom)?; Ok(Duration::from_secs(secs)) } - -pub(super) fn read_env_var(env_var: &str) -> anyhow::Result { - std::env::var(env_var) - .map_err(|_| anyhow!("You need to set {}", env_var)) - .map(|value| { - tracing::trace!("{}={}", env_var, value); - value - }) -} diff --git a/nym-node-status-api/src/db/mod.rs b/nym-node-status-api/src/db/mod.rs index 784a35f17a..37c0a7f5ba 100644 --- a/nym-node-status-api/src/db/mod.rs +++ b/nym-node-status-api/src/db/mod.rs @@ -1,13 +1,11 @@ use std::str::FromStr; -use crate::read_env_var; use anyhow::{anyhow, Result}; use sqlx::{migrate::Migrator, sqlite::SqliteConnectOptions, ConnectOptions, SqlitePool}; pub(crate) mod models; pub(crate) mod queries; -pub(crate) const DATABASE_URL_ENV_VAR: &str = "DATABASE_URL"; static MIGRATOR: Migrator = sqlx::migrate!("./migrations"); pub(crate) type DbPool = SqlitePool; @@ -17,8 +15,7 @@ pub(crate) struct Storage { } impl Storage { - pub async fn init() -> Result { - let connection_url = read_env_var(DATABASE_URL_ENV_VAR)?; + pub async fn init(connection_url: String) -> Result { let connect_options = { let connect_options = SqliteConnectOptions::from_str(&connection_url)?; let mut connect_options = connect_options.create_if_missing(true); diff --git a/nym-node-status-api/src/main.rs b/nym-node-status-api/src/main.rs index 0fb1d0e1d2..9ae561e483 100644 --- a/nym-node-status-api/src/main.rs +++ b/nym-node-status-api/src/main.rs @@ -2,8 +2,6 @@ use clap::Parser; use nym_network_defaults::setup_env; use nym_task::signal::wait_for_signal; -use crate::config::read_env_var; - mod cli; mod config; mod db; @@ -19,14 +17,12 @@ async fn main() -> anyhow::Result<()> { // if dotenv file is present, load its values // otherwise, default to mainnet setup_env(args.config_env_file.as_ref()); - tracing::debug!("{:?}", read_env_var("NETWORK_NAME")); - tracing::debug!("{:?}", read_env_var("EXPLORER_API")); - tracing::debug!("{:?}", read_env_var("NYM_API")); - let conf = config::Config::from_env()?; + let connection_url = args.connection_url.clone(); + let conf = config::Config::from_args(args); tracing::debug!("Using config:\n{:#?}", conf); - let storage = db::Storage::init().await?; + let storage = db::Storage::init(connection_url).await?; let db_pool = storage.pool_owned().await; let conf_clone = conf.clone(); tokio::spawn(async move {