diff --git a/.vscode/settings.json b/.vscode/settings.json index 8df8b811..f66aa33e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,4 @@ { - "rust-analyzer.rustfmt.extraArgs": [ - "+nightly" - ], - "rust-analyzer.showUnlinkedFileNotification": false, - "rust-analyzer.check.extraArgs": ["--all-features", "--", "-D", "warnings", "--no-deps"] + "rust-analyzer.rustfmt.extraArgs": ["+nightly"], + "rust-analyzer.showUnlinkedFileNotification": false } diff --git a/Cargo.lock b/Cargo.lock index 4e8bb014..88ba5099 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -449,53 +449,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbc26382d871df4b7442e3df10a9402bf3cf5e55cbd66f12be38861425f0564" -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-upgrades" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e2ecf0f5b0ca1144cce2c68679ed6b4c5aeef90b2d7d6ca111c9f33c9c0346" -dependencies = [ - "cargo_metadata", - "crates-index", - "getopts", - "http 0.2.12", - "quick-error 2.0.1", - "semver", - "ureq", -] - -[[package]] -name = "cargo_metadata" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "cc" version = "1.0.90" @@ -693,26 +646,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crates-index" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9efa03a974d583ad530bbfe00e3d0021de7f26217120437b128dc4c331aa4f" -dependencies = [ - "hex", - "home", - "http 0.2.12", - "memchr", - "rustc-hash", - "semver", - "serde", - "serde_derive", - "serde_json", - "smol_str", - "thiserror", - "toml", -] - [[package]] name = "crc32fast" version = "1.4.0" @@ -1101,20 +1034,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "external-ip" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8ffaa6a69a16a38efb9940c9e6612acbb799f80d9b913327df519dede6cb63" -dependencies = [ - "cargo-upgrades", - "futures", - "log", - "rand", - "reqwest 0.11.27", - "trust-dns-resolver", -] - [[package]] name = "fastrand" version = "1.9.0" @@ -1511,9 +1430,6 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] [[package]] name = "hmac" @@ -1524,15 +1440,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "hostname" version = "0.3.1" @@ -1724,16 +1631,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.5.0" @@ -1789,18 +1686,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "ipconfig" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" -dependencies = [ - "socket2", - "widestring", - "windows-sys 0.48.0", - "winreg 0.50.0", -] - [[package]] name = "ipnet" version = "2.9.0" @@ -2056,15 +1941,6 @@ dependencies = [ "hashbrown 0.14.3", ] -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "lz4-sys" version = "1.9.4" @@ -2732,18 +2608,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - [[package]] name = "quick-xml" version = "0.23.1" @@ -2992,16 +2856,6 @@ dependencies = [ "winreg 0.52.0", ] -[[package]] -name = "resolv-conf" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" -dependencies = [ - "hostname", - "quick-error 1.2.3", -] - [[package]] name = "ring" version = "0.17.8" @@ -3252,9 +3106,6 @@ name = "semver" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" -dependencies = [ - "serde", -] [[package]] name = "serde" @@ -3309,15 +3160,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4612,7 +4454,6 @@ dependencies = [ "clap", "dashmap", "duration-str", - "external-ip", "fixedbitset", "futures-util", "hmac", @@ -4655,7 +4496,6 @@ dependencies = [ "bincode", "checkpoint", "clap", - "external-ip", "futures", "futures-util", "http 1.1.0", @@ -5043,6 +4883,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.15" @@ -5062,8 +4913,13 @@ checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" dependencies = [ "futures-util", "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", "tokio", + "tokio-rustls", "tungstenite", + "webpki-roots", ] [[package]] @@ -5081,40 +4937,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "toml" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" -dependencies = [ - "indexmap 2.2.6", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - [[package]] name = "tower" version = "0.4.13" @@ -5270,52 +5092,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "trust-dns-proto" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3119112651c157f4488931a01e586aa459736e9d6046d3bd9105ffb69352d374" -dependencies = [ - "async-trait", - "cfg-if 1.0.0", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.4.0", - "ipnet", - "once_cell", - "rand", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6" -dependencies = [ - "cfg-if 1.0.0", - "futures-util", - "ipconfig", - "lru-cache", - "once_cell", - "parking_lot 0.12.1", - "rand", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -5344,6 +5120,8 @@ dependencies = [ "httparse", "log", "rand", + "rustls", + "rustls-pki-types", "sha1", "thiserror", "url", @@ -5418,11 +5196,9 @@ checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" dependencies = [ "base64 0.21.7", "flate2", - "http 0.2.12", "log", "once_cell", "rustls", - "rustls-native-certs", "rustls-pki-types", "rustls-webpki", "serde", @@ -5438,7 +5214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", "serde", ] @@ -5657,12 +5433,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "widestring" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" - [[package]] name = "wildmatch" version = "2.3.3" @@ -5832,15 +5602,6 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" -[[package]] -name = "winnow" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" -dependencies = [ - "memchr", -] - [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index 8be313dd..feaf4785 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,6 @@ colored = "2" crossterm = { version = "0.27", default-features = false } dashmap = "5.5" duration-str = { version = "0.7", default-features = false } -external-ip = { version = "5.0", default-features = false } fixedbitset = { version = "0.5", default-features = false } futures = { version = "0.3", default-features = false } futures-util = { version = "0.3", default-features = false } @@ -99,7 +98,10 @@ surrealdb = { version = "1.3", default-features = false } tarpc = { version = "0.34", features = ["tokio1", "serde1"] } thiserror = "1.0" tokio = "1" -tokio-tungstenite = "0.21" +tokio-tungstenite = { version = "0.21", features = [ + "rustls-tls-native-roots", + "rustls-tls-webpki-roots", +] } tower = { version = "0.4", default-features = false } tower-http = { version = "0.5", features = ["fs", "trace"] } tracing = { version = "0.1", default-features = false, features = ["std"] } diff --git a/crates/snops-agent/Cargo.toml b/crates/snops-agent/Cargo.toml index 7223d5b9..b50f1a4b 100644 --- a/crates/snops-agent/Cargo.toml +++ b/crates/snops-agent/Cargo.toml @@ -8,7 +8,6 @@ anyhow.workspace = true bincode.workspace = true checkpoint.workspace = true clap.workspace = true -external-ip.workspace = true futures.workspace = true futures-util.workspace = true http.workspace = true @@ -19,7 +18,12 @@ reqwest = { workspace = true, features = ["json", "stream"] } simple_moving_average.workspace = true snops-common = { path = "../snops-common" } tarpc.workspace = true -tokio = { workspace = true, features = ["macros", "process", "signal"] } +tokio = { workspace = true, features = [ + "macros", + "process", + "signal", + "rt-multi-thread", +] } tokio-tungstenite.workspace = true tracing-appender.workspace = true tracing.workspace = true diff --git a/crates/snops-agent/src/cli.rs b/crates/snops-agent/src/cli.rs index cee5ca7e..e8d83db9 100644 --- a/crates/snops-agent/src/cli.rs +++ b/crates/snops-agent/src/cli.rs @@ -17,7 +17,7 @@ pub const ENV_ENDPOINT_DEFAULT: &str = "127.0.0.1:1234"; #[derive(Debug, Parser)] pub struct Cli { #[arg(long)] - /// Control plane endpoint address + /// Control plane endpoint address (IP, or wss://host, http://host) pub endpoint: Option, #[arg(long)] @@ -40,7 +40,7 @@ pub struct Cli { /// which agents are on shared networks, and for /// external-to-external connections #[arg(long)] - pub external: bool, + pub external: Option, #[clap(long = "bind", default_value_t = IpAddr::V4(Ipv4Addr::UNSPECIFIED))] pub bind_addr: IpAddr, @@ -84,13 +84,26 @@ impl Cli { query.push_str(&format!("&labels={}", labels.join(","))); } + let (is_tls, host) = endpoint + .split_once("://") + .map(|(left, right)| (left == "wss" || left == "https", right)) + .unwrap_or((false, endpoint.as_str())); + + let addr = format!("{host}{}", if host.contains(':') { "" } else { ":1234" }); + let ws_uri = Uri::builder() - .scheme("ws") - .authority(endpoint.to_string()) + .scheme(if is_tls { "wss" } else { "ws" }) + .authority(addr.to_owned()) .path_and_query(query) .build() .unwrap(); - (endpoint.to_string(), ws_uri) + ( + format!( + "{proto}://{addr}", + proto = if is_tls { "https" } else { "http" }, + ), + ws_uri, + ) } } diff --git a/crates/snops-agent/src/main.rs b/crates/snops-agent/src/main.rs index c92f6416..7731ed7c 100644 --- a/crates/snops-agent/src/main.rs +++ b/crates/snops-agent/src/main.rs @@ -13,7 +13,7 @@ use std::{ use clap::Parser; use cli::Cli; -use futures::{executor::block_on, SinkExt}; +use futures::SinkExt; use futures_util::stream::{FuturesUnordered, StreamExt}; use http::HeaderValue; use snops_common::{ @@ -29,7 +29,7 @@ use tokio_tungstenite::{ connect_async, tungstenite::{self, client::IntoClientRequest}, }; -use tracing::{error, info, level_filters::LevelFilter, warn}; +use tracing::{error, info, level_filters::LevelFilter}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use crate::rpc::{AgentRpcServer, MuxedMessageIncoming, MuxedMessageOutgoing, JWT_FILE}; @@ -74,20 +74,16 @@ async fn main() { // get the network interfaces available to this node let internal_addrs = net::get_internal_addrs().expect("failed to get network interfaces"); - let external_addr = args - .external - .then(|| block_on(net::get_external_addr())) - .flatten(); + let external_addr = args.external; if let Some(addr) = external_addr { info!("using external addr: {}", addr); - } else if args.external { - warn!("failed to get external address"); } else { info!("skipping external addr"); } // get the endpoint let (endpoint, ws_uri) = args.endpoint_and_uri(); + info!("connecting to {endpoint}"); // create the data directory tokio::fs::create_dir_all(&args.path) @@ -260,6 +256,7 @@ async fn main() { } } + state.node_graceful_shutdown().await; info!("snops agent has shut down gracefully :)"); } diff --git a/crates/snops-agent/src/net.rs b/crates/snops-agent/src/net.rs index f155bb1d..fb931d7a 100644 --- a/crates/snops-agent/src/net.rs +++ b/crates/snops-agent/src/net.rs @@ -30,17 +30,3 @@ pub fn get_internal_addrs() -> Result> { }) .collect()) } - -pub async fn get_external_addr() -> Option { - // default behavior of the external_ip::get_ip function uses - // dns sources, which have given me addresses that resolve to - // networks that are not mine... - - let sources: external_ip::Sources = external_ip::get_http_sources(); - let consensus = external_ip::ConsensusBuilder::new() - .add_sources(sources) - .build(); - consensus.get_consensus().await -} -// 172.253.198.135 -// 172.217.38.175 diff --git a/crates/snops-agent/src/reconcile.rs b/crates/snops-agent/src/reconcile.rs index 7bdf0cd1..661b3e0d 100644 --- a/crates/snops-agent/src/reconcile.rs +++ b/crates/snops-agent/src/reconcile.rs @@ -36,13 +36,9 @@ pub async fn check_files( // TODO: store binary based on binary id // download the snarkOS binary - api::check_binary( - env_id, - &format!("http://{}", &state.endpoint), - &base_path.join(SNARKOS_FILE), - ) // TODO: http(s)? - .await - .expect("failed to acquire snarkOS binary"); + api::check_binary(env_id, &state.endpoint, &base_path.join(SNARKOS_FILE)) // TODO: http(s)? + .await + .expect("failed to acquire snarkOS binary"); let version_file = storage_path.join(VERSION_FILE); @@ -58,12 +54,12 @@ pub async fn check_files( let genesis_path = storage_path.join(SNARKOS_GENESIS_FILE); let genesis_url = format!( - "http://{}/content/storage/{storage_id}/{SNARKOS_GENESIS_FILE}", + "{}/content/storage/{storage_id}/{SNARKOS_GENESIS_FILE}", &state.endpoint ); let ledger_path = storage_path.join(LEDGER_STORAGE_FILE); let ledger_url = format!( - "http://{}/content/storage/{storage_id}/{LEDGER_STORAGE_FILE}", + "{}/content/storage/{storage_id}/{LEDGER_STORAGE_FILE}", &state.endpoint ); @@ -294,7 +290,7 @@ impl<'a> CheckpointSource<'a> { meta.height, meta.timestamp ); let checkpoint_url = format!( - "http://{}/content/storage/{storage_id}/{}", + "{}/content/storage/{storage_id}/{}", &state.endpoint, meta.filename ); let path = storage_path.join(&meta.filename); diff --git a/crates/snops-agent/src/rpc.rs b/crates/snops-agent/src/rpc.rs index 3a7542aa..744c2c08 100644 --- a/crates/snops-agent/src/rpc.rs +++ b/crates/snops-agent/src/rpc.rs @@ -1,6 +1,4 @@ -use std::{ - collections::HashSet, net::IpAddr, ops::Deref, process::Stdio, sync::Arc, time::Duration, -}; +use std::{collections::HashSet, net::IpAddr, ops::Deref, process::Stdio, sync::Arc}; use snops_common::{ constant::{ @@ -18,7 +16,6 @@ use tarpc::{context, ClientMessage, Response}; use tokio::{ io::{AsyncBufReadExt, BufReader}, process::Command, - select, }; use tracing::{debug, error, info, trace, warn, Level}; @@ -27,8 +24,6 @@ use crate::{api, metrics::MetricComputer, reconcile, state::AppState}; /// The JWT file name. pub const JWT_FILE: &str = "jwt"; -pub const NODE_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(10); - /// A multiplexed message, incoming on the websocket. pub type MuxedMessageIncoming = MuxMessage, ClientMessage>; @@ -97,32 +92,7 @@ impl AgentService for AgentRpcServer { // kill existing child if running AgentState::Node(_, node) if node.online => { info!("cleaning up snarkos process..."); - - if let Some((mut child, id)) = - state.child.write().await.take().and_then(|ch| { - let id = ch.id()?; - Some((ch, id)) - }) - { - use nix::{ - sys::signal::{self, Signal}, - unistd::Pid, - }; - - // send SIGINT to the child process - signal::kill(Pid::from_raw(id as i32), Signal::SIGINT).unwrap(); - - // wait for graceful shutdown or kill process after 10 seconds - let timeout = tokio::time::sleep(NODE_GRACEFUL_SHUTDOWN_TIMEOUT); - - select! { - _ = child.wait() => (), - _ = timeout => { - info!("snarkos process did not gracefully shut down, killing..."); - child.kill().await.unwrap(); - } - } - } + state.node_graceful_shutdown().await; } _ => (), @@ -457,7 +427,7 @@ impl AgentService for AgentRpcServer { // download the snarkOS binary api::check_binary( env_id, - &format!("http://{}", &self.state.endpoint), + &self.state.endpoint, &self.state.cli.path.join(SNARKOS_FILE), ) // TODO: http(s)? .await @@ -471,7 +441,7 @@ impl AgentService for AgentRpcServer { .stderr(std::io::stderr()) .arg("execute") .arg("--query") - .arg(&format!("http://{}{query}", self.state.endpoint)) + .arg(&format!("{}{query}", self.state.endpoint)) .arg(auth) .spawn() .map_err(|e| { diff --git a/crates/snops-agent/src/state.rs b/crates/snops-agent/src/state.rs index 738e8616..01610f2a 100644 --- a/crates/snops-agent/src/state.rs +++ b/crates/snops-agent/src/state.rs @@ -2,6 +2,7 @@ use std::{ collections::HashMap, net::IpAddr, sync::{Arc, Mutex}, + time::Duration, }; use snops_common::{ @@ -11,12 +12,16 @@ use snops_common::{ }; use tokio::{ process::Child, + select, sync::{Mutex as AsyncMutex, RwLock}, task::AbortHandle, }; +use tracing::info; use crate::{api, cli::Cli, metrics::Metrics}; +pub const NODE_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(10); + pub type AppState = Arc; /// Global state for this agent runner. @@ -63,11 +68,8 @@ impl GlobalState { // if an else was used here, the lock would be held for the entire function so // we return early to prevent a deadlock - let info = api::get_storage_info(format!( - "http://{}/api/v1/env/{env_id}/storage", - &self.endpoint - )) - .await?; + let info = api::get_storage_info(format!("{}/api/v1/env/{env_id}/storage", &self.endpoint)) + .await?; self.env_to_storage .write() @@ -76,4 +78,31 @@ impl GlobalState { Ok(info) } + + /// Attempt to gracefully shutdown the node if one is running. + pub async fn node_graceful_shutdown(&self) { + if let Some((mut child, id)) = self.child.write().await.take().and_then(|ch| { + let id = ch.id()?; + Some((ch, id)) + }) { + use nix::{ + sys::signal::{self, Signal}, + unistd::Pid, + }; + + // send SIGINT to the child process + signal::kill(Pid::from_raw(id as i32), Signal::SIGINT).unwrap(); + + // wait for graceful shutdown or kill process after 10 seconds + let timeout = tokio::time::sleep(NODE_GRACEFUL_SHUTDOWN_TIMEOUT); + + select! { + _ = child.wait() => (), + _ = timeout => { + info!("snarkos process did not gracefully shut down, killing..."); + child.kill().await.unwrap(); + } + } + } + } } diff --git a/crates/snops/Cargo.toml b/crates/snops/Cargo.toml index 0c2ccfd7..2645e78f 100644 --- a/crates/snops/Cargo.toml +++ b/crates/snops/Cargo.toml @@ -19,7 +19,6 @@ chrono = { workspace = true, features = ["serde"] } clap.workspace = true dashmap = { workspace = true, features = ["serde"] } duration-str.workspace = true -external-ip.workspace = true fixedbitset.workspace = true futures-util.workspace = true hmac.workspace = true diff --git a/crates/snops/src/cannon/error.rs b/crates/snops/src/cannon/error.rs index 6c3c4d66..7847fbb6 100644 --- a/crates/snops/src/cannon/error.rs +++ b/crates/snops/src/cannon/error.rs @@ -144,8 +144,8 @@ pub enum ExecutionContextError { EnvDropped(Option, Option), #[error("no available agents `{0}` for exec ctx `{1}`")] NoAvailableAgents(&'static str, CannonId), - #[error("no --host configured for demox based cannon")] - NoDemoxHostConfigured, + #[error("no --hostname configured for demox based cannon")] + NoHostnameConfigured, #[error("tx drain `{2}` not found for exec ctx `{0}` for cannon `{1}`")] TransactionDrainNotFound(EnvId, CannonId, TxPipeId), #[error("tx sink `{2}` not found for exec ctx `{0}` for cannon `{1}`")] @@ -154,7 +154,7 @@ pub enum ExecutionContextError { impl_into_status_code!(ExecutionContextError, |value| match value { Broadcast(_, _) | BroadcastRequest(_, _) => StatusCode::MISDIRECTED_REQUEST, - NoAvailableAgents(_, _) | NoDemoxHostConfigured => StatusCode::SERVICE_UNAVAILABLE, + NoAvailableAgents(_, _) | NoHostnameConfigured => StatusCode::SERVICE_UNAVAILABLE, _ => StatusCode::INTERNAL_SERVER_ERROR, }); diff --git a/crates/snops/src/cannon/mod.rs b/crates/snops/src/cannon/mod.rs index 884f5e5f..ecb7a738 100644 --- a/crates/snops/src/cannon/mod.rs +++ b/crates/snops/src/cannon/mod.rs @@ -10,7 +10,7 @@ pub mod source; use std::{ path::PathBuf, process::Stdio, - sync::{atomic::AtomicUsize, Arc, OnceLock}, + sync::{atomic::AtomicUsize, Arc, Weak}, }; use futures_util::{stream::FuturesUnordered, StreamExt}; @@ -112,23 +112,6 @@ pub struct CannonInstance { tx_count: Option, } -#[tokio::main] -async fn get_external_ip() -> Option { - let sources: external_ip::Sources = external_ip::get_http_sources(); - let consensus = external_ip::ConsensusBuilder::new() - .add_sources(sources) - .build(); - consensus.get_consensus().await.map(|s| s.to_string()) -} - -async fn get_host(state: &GlobalState) -> Option { - static ONCE: OnceLock> = OnceLock::new(); - match state.cli.hostname.as_ref() { - Some(host) => Some(host.to_owned()), - None => ONCE.get_or_init(get_external_ip).to_owned(), - } -} - pub struct CannonReceivers { transactions: UnboundedReceiver, authorizations: UnboundedReceiver, @@ -373,10 +356,12 @@ impl ExecutionContext { ComputeTarget::Agent { .. } => suffix, // demox needs to locate it ComputeTarget::Demox { .. } => { - let host = get_host(state) - .await - .ok_or(ExecutionContextError::NoDemoxHostConfigured)?; - format!("http://{host}:{}{suffix}", state.cli.port) + let host = state + .cli + .hostname + .as_ref() + .ok_or(ExecutionContextError::NoHostnameConfigured)?; + format!("{host}:{}{suffix}", state.cli.port) } }; trace!("cannon {env_id}.{cannon_id} using realtime query {query}"); diff --git a/crates/snops/src/cli.rs b/crates/snops/src/cli.rs index 52902b0f..db4be337 100644 --- a/crates/snops/src/cli.rs +++ b/crates/snops/src/cli.rs @@ -20,6 +20,11 @@ pub struct Cli { pub path: PathBuf, #[arg(long)] + /// Hostname to advertise to the control plane, used when resolving the + /// control plane's address for external cannons can be an external IP + /// or FQDN, will have the port appended + /// + /// must contain http:// or https:// pub hostname: Option, }