From 39c931a294b61ccf1b50c738f72b092fb6cf0be7 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Thu, 7 Mar 2024 23:33:48 +0100 Subject: [PATCH 01/16] refactor: move secrets and metadata plugins to runtime --- cargo-shuttle/src/lib.rs | 3 +- codegen/src/lib.rs | 2 +- common/src/resource.rs | 4 +- common/src/secrets.rs | 2 +- resources/metadata/Cargo.toml | 2 - resources/metadata/README.md | 21 +-- resources/metadata/src/lib.rs | 15 -- resources/secrets/Cargo.toml | 3 - resources/secrets/README.md | 31 +--- resources/secrets/src/lib.rs | 24 --- runtime/README.md | 96 ++++++++++-- runtime/src/alpha.rs | 27 +--- runtime/src/lib.rs | 287 ++++++++++------------------------ service/src/lib.rs | 2 +- 14 files changed, 185 insertions(+), 334 deletions(-) diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index eca66eb3dc..7409f0e382 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -448,7 +448,8 @@ impl Shuttle { } else { get_templates_schema() .await - .map_err(|_| { + .map_err(|e| { + error!(err = %e, "Failed to get templates"); println!( "{}", "Failed to look up template list. Falling back to internal list." diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 9935ad3adb..7072046057 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -26,7 +26,7 @@ mod shuttle_main; /// | `ShuttlePoem` | [shuttle-poem](https://crates.io/crates/shuttle-poem) | [poem](https://docs.rs/poem/2.0) | 2.0 | [GitHub](https://github.com/shuttle-hq/shuttle-examples/tree/main/poem/hello-world) | /// | `ShuttleRocket` | [shuttle-rocket](https://crates.io/crates/shuttle-rocket) | [rocket](https://docs.rs/rocket/0.5) | 0.5 | [GitHub](https://github.com/shuttle-hq/shuttle-examples/tree/main/rocket/hello-world) | /// | `ShuttleSalvo` | [shuttle-salvo](https://crates.io/crates/shuttle-salvo) | [salvo](https://docs.rs/salvo/0.63) | 0.63 | [GitHub](https://github.com/shuttle-hq/shuttle-examples/tree/main/salvo/hello-world) | -/// | `ShuttleSerenity` | [shuttle-serenity](https://crates.io/crates/shuttle-serenity | [serenity](https://docs.rs/serenity/0.12) and [poise](https://docs.rs/poise/0.6) | 0.12 | [GitHub](https://github.com/shuttle-hq/shuttle-examples/tree/main/serenity/hello-world) | +/// | `ShuttleSerenity` | [shuttle-serenity](https://crates.io/crates/shuttle-serenity) | [serenity](https://docs.rs/serenity/0.12) and [poise](https://docs.rs/poise/0.6) | 0.12 | [GitHub](https://github.com/shuttle-hq/shuttle-examples/tree/main/serenity/hello-world) | /// | `ShuttleThruster` | [shuttle-thruster](https://crates.io/crates/shuttle-thruster) | [thruster](https://docs.rs/thruster/1.3) | 1.3 | [GitHub](https://github.com/shuttle-hq/shuttle-examples/tree/main/thruster/hello-world) | /// | `ShuttleTower` | [shuttle-tower](https://crates.io/crates/shuttle-tower) | [tower](https://docs.rs/tower/0.4) | 0.4 | [GitHub](https://github.com/shuttle-hq/shuttle-examples/tree/main/tower/hello-world) | /// | `ShuttleTide` | [shuttle-tide](https://crates.io/crates/shuttle-tide) | [tide](https://docs.rs/tide/0.16) | 0.16 | [GitHub](https://github.com/shuttle-hq/shuttle-examples/tree/main/tide/hello-world) | diff --git a/common/src/resource.rs b/common/src/resource.rs index b2d7b9c9bb..53931733e7 100644 --- a/common/src/resource.rs +++ b/common/src/resource.rs @@ -56,10 +56,10 @@ pub struct Response { /// The type of this resource. pub r#type: Type, - /// The config used when creating this resource. Use the [Self::r#type] to know how to parse this data. + /// The config used when creating this resource. Use the `r#type` to know how to parse this data. pub config: Value, - /// The data associated with this resource. Use the [Self::r#type] to know how to parse this data. + /// The data associated with this resource. Use the `r#type` to know how to parse this data. pub data: Value, } diff --git a/common/src/secrets.rs b/common/src/secrets.rs index 7ce4684b97..e90c4c7512 100644 --- a/common/src/secrets.rs +++ b/common/src/secrets.rs @@ -4,7 +4,7 @@ use zeroize::Zeroize; /// Wrapper type for secret values such as passwords or authentication keys. /// -/// Once wrapped, the inner value cannot leak accidentally, as both the [`Display`] and [`Debug`] +/// Once wrapped, the inner value cannot leak accidentally, as both the [`std::fmt::Display`] and [`Debug`] /// implementations cover up the actual value and only show the type. /// /// If you need access to the inner value, there is an [expose](`Secret::expose`) method. diff --git a/resources/metadata/Cargo.toml b/resources/metadata/Cargo.toml index fbaaf4e7a4..d291263e0b 100644 --- a/resources/metadata/Cargo.toml +++ b/resources/metadata/Cargo.toml @@ -7,5 +7,3 @@ description = "Plugin to get Shuttle service information" keywords = ["shuttle-service", "metadata"] [dependencies] -async-trait = "0.1.56" -shuttle-service = { path = "../../service", version = "0.41.0" } diff --git a/resources/metadata/README.md b/resources/metadata/README.md index 171af2863d..566d836650 100644 --- a/resources/metadata/README.md +++ b/resources/metadata/README.md @@ -1,22 +1,3 @@ # Shuttle Metadata -This plugin allows applications to obtain certain information about their runtime environment. - -## Usage - -Add `shuttle-metadata` to the dependencies for your service. - -You can get this resource using the `shuttle_metadata::ShuttleMetadata` attribute to get a `Metadata`. This struct will contain information such as the Shuttle service name. - -```rust -#[shuttle_runtime::main] -async fn app( - #[shuttle_metadata::ShuttleMetadata] metadata: shuttle_metadata::Metadata, -) -> __ { ... } -``` - -#### Example projects that use `shuttle-metadata` - -| Framework | Link | -| --------- | -------------------------------------------------------------------------------------- | -| Axum | [axum example](https://github.com/shuttle-hq/shuttle-examples/tree/main/axum/metadata) | +This plugin has been moved to [shuttle-runtime](https://crates.io/crates/shuttle-runtime). diff --git a/resources/metadata/src/lib.rs b/resources/metadata/src/lib.rs index e612e08e27..8b13789179 100644 --- a/resources/metadata/src/lib.rs +++ b/resources/metadata/src/lib.rs @@ -1,16 +1 @@ -use async_trait::async_trait; -pub use shuttle_service::{DeploymentMetadata as Metadata, Environment, SecretStore}; -use shuttle_service::{Error, ResourceFactory, ResourceInputBuilder}; -#[derive(Default)] -pub struct ShuttleMetadata; - -#[async_trait] -impl ResourceInputBuilder for ShuttleMetadata { - type Input = Metadata; - type Output = Metadata; - - async fn build(self, factory: &ResourceFactory) -> Result { - Ok(factory.get_metadata()) - } -} diff --git a/resources/secrets/Cargo.toml b/resources/secrets/Cargo.toml index 22223b9b4e..fe2bf04c5c 100644 --- a/resources/secrets/Cargo.toml +++ b/resources/secrets/Cargo.toml @@ -7,6 +7,3 @@ description = "Plugin to for managing secrets on shuttle" keywords = ["shuttle-service", "secrets"] [dependencies] -async-trait = "0.1.56" -serde_json = "1" -shuttle-service = { path = "../../service", version = "0.41.0" } diff --git a/resources/secrets/README.md b/resources/secrets/README.md index 9164d92df6..09b60280fe 100644 --- a/resources/secrets/README.md +++ b/resources/secrets/README.md @@ -1,32 +1,3 @@ # Shuttle Secrets -This plugin manages secrets on [Shuttle](https://www.shuttle.rs). - -## Usage - -Add `shuttle-secrets` to the dependencies for your service, and add a `Secrets.toml` to the root of your project -with the secrets you'd like to store. Make sure to add `Secrets*.toml` to a `.gitignore` to omit your secrets from version control. - -Next, pass `#[shuttle_secrets::Secrets] secret_store: SecretStore` as an argument to your `shuttle_service::main` function. -`SecretStore::get` can now be called to retrieve your API keys and other secrets at runtime. - -## Example - -```rust,ignore -#[shuttle_runtime::main] -async fn rocket( - #[shuttle_secrets::Secrets] secret_store: SecretStore, -) -> ShuttleRocket { - // get secret defined in `Secrets.toml` file. - let secret = if let Some(secret) = secret_store.get("MY_API_KEY") { - secret - } else { - return Err(anyhow!("secret was not found").into()); - }; - - let state = MyState { secret }; - let rocket = rocket::build().mount("/", routes![secret]).manage(state); - - Ok(rocket.into()) -} -``` +This plugin has been moved to [shuttle-runtime](https://crates.io/crates/shuttle-runtime). diff --git a/resources/secrets/src/lib.rs b/resources/secrets/src/lib.rs index 44d3b20ddc..8b13789179 100644 --- a/resources/secrets/src/lib.rs +++ b/resources/secrets/src/lib.rs @@ -1,25 +1 @@ -#![doc = include_str!("../README.md")] -use async_trait::async_trait; -pub use shuttle_service::SecretStore; -use shuttle_service::{ - resource::{ProvisionResourceRequest, ShuttleResourceOutput, Type}, - Error, ResourceFactory, ResourceInputBuilder, -}; -/// Secrets plugin that provides service secrets -#[derive(Default)] -pub struct Secrets; - -#[async_trait] -impl ResourceInputBuilder for Secrets { - type Input = ProvisionResourceRequest; - type Output = ShuttleResourceOutput; - - async fn build(self, _factory: &ResourceFactory) -> Result { - Ok(ProvisionResourceRequest::new( - Type::Secrets, - serde_json::Value::Null, - serde_json::Value::Null, - )) - } -} diff --git a/runtime/README.md b/runtime/README.md index 07cc9d24b2..f06b4d3007 100644 --- a/runtime/README.md +++ b/runtime/README.md @@ -1,15 +1,93 @@ -# shuttle-runtime +# Shuttle - Deploy Rust apps with a single Cargo subcommand -[Shuttle](https://www.shuttle.rs/) is a Rust-native cloud development platform that lets you deploy your Rust apps for free. - -Shuttle is built for productivity, reliability and performance: +
+ +
-- Zero-Configuration support for Rust using annotations -- Automatic resource provisioning (databases, caches, subdomains, etc.) via [Infrastructure-From-Code](https://www.shuttle.rs/blog/2022/05/09/ifc) -- First-class support for popular Rust frameworks ([Actix Web](https://docs.shuttle.rs/examples/actix), [Rocket](https://docs.shuttle.rs/examples/rocket), [Axum](https://docs.shuttle.rs/examples/axum), and [more](https://docs.shuttle.rs/examples/other)) -- Support for deploying Discord bots using [Serenity](https://docs.shuttle.rs/examples/serenity) -- Scalable hosting (with optional self-hosting in the future) +[Shuttle](https://www.shuttle.rs/) is a Rust-native cloud development platform that lets you deploy your Rust apps for free. 📖 Check out our documentation to get started quickly: [docs.shuttle.rs](https://docs.shuttle.rs) 🙋‍♂️ If you have any questions, join our [Discord](https://discord.gg/shuttle) server. + +## Usage + +Start by installing the [`cargo shuttle`](https://docs.rs/crate/cargo-shuttle/latest) subcommand by running the following in a terminal: + +```bash +cargo install cargo-shuttle +``` + +Now that Shuttle is installed, you can initialize a project with Axum boilerplate: + +```bash +cargo shuttle init --template axum my-axum-app +``` + +By looking at the `Cargo.toml` file of the generated `my-axum-app` project you will see it has been made to +be a binary crate with a few dependencies including `shuttle-runtime` and `shuttle-axum`. + +```toml +axum = "0.7.3" +shuttle-axum = "0.41.0" +shuttle-runtime = "0.41.0" +tokio = "1.28.2" +``` + +A boilerplate code for your axum project can also be found in `src/main.rs`: + +```rust,no_run +use axum::{routing::get, Router}; + +async fn hello_world() -> &'static str { + "Hello, world!" +} + +#[shuttle_runtime::main] +async fn main() -> shuttle_axum::ShuttleAxum { + let router = Router::new().route("/", get(hello_world)); + + Ok(router.into()) +} +``` + +Check out [our docs](https://docs.shuttle.rs/introduction/welcome) to see all the frameworks we support, or +our [examples](https://github.com/shuttle-hq/shuttle-examples) if you prefer that format. + +## Running locally + +To test your app locally before deploying, use: + +```bash +cargo shuttle run +``` + +You should see your app build and start on the default port 8000. You can test this using; + +```bash +curl http://localhost:8000/ +# Hello, world! +``` + +## Deploying + +Before you can deploy, you have to create a project. This will start a deployer container for your +project under the hood, ensuring isolation from other users' projects. PS. you don't have to do this +now if you did in in the `cargo shuttle init` flow. + +```bash +cargo shuttle project start +``` + +Then, deploy the service with: + +```bash +cargo shuttle deploy +``` + +Your service will immediately be available at `https://{project_name}.shuttleapp.rs/`. For example: + +```bash +curl https://my-axum-app.shuttleapp.rs/ +# Hello, world! +``` diff --git a/runtime/src/alpha.rs b/runtime/src/alpha.rs index 51c5938781..0675b55f50 100644 --- a/runtime/src/alpha.rs +++ b/runtime/src/alpha.rs @@ -25,9 +25,8 @@ use tokio::sync::{ use tokio_stream::wrappers::ReceiverStream; use tonic::{transport::Server, Request, Response, Status}; -use crate::__internals::print_version; - use crate::args::args; +use crate::print_version; // uses custom macro instead of clap to reduce dependency weight args! { @@ -49,17 +48,14 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S Ok(args) => args, Err(e) => { eprintln!("Runtime received malformed or incorrect args, {e}"); - let help_str = "[HINT]: Run shuttle with `cargo shuttle run`"; + let help_str = "[HINT]: Run your Shuttle app with `cargo shuttle run`"; let wrapper_str = "-".repeat(help_str.len()); eprintln!("{wrapper_str}\n{help_str}\n{wrapper_str}"); return; } }; - println!( - "shuttle-runtime executable started (version {})", - crate::VERSION - ); + println!("{} {} executable started", crate::NAME, crate::VERSION); // this is handled after arg parsing to not interfere with --version above #[cfg(feature = "setup-tracing")] @@ -81,21 +77,10 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S .init(); println!( - "{}\n\ - {}\n\ - To disable the subscriber and use your own,\n\ - turn off the default features for {}:\n\ - \n\ - {}\n\ - {}", - "=".repeat(63).yellow(), - "Shuttle's default tracing subscriber is initialized!" - .yellow() - .bold(), - "shuttle-runtime".italic(), - r#"shuttle-runtime = { version = "...", default-features = false }"#.italic(), - "=".repeat(63).yellow(), + "{}", + "Shuttle's default tracing subscriber is initialized!".yellow(), ); + println!("To disable it and use your own, check the docs: https://docs.shuttle.rs/configuration/logs"); } // where to serve the gRPC control layer diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 4ef3567a1e..babcfe53f4 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -1,212 +1,14 @@ +#![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/shuttle-hq/shuttle/main/assets/logo-square-transparent.png", html_favicon_url = "https://raw.githubusercontent.com/shuttle-hq/shuttle/main/assets/favicon.ico" )] -//! # Shuttle - Deploy Rust apps with a single Cargo subcommand -//!
-//! -//!
-//! -//! Hello, and welcome to the shuttle API documentation! -//! -//! Shuttle is an open-source app platform that uses traits and annotations to configure your backend deployments. -//! -//! ## Usage -//! Start by installing the [`cargo shuttle`](https://docs.rs/crate/cargo-shuttle/latest) subcommand by running the following in a terminal: -//! -//! ```bash -//! $ cargo install cargo-shuttle -//! ``` -//! -//! Now that shuttle is installed, you can initialize a project with Axum boilerplate: -//! ```bash -//! $ cargo shuttle init --template axum my-axum-app -//! ``` -//! -//! By looking at the `Cargo.toml` file of the generated `my-axum-app` project you will see it has been made to -//! be a binary crate with a few dependencies including `shuttle-runtime` and `shuttle-axum`. -//! -//! ```toml -//! axum = "0.7.3" -//! shuttle-axum = "0.41.0" -//! shuttle-runtime = "0.41.0" -//! tokio = "1.28.2" -//! ``` -//! -//! A boilerplate code for your axum project can also be found in `src/main.rs`: -//! -//! ```rust,no_run -//! use axum::{routing::get, Router}; -//! -//! async fn hello_world() -> &'static str { -//! "Hello, world!" -//! } -//! -//! #[shuttle_runtime::main] -//! async fn main() -> shuttle_axum::ShuttleAxum { -//! let router = Router::new().route("/", get(hello_world)); -//! -//! Ok(router.into()) -//! } -//! ``` -//! -//! Check out [our docs](https://docs.shuttle.rs/introduction/welcome) to see all the frameworks we support, or -//! our [examples](https://github.com/shuttle-hq/shuttle-examples) if you prefer that format. -//! -//! ## Running locally -//! To test your app locally before deploying, use: -//! -//! ```bash -//! $ cargo shuttle run -//! ``` -//! -//! You should see your app build and start on the default port 8000. You can test this using; -//! -//! ```bash -//! $ curl http://localhost:8000/ -//! Hello, world! -//! ``` -//! -//! ## Deploying -//! -//! You can deploy your service with the [`cargo shuttle`](https://docs.rs/crate/cargo-shuttle/latest) subcommand too. -//! But, you will need to authenticate with the shuttle service first using: -//! -//! ```bash -//! $ cargo shuttle login -//! ``` -//! -//! This will open a browser window and prompt you to connect using your GitHub account. -//! -//! Before you can deploy, you have to create a project. This will start a deployer container for your -//! project under the hood, ensuring isolation from other users' projects. PS. you don't have to do this -//! now if you did in in the `cargo shuttle init` flow. -//! -//! ```bash -//! $ cargo shuttle project start -//! ``` -//! -//! Then, deploy the service with: -//! -//! ```bash -//! $ cargo shuttle deploy -//! ``` -//! -//! Your service will immediately be available at `{crate_name}.shuttleapp.rs`. For example: -//! -//! ```bash -//! $ curl https://my-axum-app.shuttleapp.rs/ -//! Hello, world! -//! ``` -//! -//! ## Using `sqlx` -//! -//! Here is a quick example to deploy a rocket service that uses a postgres database and [sqlx](http://docs.rs/sqlx): -//! -//! Initialize a project with Rocket boilerplate: -//! ```bash -//! $ cargo shuttle init --template rocket my-rocket-app -//! ``` -//! -//! Add `shuttle-shared-db` as a dependency with the `postgres` feature, and add `sqlx` as a dependency with the -//! `runtime-tokio-native-tls` and `postgres` features inside `Cargo.toml`: -//! -//! ```toml -//! shuttle-shared-db = { version = "0.41.0", features = ["postgres"] } -//! sqlx = "0.7.1" -//! ``` -//! -//! Now update the `#[shuttle_runtime::main]` function to take in a `PgPool`: -//! -//! ```rust,no_run -//! #[macro_use] -//! extern crate rocket; -//! -//! use rocket::State; -//! use sqlx::PgPool; -//! use shuttle_rocket::ShuttleRocket; -//! -//! struct MyState(PgPool); -//! -//! #[get("/")] -//! fn hello(state: &State) -> &'static str { -//! // Do things with `state.0`... -//! "Hello, Postgres!" -//! } -//! -//! #[shuttle_runtime::main] -//! async fn rocket(#[shuttle_shared_db::Postgres] pool: PgPool) -> ShuttleRocket { -//! let state = MyState(pool); -//! let rocket = rocket::build().manage(state).mount("/", routes![hello]); -//! -//! Ok(rocket.into()) -//! } -//! ``` -//! -//! For a local run, shuttle will automatically provision a Postgres instance inside a [Docker](https://www.docker.com/) container on your machine and connect it to the `PgPool`. -//! -//! For deploys, shuttle will provision a database for your application and connect it to the `PgPool` on your behalf. -//! -//! To learn more about shuttle managed resources, see our [resource docs](https://docs.shuttle.rs/resources/shuttle-shared-db). -//! -//! ## Configuration -//! -//! The `cargo shuttle` command can be customized by creating a `Shuttle.toml` in the same location as your `Cargo.toml`. -//! -//! ##### Change the name of your service -//! -//! To have your service deployed with a different name, add a `name` entry in the `Shuttle.toml`: -//! -//! ```toml -//! name = "hello-world" -//! ``` -//! -//! If the `name` key is not specified, the service's name will be the same as the crate's name. -//! -//! Alternatively, you can override the project name on the command-line, by passing the --name argument to any subcommand like so: -//! -//! ```bash -//! $ cargo shuttle deploy --name=$PROJECT_NAME -//! ``` -//! -//! ##### Using Podman instead of Docker -//! If you are using [Podman](https://podman.io/) instead of Docker, then `cargo shuttle run` will give -//! `got unexpected error while inspecting docker container: error trying to connect: No such file or directory` error. -//! -//! To fix this error you will need to expose a rootless socket for Podman first. This can be done using: -//! -//! ```bash -//! podman system service --time=0 unix:///tmp/podman.sock -//! ``` -//! -//! Now set the `DOCKER_HOST` environment variable to point to this socket using: -//! -//! ```bash -//! export DOCKER_HOST=unix:///tmp/podman.sock -//! ``` -//! -//! Now all `cargo shuttle run` commands will work against Podman. -//! -//! ## Getting API keys -//! -//! After you've installed the [cargo-shuttle](https://docs.rs/crate/cargo-shuttle/latest) command, run: -//! -//! ```bash -//! $ cargo shuttle login -//! ``` -//! -//! this will open a browser window and prompt you to connect using your GitHub account. -//! -//! ## Join Discord -//! -//! If you have any questions, [join our Discord server](https://discord.gg/shuttle). There's always someone on there that can help! -//! -//! You can also [open an issue or a discussion on GitHub](https://github.com/shuttle-hq/shuttle). // Public API pub use shuttle_codegen::main; pub use shuttle_service::{ - CustomError, DbInput, Error, IntoResource, ResourceFactory, ResourceInputBuilder, Service, + CustomError, DbInput, DeploymentMetadata, Error, IntoResource, ResourceFactory, + ResourceInputBuilder, SecretStore, Service, }; // Useful re-exports @@ -218,6 +20,9 @@ mod args; const NAME: &str = env!("CARGO_PKG_NAME"); const VERSION: &str = env!("CARGO_PKG_VERSION"); +fn print_version() { + println!("{} {}", crate::NAME, crate::VERSION); +} // Not part of public API #[doc(hidden)] @@ -233,9 +38,83 @@ pub mod __internals { pub use strfmt::strfmt; #[cfg(feature = "setup-tracing")] pub use tracing_subscriber; +} + +pub use plugins::*; +/// Built-in plugins +mod plugins { + use crate::async_trait; + use shuttle_service::{ + resource::{ProvisionResourceRequest, ShuttleResourceOutput, Type}, + DeploymentMetadata, Error, ResourceFactory, ResourceInputBuilder, SecretStore, + }; + + /// ## Shuttle Metadata + /// + /// Plugin for getting various metadata at runtime. + /// + /// ### Usage + /// + /// ```rust,ignore + /// #[shuttle_runtime::main] + /// async fn main( + /// #[shuttle_runtime::Metadata] metadata: DeploymentMetadata, + /// ) -> __ { ... } + #[derive(Default)] + pub struct Metadata; + + #[async_trait] + impl ResourceInputBuilder for Metadata { + type Input = DeploymentMetadata; + type Output = DeploymentMetadata; + + async fn build(self, factory: &ResourceFactory) -> Result { + Ok(factory.get_metadata()) + } + } + + /// ## Shuttle Secrets + /// + /// Plugin for getting secrets in your [Shuttle](https://www.shuttle.rs) service. + /// + /// ### Usage + /// + /// Add a `Secrets.toml` file to the root of your crate with the secrets you'd like to store. + /// Make sure to add `Secrets*.toml` to `.gitignore` to omit your secrets from version control. + /// + /// Next, add `#[shuttle_runtime::Secrets] secrets: SecretStore` as a parameter to your `shuttle_service::main` function. + /// `SecretStore::get` can now be called to retrieve your API keys and other secrets at runtime. + /// + /// ### Example + /// + /// ```rust,ignore + /// #[shuttle_runtime::main] + /// async fn main( + /// #[shuttle_runtime::Secrets] secrets: SecretStore + /// ) -> ShuttleAxum { + /// // get secret defined in `Secrets.toml` file. + /// let secret = secrets.get("MY_API_KEY").unwrap(); + /// + /// let router = Router::new() + /// .route("/", async move { format!("My secret is: {}", secret) }); + /// + /// Ok(router.into()) + /// } + /// ``` + #[derive(Default)] + pub struct Secrets; + + #[async_trait] + impl ResourceInputBuilder for Secrets { + type Input = ProvisionResourceRequest; + type Output = ShuttleResourceOutput; - // Print the version of the runtime. - pub fn print_version() { - println!("{} {}", crate::NAME, crate::VERSION); + async fn build(self, _factory: &ResourceFactory) -> Result { + Ok(ProvisionResourceRequest::new( + Type::Secrets, + serde_json::Value::Null, + serde_json::Value::Null, + )) + } } } diff --git a/service/src/lib.rs b/service/src/lib.rs index b7388e450f..c9c5b673cb 100644 --- a/service/src/lib.rs +++ b/service/src/lib.rs @@ -114,7 +114,7 @@ impl IntoResource for ShuttleResource /// The core trait of the Shuttle platform. Every service deployed to Shuttle needs to implement this trait. /// -/// An `Into` implementor is what is returned in the [`shuttle_runtime::main`] macro +/// An `Into` implementor is what is returned in the `shuttle_runtime::main` macro /// in order to run it on the Shuttle servers. #[async_trait] pub trait Service: Send { From 7442c24ecf787ae1fea3fe91338c10b98222eb34 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Fri, 8 Mar 2024 01:08:19 +0100 Subject: [PATCH 02/16] feat: impl config::Source for SecretStore --- Cargo.lock | 91 ++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + common/Cargo.toml | 1 + common/src/models/resource.rs | 2 +- common/src/secrets.rs | 53 ++++++++------------ deployer/src/deployment/run.rs | 2 +- 6 files changed, 116 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4953cbdbed..bea15b0301 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1195,6 +1195,18 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "config" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +dependencies = [ + "lazy_static", + "nom", + "pathdiff", + "serde", +] + [[package]] name = "console" version = "0.15.8" @@ -4011,6 +4023,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pbkdf2" version = "0.11.0" @@ -5210,6 +5228,7 @@ dependencies = [ "bytes", "chrono", "comfy-table", + "config", "crossterm 0.27.0", "headers", "http 0.2.12", @@ -7499,3 +7518,75 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[patch.unused]] +name = "shuttle-actix-web" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-aws-rds" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-axum" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-metadata" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-opendal" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-persist" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-poem" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-qdrant" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-rocket" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-salvo" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-secrets" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-serenity" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-shared-db" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-thruster" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-tide" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-tower" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-turso" +version = "0.41.0" + +[[patch.unused]] +name = "shuttle-warp" +version = "0.41.0" diff --git a/Cargo.toml b/Cargo.toml index 31e56698de..eb0eb73f20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ chrono = { version = "0.4.23", default-features = false } clap = { version = "4.2.7", features = ["derive"] } colored = "2.0.0" comfy-table = "6.2.0" +config = { version = "0.14.0", default-features = false } crossterm = "0.27.0" ctor = "0.2.5" dirs = "5.0.0" diff --git a/common/Cargo.toml b/common/Cargo.toml index 0099056abb..f123d4dbec 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -15,6 +15,7 @@ axum = { workspace = true, optional = true } bytes = { workspace = true, optional = true } chrono = { workspace = true } comfy-table = { workspace = true, optional = true } +config = { workspace = true } crossterm = { workspace = true, optional = true } headers = { workspace = true, optional = true } http = { workspace = true, optional = true } diff --git a/common/src/models/resource.rs b/common/src/models/resource.rs index 457f2fb461..972654ce64 100644 --- a/common/src/models/resource.rs +++ b/common/src/models/resource.rs @@ -155,7 +155,7 @@ fn get_secrets_table(secrets: &[&Response], service_name: &str, raw: bool) -> St let secrets = serde_json::from_value::(secrets[0].data.clone()).unwrap(); - for key in secrets.secrets.keys() { + for key in secrets.keys() { table.add_row(vec![key]); } diff --git a/common/src/secrets.rs b/common/src/secrets.rs index e90c4c7512..f37725b433 100644 --- a/common/src/secrets.rs +++ b/common/src/secrets.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use std::{collections::BTreeMap, fmt::Debug}; +use std::{collections::BTreeMap, fmt::Debug, ops::Deref}; use zeroize::Zeroize; /// Wrapper type for secret values such as passwords or authentication keys. @@ -49,32 +49,35 @@ impl Secret { } /// Store that holds all the secrets available to a deployment -#[derive(Deserialize, Serialize, Clone)] +#[derive(Deserialize, Serialize, Clone, Debug)] #[serde(transparent)] -pub struct SecretStore { - pub(crate) secrets: BTreeMap>, -} +pub struct SecretStore(pub BTreeMap); impl SecretStore { - pub fn new(secrets: BTreeMap>) -> Self { - Self { secrets } + pub fn get(&self, key: &str) -> Option { + self.0.get(key).map(|s| s.to_owned()) } +} - pub fn get(&self, key: &str) -> Option { - self.secrets.get(key).map(|s| s.expose().to_owned()) +impl Deref for SecretStore { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 } } -impl IntoIterator for SecretStore { - type Item = (String, String); - type IntoIter = as IntoIterator>::IntoIter; +impl config::Source for SecretStore { + fn clone_into_box(&self) -> Box { + Box::new(self.clone()) + } - fn into_iter(self) -> Self::IntoIter { - self.secrets - .into_iter() - .map(|(k, s)| (k, s.expose().to_owned())) - .collect::>() - .into_iter() + fn collect(&self) -> Result, config::ConfigError> { + let mut map: config::Map = config::Map::new(); + for (a, b) in self.iter() { + map.insert(a.clone(), b.clone().into()); + } + Ok(map) } } @@ -122,18 +125,4 @@ mod secrets_tests { "Wrapper { password: [REDACTED \"alloc::string::String\"] }" ); } - - #[test] - fn secretstore_intoiter() { - let bt = BTreeMap::from([ - ("1".to_owned(), "2".to_owned().into()), - ("3".to_owned(), "4".to_owned().into()), - ]); - let ss = SecretStore::new(bt); - - let mut iter = ss.into_iter(); - assert_eq!(iter.next(), Some(("1".to_owned(), "2".to_owned()))); - assert_eq!(iter.next(), Some(("3".to_owned(), "4".to_owned()))); - assert_eq!(iter.next(), None); - } } diff --git a/deployer/src/deployment/run.rs b/deployer/src/deployment/run.rs index 0ea9ec625d..546f50a3e0 100644 --- a/deployer/src/deployment/run.rs +++ b/deployer/src/deployment/run.rs @@ -309,7 +309,7 @@ impl Built { match serde_json::from_value::(r.data.clone()) { Ok(ss) => { // Combine old and new, but insert old first so that new ones override. - let mut combined = HashMap::from_iter(ss.into_iter()); + let mut combined = HashMap::from_iter(ss.0.into_iter()); combined.extend(new_secrets.clone().into_iter()); new_secrets = combined; } From 677132d18139c7488b7e398ff506e7ee2a26b430 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Fri, 8 Mar 2024 01:21:16 +0100 Subject: [PATCH 03/16] ci: skip crates --- .circleci/config.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4fec5ecb2c..ab9f9f9e0c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -631,10 +631,8 @@ workflows: parameters: path: - resources/aws-rds - - resources/metadata - resources/persist - resources/qdrant - - resources/secrets - resources/shared-db - resources/turso - resources/opendal From b2c880fe6582054ec4ffad459b1995f9f70c43a7 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Fri, 8 Mar 2024 01:24:19 +0100 Subject: [PATCH 04/16] fix lock --- Cargo.lock | 72 ------------------------------------------------------ 1 file changed, 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bea15b0301..9d288fcb9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7518,75 +7518,3 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" - -[[patch.unused]] -name = "shuttle-actix-web" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-aws-rds" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-axum" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-metadata" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-opendal" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-persist" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-poem" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-qdrant" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-rocket" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-salvo" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-secrets" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-serenity" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-shared-db" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-thruster" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-tide" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-tower" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-turso" -version = "0.41.0" - -[[patch.unused]] -name = "shuttle-warp" -version = "0.41.0" From 3b33c12035c9bb372ea0f7bf290b078cfcd75dda Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Fri, 8 Mar 2024 12:43:59 +0100 Subject: [PATCH 05/16] Revert "feat: impl config::Source for SecretStore" This reverts commit 7442c24ecf787ae1fea3fe91338c10b98222eb34. --- Cargo.lock | 19 ------------ Cargo.toml | 1 - common/Cargo.toml | 1 - common/src/models/resource.rs | 2 +- common/src/secrets.rs | 53 ++++++++++++++++++++-------------- deployer/src/deployment/run.rs | 2 +- 6 files changed, 34 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d288fcb9a..4953cbdbed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1195,18 +1195,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "config" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" -dependencies = [ - "lazy_static", - "nom", - "pathdiff", - "serde", -] - [[package]] name = "console" version = "0.15.8" @@ -4023,12 +4011,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - [[package]] name = "pbkdf2" version = "0.11.0" @@ -5228,7 +5210,6 @@ dependencies = [ "bytes", "chrono", "comfy-table", - "config", "crossterm 0.27.0", "headers", "http 0.2.12", diff --git a/Cargo.toml b/Cargo.toml index eb0eb73f20..31e56698de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,6 @@ chrono = { version = "0.4.23", default-features = false } clap = { version = "4.2.7", features = ["derive"] } colored = "2.0.0" comfy-table = "6.2.0" -config = { version = "0.14.0", default-features = false } crossterm = "0.27.0" ctor = "0.2.5" dirs = "5.0.0" diff --git a/common/Cargo.toml b/common/Cargo.toml index f123d4dbec..0099056abb 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -15,7 +15,6 @@ axum = { workspace = true, optional = true } bytes = { workspace = true, optional = true } chrono = { workspace = true } comfy-table = { workspace = true, optional = true } -config = { workspace = true } crossterm = { workspace = true, optional = true } headers = { workspace = true, optional = true } http = { workspace = true, optional = true } diff --git a/common/src/models/resource.rs b/common/src/models/resource.rs index 972654ce64..457f2fb461 100644 --- a/common/src/models/resource.rs +++ b/common/src/models/resource.rs @@ -155,7 +155,7 @@ fn get_secrets_table(secrets: &[&Response], service_name: &str, raw: bool) -> St let secrets = serde_json::from_value::(secrets[0].data.clone()).unwrap(); - for key in secrets.keys() { + for key in secrets.secrets.keys() { table.add_row(vec![key]); } diff --git a/common/src/secrets.rs b/common/src/secrets.rs index f37725b433..e90c4c7512 100644 --- a/common/src/secrets.rs +++ b/common/src/secrets.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use std::{collections::BTreeMap, fmt::Debug, ops::Deref}; +use std::{collections::BTreeMap, fmt::Debug}; use zeroize::Zeroize; /// Wrapper type for secret values such as passwords or authentication keys. @@ -49,35 +49,32 @@ impl Secret { } /// Store that holds all the secrets available to a deployment -#[derive(Deserialize, Serialize, Clone, Debug)] +#[derive(Deserialize, Serialize, Clone)] #[serde(transparent)] -pub struct SecretStore(pub BTreeMap); +pub struct SecretStore { + pub(crate) secrets: BTreeMap>, +} impl SecretStore { - pub fn get(&self, key: &str) -> Option { - self.0.get(key).map(|s| s.to_owned()) + pub fn new(secrets: BTreeMap>) -> Self { + Self { secrets } } -} -impl Deref for SecretStore { - type Target = BTreeMap; - - fn deref(&self) -> &Self::Target { - &self.0 + pub fn get(&self, key: &str) -> Option { + self.secrets.get(key).map(|s| s.expose().to_owned()) } } -impl config::Source for SecretStore { - fn clone_into_box(&self) -> Box { - Box::new(self.clone()) - } +impl IntoIterator for SecretStore { + type Item = (String, String); + type IntoIter = as IntoIterator>::IntoIter; - fn collect(&self) -> Result, config::ConfigError> { - let mut map: config::Map = config::Map::new(); - for (a, b) in self.iter() { - map.insert(a.clone(), b.clone().into()); - } - Ok(map) + fn into_iter(self) -> Self::IntoIter { + self.secrets + .into_iter() + .map(|(k, s)| (k, s.expose().to_owned())) + .collect::>() + .into_iter() } } @@ -125,4 +122,18 @@ mod secrets_tests { "Wrapper { password: [REDACTED \"alloc::string::String\"] }" ); } + + #[test] + fn secretstore_intoiter() { + let bt = BTreeMap::from([ + ("1".to_owned(), "2".to_owned().into()), + ("3".to_owned(), "4".to_owned().into()), + ]); + let ss = SecretStore::new(bt); + + let mut iter = ss.into_iter(); + assert_eq!(iter.next(), Some(("1".to_owned(), "2".to_owned()))); + assert_eq!(iter.next(), Some(("3".to_owned(), "4".to_owned()))); + assert_eq!(iter.next(), None); + } } diff --git a/deployer/src/deployment/run.rs b/deployer/src/deployment/run.rs index 546f50a3e0..0ea9ec625d 100644 --- a/deployer/src/deployment/run.rs +++ b/deployer/src/deployment/run.rs @@ -309,7 +309,7 @@ impl Built { match serde_json::from_value::(r.data.clone()) { Ok(ss) => { // Combine old and new, but insert old first so that new ones override. - let mut combined = HashMap::from_iter(ss.0.into_iter()); + let mut combined = HashMap::from_iter(ss.into_iter()); combined.extend(new_secrets.clone().into_iter()); new_secrets = combined; } From 90dd02fed67a28f6432e1c5ab5dd60b988bec50f Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Fri, 8 Mar 2024 12:55:28 +0100 Subject: [PATCH 06/16] fix docs --- services/shuttle-actix-web/README.md | 3 +-- services/shuttle-poem/README.md | 2 +- services/shuttle-rocket/README.md | 4 +--- services/shuttle-salvo/README.md | 3 +-- services/shuttle-serenity/README.md | 12 ++++-------- services/shuttle-thruster/README.md | 2 +- services/shuttle-tide/README.md | 2 +- services/shuttle-tower/README.md | 2 +- services/shuttle-warp/README.md | 2 +- 9 files changed, 12 insertions(+), 20 deletions(-) diff --git a/services/shuttle-actix-web/README.md b/services/shuttle-actix-web/README.md index 9176405e44..687e0365d4 100644 --- a/services/shuttle-actix-web/README.md +++ b/services/shuttle-actix-web/README.md @@ -1,4 +1,4 @@ -## Shuttle service integration for the Actix Web framework. +## Shuttle service integration for the Actix Web framework ### Example @@ -19,5 +19,4 @@ async fn actix_web() -> ShuttleActixWeb &'static str { "Hello, world!" @@ -18,5 +17,4 @@ async fn rocket() -> shuttle_rocket::ShuttleRocket { Ok(rocket.into()) } -# } ``` diff --git a/services/shuttle-salvo/README.md b/services/shuttle-salvo/README.md index d3c81e35cb..53bae0baa6 100644 --- a/services/shuttle-salvo/README.md +++ b/services/shuttle-salvo/README.md @@ -1,4 +1,4 @@ -## Shuttle service integration for the Salvo web framework. +## Shuttle service integration for the Salvo web framework ### Example @@ -16,5 +16,4 @@ async fn salvo() -> shuttle_salvo::ShuttleSalvo { Ok(router.into()) } - ``` diff --git a/services/shuttle-serenity/README.md b/services/shuttle-serenity/README.md index 8cb362c25e..bb02afd502 100644 --- a/services/shuttle-serenity/README.md +++ b/services/shuttle-serenity/README.md @@ -12,12 +12,12 @@ shuttle-serenity = { version = "0.41.0", default-features = false, features = [" ### Example ```rust,ignore -use anyhow::anyhow; +use anyhow::Context; use serenity::async_trait; use serenity::model::channel::Message; use serenity::model::gateway::Ready; use serenity::prelude::*; -use shuttle_secrets::SecretStore; +use shuttle_runtime::SecretStore; use tracing::{error, info}; struct Bot; @@ -39,14 +39,10 @@ impl EventHandler for Bot { #[shuttle_runtime::main] async fn serenity( - #[shuttle_secrets::Secrets] secret_store: SecretStore, + #[shuttle_runtime::Secrets] secrets: SecretStore, ) -> shuttle_serenity::ShuttleSerenity { // Get the discord token set in `Secrets.toml` - let token = if let Some(token) = secret_store.get("DISCORD_TOKEN") { - token - } else { - return Err(anyhow!("'DISCORD_TOKEN' was not found").into()); - }; + let token = secret_store.get("DISCORD_TOKEN").context("'DISCORD_TOKEN' was not found")?; // Set gateway intents, which decides what events the bot will be notified about let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT; diff --git a/services/shuttle-thruster/README.md b/services/shuttle-thruster/README.md index 699f928a0c..344d7027f9 100644 --- a/services/shuttle-thruster/README.md +++ b/services/shuttle-thruster/README.md @@ -1,4 +1,4 @@ -## Shuttle service integration for the Thruster web framework. +## Shuttle service integration for the Thruster web framework ### Example diff --git a/services/shuttle-tide/README.md b/services/shuttle-tide/README.md index 5b443fc3f1..e4c54235c8 100644 --- a/services/shuttle-tide/README.md +++ b/services/shuttle-tide/README.md @@ -1,4 +1,4 @@ -## Shuttle service integration for the Tide web framework. +## Shuttle service integration for the Tide web framework ### Example diff --git a/services/shuttle-tower/README.md b/services/shuttle-tower/README.md index 555f6efc01..c62a600e6c 100644 --- a/services/shuttle-tower/README.md +++ b/services/shuttle-tower/README.md @@ -1,4 +1,4 @@ -## Shuttle service integration for the Tower framework. +## Shuttle service integration for the Tower framework ### Example diff --git a/services/shuttle-warp/README.md b/services/shuttle-warp/README.md index d1184ebe83..ed060a2419 100644 --- a/services/shuttle-warp/README.md +++ b/services/shuttle-warp/README.md @@ -1,4 +1,4 @@ -## Shuttle service integration for the Warp web framework. +## Shuttle service integration for the Warp web framework ### Example From 2cbf62e215f681c4d24a186867321f8e63db2fbf Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Mon, 11 Mar 2024 13:47:00 +0100 Subject: [PATCH 07/16] fix: deprecation warnings --- resources/metadata/Cargo.toml | 2 ++ resources/metadata/src/lib.rs | 19 ++++++++++++++++++ resources/secrets/Cargo.toml | 3 +++ resources/secrets/src/lib.rs | 29 ++++++++++++++++++++++++++++ scripts/patches.toml | 2 -- services/shuttle-serenity/Cargo.toml | 3 +-- 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/resources/metadata/Cargo.toml b/resources/metadata/Cargo.toml index d291263e0b..4650539a05 100644 --- a/resources/metadata/Cargo.toml +++ b/resources/metadata/Cargo.toml @@ -7,3 +7,5 @@ description = "Plugin to get Shuttle service information" keywords = ["shuttle-service", "metadata"] [dependencies] +async-trait = "0.1.56" +shuttle-service = { path = "../../service", version = "<=0.44.0" } diff --git a/resources/metadata/src/lib.rs b/resources/metadata/src/lib.rs index 8b13789179..38ab9d1ede 100644 --- a/resources/metadata/src/lib.rs +++ b/resources/metadata/src/lib.rs @@ -1 +1,20 @@ +use async_trait::async_trait; +pub use shuttle_service::{DeploymentMetadata as Metadata, Environment, SecretStore}; +use shuttle_service::{Error, ResourceFactory, ResourceInputBuilder}; +#[derive(Default)] +#[deprecated( + since = "0.42.0", + note = "This plugin has been moved to shuttle_runtime::Metadata, see https://docs.shuttle.rs/resources/shuttle-metadata" +)] +pub struct ShuttleMetadata; + +#[async_trait] +impl ResourceInputBuilder for ShuttleMetadata { + type Input = Metadata; + type Output = Metadata; + + async fn build(self, factory: &ResourceFactory) -> Result { + Ok(factory.get_metadata()) + } +} diff --git a/resources/secrets/Cargo.toml b/resources/secrets/Cargo.toml index fe2bf04c5c..86b39f0040 100644 --- a/resources/secrets/Cargo.toml +++ b/resources/secrets/Cargo.toml @@ -7,3 +7,6 @@ description = "Plugin to for managing secrets on shuttle" keywords = ["shuttle-service", "secrets"] [dependencies] +async-trait = "0.1.56" +serde_json = "1" +shuttle-service = { path = "../../service", version = "<=0.44.0" } diff --git a/resources/secrets/src/lib.rs b/resources/secrets/src/lib.rs index 8b13789179..fb7725a643 100644 --- a/resources/secrets/src/lib.rs +++ b/resources/secrets/src/lib.rs @@ -1 +1,30 @@ +#![doc = include_str!("../README.md")] +use async_trait::async_trait; +pub use shuttle_service::SecretStore; +use shuttle_service::{ + resource::{ProvisionResourceRequest, ShuttleResourceOutput, Type}, + Error, ResourceFactory, ResourceInputBuilder, +}; + +/// Secrets plugin that provides service secrets +#[derive(Default)] +#[deprecated( + since = "0.42.0", + note = "This plugin has been moved to shuttle_runtime::Secrets, see https://docs.shuttle.rs/resources/shuttle-secrets" +)] +pub struct Secrets; + +#[async_trait] +impl ResourceInputBuilder for Secrets { + type Input = ProvisionResourceRequest; + type Output = ShuttleResourceOutput; + + async fn build(self, _factory: &ResourceFactory) -> Result { + Ok(ProvisionResourceRequest::new( + Type::Secrets, + serde_json::Value::Null, + serde_json::Value::Null, + )) + } +} diff --git a/scripts/patches.toml b/scripts/patches.toml index 0c9bc82073..b94c85fbaf 100644 --- a/scripts/patches.toml +++ b/scripts/patches.toml @@ -6,12 +6,10 @@ shuttle-runtime = { path = "BASE/runtime" } shuttle-service = { path = "BASE/service" } shuttle-aws-rds = { path = "BASE/resources/aws-rds" } -shuttle-metadata = { path = "BASE/resources/metadata" } shuttle-opendal = { path = "BASE/resources/opendal" } shuttle-persist = { path = "BASE/resources/persist" } shuttle-qdrant = { path = "BASE/resources/qdrant" } shuttle-shared-db = { path = "BASE/resources/shared-db" } -shuttle-secrets = { path = "BASE/resources/secrets" } shuttle-turso = { path = "BASE/resources/turso" } shuttle-axum = { path = "BASE/services/shuttle-axum" } diff --git a/services/shuttle-serenity/Cargo.toml b/services/shuttle-serenity/Cargo.toml index bcff870496..998066f19e 100644 --- a/services/shuttle-serenity/Cargo.toml +++ b/services/shuttle-serenity/Cargo.toml @@ -13,9 +13,8 @@ serenity = { version = "0.12", default-features = false, features = ["client", " serenity-0-11 = { package = "serenity", version = "0.11.7", default-features = false, features = ["client", "gateway", "model"], optional = true } shuttle-runtime = { path = "../../runtime", version = "0.41.0", default-features = false } -[dev-dependencies] +[dev-dependencies] # for building doctests anyhow = "1.0.69" -shuttle-secrets = { path = "../../resources/secrets" } tokio = { version = "1.26.0", features = ["macros", "rt-multi-thread"] } tracing = "0.1.37" From ea0e11eba5f5dfb791b55d2ffe86ea836f3dca80 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Mon, 11 Mar 2024 13:47:18 +0100 Subject: [PATCH 08/16] bump examples --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 7af5b42f94..1966c77d1c 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 7af5b42f944a386140df8fdfe045a12fc88657e5 +Subproject commit 1966c77d1c62a3a1ccfa7768f0124a1b5fb622f1 From a99ddc35050056244fca7af61980574f1226ed00 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Mon, 11 Mar 2024 13:48:28 +0100 Subject: [PATCH 09/16] fix --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index babcfe53f4..8aa8b58a89 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -96,7 +96,7 @@ mod plugins { /// let secret = secrets.get("MY_API_KEY").unwrap(); /// /// let router = Router::new() - /// .route("/", async move { format!("My secret is: {}", secret) }); + /// .route("/", || async move { format!("My secret is: {}", secret) }); /// /// Ok(router.into()) /// } From f262d1676c177586122c21738a4ddbcf15767b5c Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Mon, 11 Mar 2024 14:01:40 +0100 Subject: [PATCH 10/16] fix serenity --- examples | 2 +- services/shuttle-serenity/Cargo.toml | 2 +- services/shuttle-serenity/README.md | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples b/examples index 1966c77d1c..37001768a2 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 1966c77d1c62a3a1ccfa7768f0124a1b5fb622f1 +Subproject commit 37001768a2c5c23efe79a004f172196757d21062 diff --git a/services/shuttle-serenity/Cargo.toml b/services/shuttle-serenity/Cargo.toml index 998066f19e..4e29d11321 100644 --- a/services/shuttle-serenity/Cargo.toml +++ b/services/shuttle-serenity/Cargo.toml @@ -15,7 +15,7 @@ shuttle-runtime = { path = "../../runtime", version = "0.41.0", default-features [dev-dependencies] # for building doctests anyhow = "1.0.69" -tokio = { version = "1.26.0", features = ["macros", "rt-multi-thread"] } +tokio = "1.26.0" tracing = "0.1.37" [features] diff --git a/services/shuttle-serenity/README.md b/services/shuttle-serenity/README.md index bb02afd502..001c8b335b 100644 --- a/services/shuttle-serenity/README.md +++ b/services/shuttle-serenity/README.md @@ -11,8 +11,8 @@ shuttle-serenity = { version = "0.41.0", default-features = false, features = [" ### Example -```rust,ignore -use anyhow::Context; +```rust,no_run +use anyhow::Context as _; use serenity::async_trait; use serenity::model::channel::Message; use serenity::model::gateway::Ready; @@ -42,7 +42,7 @@ async fn serenity( #[shuttle_runtime::Secrets] secrets: SecretStore, ) -> shuttle_serenity::ShuttleSerenity { // Get the discord token set in `Secrets.toml` - let token = secret_store.get("DISCORD_TOKEN").context("'DISCORD_TOKEN' was not found")?; + let token = secrets.get("DISCORD_TOKEN").context("'DISCORD_TOKEN' was not found")?; // Set gateway intents, which decides what events the bot will be notified about let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT; From ea7acc1325e4ac0e671a7435898dc42468c89b61 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Mon, 11 Mar 2024 14:04:30 +0100 Subject: [PATCH 11/16] nit --- services/shuttle-serenity/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/shuttle-serenity/Cargo.toml b/services/shuttle-serenity/Cargo.toml index 4e29d11321..b2405879ca 100644 --- a/services/shuttle-serenity/Cargo.toml +++ b/services/shuttle-serenity/Cargo.toml @@ -13,9 +13,8 @@ serenity = { version = "0.12", default-features = false, features = ["client", " serenity-0-11 = { package = "serenity", version = "0.11.7", default-features = false, features = ["client", "gateway", "model"], optional = true } shuttle-runtime = { path = "../../runtime", version = "0.41.0", default-features = false } -[dev-dependencies] # for building doctests +[dev-dependencies] # for building doctest anyhow = "1.0.69" -tokio = "1.26.0" tracing = "0.1.37" [features] From 0a0b27869ca88aef20aa39d3f95f482abafa56be Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Mon, 11 Mar 2024 14:09:35 +0100 Subject: [PATCH 12/16] bump examples --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 37001768a2..77a3bf0a0e 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 37001768a2c5c23efe79a004f172196757d21062 +Subproject commit 77a3bf0a0e0ba0dccbd23c0ca04c4735a7a06f33 From 31c8c8022124a2ea7f06a599adb9aa10fca02667 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Mon, 11 Mar 2024 15:00:31 +0100 Subject: [PATCH 13/16] fix serenity --- services/shuttle-serenity/Cargo.toml | 4 ---- services/shuttle-serenity/README.md | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/services/shuttle-serenity/Cargo.toml b/services/shuttle-serenity/Cargo.toml index b2405879ca..3f2e03dce4 100644 --- a/services/shuttle-serenity/Cargo.toml +++ b/services/shuttle-serenity/Cargo.toml @@ -13,10 +13,6 @@ serenity = { version = "0.12", default-features = false, features = ["client", " serenity-0-11 = { package = "serenity", version = "0.11.7", default-features = false, features = ["client", "gateway", "model"], optional = true } shuttle-runtime = { path = "../../runtime", version = "0.41.0", default-features = false } -[dev-dependencies] # for building doctest -anyhow = "1.0.69" -tracing = "0.1.37" - [features] default = ["rustls_backend"] diff --git a/services/shuttle-serenity/README.md b/services/shuttle-serenity/README.md index 001c8b335b..ca7cab99db 100644 --- a/services/shuttle-serenity/README.md +++ b/services/shuttle-serenity/README.md @@ -11,7 +11,7 @@ shuttle-serenity = { version = "0.41.0", default-features = false, features = [" ### Example -```rust,no_run +```rust,ignore use anyhow::Context as _; use serenity::async_trait; use serenity::model::channel::Message; From 45c348a591e2ab7e32de7c443b776acc87545aa6 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Tue, 12 Mar 2024 10:56:31 +0100 Subject: [PATCH 14/16] fix rocket doc test --- services/shuttle-rocket/Cargo.toml | 2 +- services/shuttle-rocket/README.md | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/services/shuttle-rocket/Cargo.toml b/services/shuttle-rocket/Cargo.toml index 1a2cb8e8be..c4f8a66c98 100644 --- a/services/shuttle-rocket/Cargo.toml +++ b/services/shuttle-rocket/Cargo.toml @@ -9,7 +9,7 @@ keywords = ["shuttle-service", "rocket"] [workspace] [dependencies] -rocket = { version = "0.5.0" } +rocket = "0.5.0" shuttle-runtime = { path = "../../runtime", version = "0.41.0", default-features = false } [dev-dependencies] diff --git a/services/shuttle-rocket/README.md b/services/shuttle-rocket/README.md index d630bee007..a7b5e21078 100644 --- a/services/shuttle-rocket/README.md +++ b/services/shuttle-rocket/README.md @@ -3,8 +3,7 @@ ### Example ```rust,no_run -#[macro_use] -extern crate rocket; +use rocket::{get, routes}; #[get("/")] fn index() -> &'static str { From 23aff02d376c9acd346d3c2b9f5e9aecacdcf94a Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:15:36 +0100 Subject: [PATCH 15/16] bump examples --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 77a3bf0a0e..1bcf805811 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 77a3bf0a0e0ba0dccbd23c0ca04c4735a7a06f33 +Subproject commit 1bcf805811def1299e4da7c64ade395eaa22a5b6 From 54cc545da2aa828b054253ea3e8d0aeee4f9f11a Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:16:23 +0100 Subject: [PATCH 16/16] bump examples --- examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples b/examples index 1bcf805811..7cf399638b 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 1bcf805811def1299e4da7c64ade395eaa22a5b6 +Subproject commit 7cf399638b96e7c78a06b68b0b2a5a980f7b3d32