From f7e09b6ac594e813668fdfdf15f1ddd6d0306c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oddbj=C3=B8rn=20Gr=C3=B8dem?= <29732646+oddgrd@users.noreply.github.com> Date: Tue, 25 Oct 2022 22:26:21 +0200 Subject: [PATCH] shuttle next wrapper POC (#431) * feat: runtime skeleton * feat: cleanup * feat: update cargo.lock, sort deps * fix: typo --- Cargo.lock | 76 +++++++++++++++++++++++----------- Cargo.toml | 1 + next/Cargo.toml | 24 +++++++++++ next/README.md | 9 ++++ next/src/args.rs | 8 ++++ next/src/error.rs | 12 ++++++ next/src/lib.rs | 2 + next/src/main.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 212 insertions(+), 23 deletions(-) create mode 100644 next/Cargo.toml create mode 100644 next/README.md create mode 100644 next/src/args.rs create mode 100644 next/src/error.rs create mode 100644 next/src/lib.rs create mode 100644 next/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 3dbbf2dd1..c97d70c0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,9 +396,9 @@ checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" [[package]] name = "async-trait" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2 1.0.43", "quote 1.0.21", @@ -1344,13 +1344,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.4" +version = "4.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f78ad8e84aa8e8aa3e821857be40eb4b925ff232de430d4dd2ae6aa058cbd92" +checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b" dependencies = [ "atty", "bitflags", - "clap_derive 4.0.1", + "clap_derive 4.0.18", "clap_lex 0.3.0", "once_cell", "strsim", @@ -1372,9 +1372,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.0.1" +version = "4.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca689d7434ce44517a12a89456b2be4d1ea1cafcd8f581978c03d45f5a5c12a7" +checksum = "16a1b0f6422af32d5da0c58e2703320f379216ee70198241c84173a8c5ac28f3" dependencies = [ "heck", "proc-macro-error", @@ -3525,6 +3525,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -3748,6 +3758,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking" version = "2.0.0" @@ -5336,7 +5352,7 @@ dependencies = [ "base64 0.13.0", "bollard", "chrono", - "clap 4.0.4", + "clap 4.0.18", "colored", "fqdn", "futures", @@ -5363,6 +5379,20 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "shuttle-next" +version = "0.1.0" +dependencies = [ + "async-trait", + "clap 4.0.18", + "shuttle-common", + "shuttle-service", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber", +] + [[package]] name = "shuttle-proto" version = "0.7.0" @@ -5503,9 +5533,9 @@ checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "smallvec" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smartstring" @@ -6063,18 +6093,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.32" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.32" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2 1.0.43", "quote 1.0.21", @@ -6553,9 +6583,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.36" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if 1.0.0", "log", @@ -6566,9 +6596,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2 1.0.43", "quote 1.0.21", @@ -6577,9 +6607,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", "valuable", @@ -6622,12 +6652,12 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" dependencies = [ - "ansi_term", "matchers", + "nu-ansi-term", "once_cell", "regex", "sharded-slab", diff --git a/Cargo.toml b/Cargo.toml index 0c2ad5836..2362b2f89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "common", "deployer", "gateway", + "next", "proto", "provisioner", "service" diff --git a/next/Cargo.toml b/next/Cargo.toml new file mode 100644 index 000000000..2f913a919 --- /dev/null +++ b/next/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "shuttle-next" +version = "0.1.0" +edition = "2021" +publish = false +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait = "0.1.58" +clap ={ version = "4.0.18", features = ["derive"] } +thiserror = "1.0.37" +tokio = { version = "=1.20.1", features = ["full"] } +tracing = "0.1.37" +tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } + +[dependencies.shuttle-common] +version = "0.7.0" +path = "../common" + +[dependencies.shuttle-service] +version = "0.7.0" +default-features = false +features = ["loader"] +path = "../service" diff --git a/next/README.md b/next/README.md new file mode 100644 index 000000000..3a9c2cabe --- /dev/null +++ b/next/README.md @@ -0,0 +1,9 @@ +## shuttle-next runtime-wrapper + +Load and run an .so library that implements `shuttle_service::Service`. + +To load and run, pass the path to the .so file to load as an argument to the shuttle-next binary: + +```bash +cargo run -- -f "src/libhello_world.so" +``` diff --git a/next/src/args.rs b/next/src/args.rs new file mode 100644 index 000000000..e435a3b2b --- /dev/null +++ b/next/src/args.rs @@ -0,0 +1,8 @@ +use clap::Parser; + +#[derive(Parser, Debug)] +pub struct Args { + /// Uri to the `.so` file to load + #[arg(long, short)] + pub file_path: String, +} diff --git a/next/src/error.rs b/next/src/error.rs new file mode 100644 index 000000000..919dab37d --- /dev/null +++ b/next/src/error.rs @@ -0,0 +1,12 @@ +use shuttle_service::loader::LoaderError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("Load error: {0}")] + Load(#[from] LoaderError), + #[error("Run error: {0}")] + Run(#[from] shuttle_service::Error), +} + +pub type Result = std::result::Result; diff --git a/next/src/lib.rs b/next/src/lib.rs new file mode 100644 index 000000000..177d34b24 --- /dev/null +++ b/next/src/lib.rs @@ -0,0 +1,2 @@ +pub mod args; +pub mod error; diff --git a/next/src/main.rs b/next/src/main.rs new file mode 100644 index 000000000..a29754bc9 --- /dev/null +++ b/next/src/main.rs @@ -0,0 +1,103 @@ +use std::{collections::BTreeMap, net::SocketAddr, path::PathBuf, str::FromStr}; + +use async_trait::async_trait; +use clap::Parser; +use shuttle_common::{database, LogItem}; +use shuttle_next::args::Args; +use shuttle_service::{ + loader::{LoadedService, Loader}, + Factory, Logger, ServiceName, +}; +use tokio::sync::mpsc::{self, UnboundedReceiver}; +use tracing::{info, instrument, trace}; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + let args = Args::parse(); + + let fmt_layer = fmt::layer(); + let filter_layer = EnvFilter::try_from_default_env() + .or_else(|_| EnvFilter::try_new("info")) + .unwrap(); + + tracing_subscriber::registry() + .with(filter_layer) + .with(fmt_layer) + .init(); + + trace!(args = ?args, "parsed args"); + + let address: SocketAddr = "127.0.0.1:8000".parse().unwrap(); + let mut factory = DummyFactory::new(); + let (logger, _rx) = get_logger(); + let so_path = PathBuf::from(args.file_path.as_str()); + + let service = load_service(address, so_path, &mut factory, logger) + .await + .unwrap(); + + _ = tokio::spawn(run(service, address)).await; +} + +#[instrument(skip(service))] +async fn run(service: LoadedService, addr: SocketAddr) { + let (handle, library) = service; + + info!("starting deployment on {}", addr); + handle.await.unwrap().unwrap(); + + tokio::spawn(async move { + trace!("closing .so file"); + library.close().unwrap(); + }); +} + +#[instrument(skip(addr, so_path, factory, logger))] +async fn load_service( + addr: SocketAddr, + so_path: PathBuf, + factory: &mut dyn Factory, + logger: Logger, +) -> shuttle_next::error::Result { + let loader = Loader::from_so_file(so_path)?; + + Ok(loader.load(factory, addr, logger).await?) +} + +struct DummyFactory { + service_name: ServiceName, +} + +impl DummyFactory { + fn new() -> Self { + Self { + service_name: ServiceName::from_str("next").unwrap(), + } + } +} + +#[async_trait] +impl Factory for DummyFactory { + fn get_service_name(&self) -> ServiceName { + self.service_name.clone() + } + + async fn get_db_connection_string( + &mut self, + _: database::Type, + ) -> Result { + todo!() + } + + async fn get_secrets(&mut self) -> Result, shuttle_service::Error> { + todo!() + } +} + +fn get_logger() -> (Logger, UnboundedReceiver) { + let (tx, rx) = mpsc::unbounded_channel(); + let logger = Logger::new(tx, Default::default()); + + (logger, rx) +}