From f60106cfbc1b85815e5ddb883e848764fa65f920 Mon Sep 17 00:00:00 2001 From: Iulian Barbu Date: Tue, 26 Mar 2024 19:17:56 +0200 Subject: [PATCH 01/26] common: add control backend type --- common/src/log.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/log.rs b/common/src/log.rs index 4606344c7..98ffa6f7a 100644 --- a/common/src/log.rs +++ b/common/src/log.rs @@ -28,6 +28,7 @@ pub enum Backend { Logger, Provisioner, ResourceRecorder, + Control, Runtime(String), } From 222b61394e840d5671741af45cd702cfe49dbf22 Mon Sep 17 00:00:00 2001 From: Iulian Barbu Date: Tue, 26 Mar 2024 23:05:52 +0200 Subject: [PATCH 02/26] backends: reinstate http otel exporter --- Cargo.lock | 1 + Cargo.toml | 2 +- backends/src/trace.rs | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0d82f9c3..748ecc83b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3869,6 +3869,7 @@ dependencies = [ "futures-core", "http 0.2.12", "opentelemetry 0.21.0", + "opentelemetry-http 0.10.0", "opentelemetry-proto", "opentelemetry-semantic-conventions", "opentelemetry_sdk", diff --git a/Cargo.toml b/Cargo.toml index 5ea6522f0..a0bfb3752 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ once_cell = "1.16.0" opentelemetry = "0.21.0" opentelemetry_sdk = { version = "0.21.0", features = ["rt-tokio", "logs"] } opentelemetry-http = "0.10.0" -opentelemetry-otlp = { version = "0.14.0", features = ["logs", "grpc-tonic"] } +opentelemetry-otlp = { version = "0.14.0", features = ["logs", "grpc-tonic", "http-proto"] } opentelemetry-proto = "0.4.0" opentelemetry-contrib = { version = "0.4.0", features = ["datadog"] } opentelemetry-appender-tracing = "0.2.0" diff --git a/backends/src/trace.rs b/backends/src/trace.rs index bd73c82b5..d41bea16b 100644 --- a/backends/src/trace.rs +++ b/backends/src/trace.rs @@ -43,7 +43,7 @@ where .tracing() .with_exporter( opentelemetry_otlp::new_exporter() - .tonic() + .http() .with_endpoint(otlp_address.clone()), ) .with_trace_config(trace::config().with_resource(Resource::new(resources.clone()))) @@ -57,7 +57,7 @@ where .with_log_config(Config::default().with_resource(Resource::new(resources.clone()))) .with_exporter( opentelemetry_otlp::new_exporter() - .tonic() + .http() .with_endpoint(otlp_address), ) .install_batch(Tokio) From e40002bb9466ddbcd1cc240b7ec3a2c3aa7cc0c0 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, 2 Apr 2024 14:10:55 +0200 Subject: [PATCH 03/26] feat: merge runtime updates in main ecs branch (#1709) * feat: runtime healthcheck, start runtime on 0.0.0.0 running on unspecified ip was necessary for the runner to be able to reach the runtime when they are running in separate containers * feat(proto): update runtime::get_client to work with * misc(proto): get client takes u16 port * feat: add health toggle to runtime * feat: set runtime to unhealthy if it doesn't start within 60s * feat: change runtime::get_client to take address * feat: kill runtime if it doesn't become healthy in time * feat: increase provisioning timeout duration --- proto/runtime.proto | 5 ++ proto/src/generated/runtime.rs | 63 +++++++++++++++++++++++ proto/src/lib.rs | 9 ++-- runtime/src/alpha.rs | 92 +++++++++++++++++++++++++++++----- service/src/runner.rs | 6 +-- 5 files changed, 153 insertions(+), 22 deletions(-) diff --git a/proto/runtime.proto b/proto/runtime.proto index 3748e6129..fd0c974b0 100644 --- a/proto/runtime.proto +++ b/proto/runtime.proto @@ -13,6 +13,8 @@ service Runtime { // Channel to notify a service has been stopped rpc SubscribeStop(SubscribeStopRequest) returns (stream SubscribeStopResponse); + + rpc HealthCheck(Ping) returns (Pong); } message LoadRequest { @@ -78,3 +80,6 @@ enum StopReason { // Service crashed Crash = 2; } + +message Ping {} +message Pong {} diff --git a/proto/src/generated/runtime.rs b/proto/src/generated/runtime.rs index 09eb3cca5..fa7097a29 100644 --- a/proto/src/generated/runtime.rs +++ b/proto/src/generated/runtime.rs @@ -73,6 +73,12 @@ pub struct SubscribeStopResponse { #[prost(string, tag = "2")] pub message: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Ping {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Pong {} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum StopReason { @@ -264,6 +270,23 @@ pub mod runtime_client { .insert(GrpcMethod::new("runtime.Runtime", "SubscribeStop")); self.inner.server_streaming(req, path, codec).await } + pub async fn health_check( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/runtime.Runtime/HealthCheck"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("runtime.Runtime", "HealthCheck")); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -298,6 +321,10 @@ pub mod runtime_server { &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; + async fn health_check( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; } #[derive(Debug)] pub struct RuntimeServer { @@ -534,6 +561,42 @@ pub mod runtime_server { }; Box::pin(fut) } + "/runtime.Runtime/HealthCheck" => { + #[allow(non_camel_case_types)] + struct HealthCheckSvc(pub Arc); + impl tonic::server::UnaryService for HealthCheckSvc { + type Response = super::Pong; + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = + async move { ::health_check(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = HealthCheckSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => Box::pin(async move { Ok(http::Response::builder() .status(200) diff --git a/proto/src/lib.rs b/proto/src/lib.rs index b2676f35a..0a6f221b6 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -146,16 +146,14 @@ mod _runtime_client { use tracing::{info, trace}; pub type Client = runtime_client::RuntimeClient< - shuttle_common::claims::ClaimService< - shuttle_common::claims::InjectPropagation, - >, + shuttle_common::claims::InjectPropagation, >; /// Get a runtime client that is correctly configured #[cfg(feature = "client")] - pub async fn get_client(port: &str) -> anyhow::Result { + pub async fn get_client(address: String) -> anyhow::Result { info!("connecting runtime client"); - let conn = Endpoint::new(format!("http://127.0.0.1:{port}")) + let conn = Endpoint::new(address) .context("creating runtime client endpoint")? .connect_timeout(Duration::from_secs(5)); @@ -177,7 +175,6 @@ mod _runtime_client { .context("runtime control port did not open in time")?; let runtime_service = tower::ServiceBuilder::new() - .layer(shuttle_common::claims::ClaimLayer) .layer(shuttle_common::claims::InjectPropagationLayer) .service(channel); diff --git a/runtime/src/alpha.rs b/runtime/src/alpha.rs index 0675b55f5..a3d5070bd 100644 --- a/runtime/src/alpha.rs +++ b/runtime/src/alpha.rs @@ -2,9 +2,9 @@ use std::{ collections::BTreeMap, iter::FromIterator, net::{Ipv4Addr, SocketAddr}, - ops::DerefMut, + ops::{Deref, DerefMut}, str::FromStr, - sync::Mutex, + sync::{Arc, Mutex}, time::Duration, }; @@ -12,10 +12,13 @@ use anyhow::Context; use async_trait::async_trait; use core::future::Future; use shuttle_common::{extract_propagation::ExtractPropagationLayer, secrets::Secret}; -use shuttle_proto::runtime::{ - runtime_server::{Runtime, RuntimeServer}, - LoadRequest, LoadResponse, StartRequest, StartResponse, StopReason, StopRequest, StopResponse, - SubscribeStopRequest, SubscribeStopResponse, +use shuttle_proto::{ + runtime::{ + runtime_server::{Runtime, RuntimeServer}, + LoadRequest, LoadResponse, StartRequest, StartResponse, StopReason, StopRequest, + StopResponse, SubscribeStopRequest, SubscribeStopResponse, + }, + runtime::{Ping, Pong}, }; use shuttle_service::{ResourceFactory, Service}; use tokio::sync::{ @@ -84,23 +87,42 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S } // where to serve the gRPC control layer - let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), args.port); + let addr = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), args.port); let mut server_builder = Server::builder() .http2_keepalive_interval(Some(Duration::from_secs(60))) .layer(ExtractPropagationLayer); + // A channel we can use to kill the runtime if it does not become healthy in time. + let (tx, rx) = tokio::sync::oneshot::channel::<()>(); + let router = { - let alpha = Alpha::new(loader, runner); + let alpha = Alpha::new(loader, runner, tx); let svc = RuntimeServer::new(alpha); server_builder.add_service(svc) }; - match router.serve(addr).await { - Ok(_) => {} - Err(e) => panic!("Error while serving address {addr}: {e}"), - }; + tokio::select! { + res = router.serve(addr) => { + match res{ + Ok(_) => {} + Err(e) => panic!("Error while serving address {addr}: {e}") + } + } + res = rx => { + match res{ + Ok(_) => panic!("Received runtime kill signal"), + Err(e) => panic!("Receiver error: {e}") + } + } + } +} + +pub enum State { + Unhealthy, + Loading, + Running, } pub struct Alpha { @@ -109,10 +131,14 @@ pub struct Alpha { kill_tx: Mutex>>, loader: Mutex>, runner: Mutex>, + /// The current state of the runtime, which is used by the ECS task to determine if the runtime + /// is healthy. + state: Arc>, + runtime_kill_tx: Mutex>>, } impl Alpha { - pub fn new(loader: L, runner: R) -> Self { + pub fn new(loader: L, runner: R, runtime_kill_tx: tokio::sync::oneshot::Sender<()>) -> Self { let (stopped_tx, _stopped_rx) = broadcast::channel(10); Self { @@ -120,6 +146,8 @@ impl Alpha { kill_tx: Mutex::new(None), loader: Mutex::new(Some(loader)), runner: Mutex::new(Some(runner)), + state: Arc::new(Mutex::new(State::Unhealthy)), + runtime_kill_tx: Mutex::new(Some(runtime_kill_tx)), } } } @@ -223,6 +251,31 @@ where } }; + println!("setting current state to healthy"); + *self.state.lock().unwrap() = State::Loading; + + let state = self.state.clone(); + let runtime_kill_tx = self + .runtime_kill_tx + .lock() + .unwrap() + .deref_mut() + .take() + .unwrap(); + + // Ensure that the runtime is set to unhealthy if it doesn't reach the running state after + // it has sent a load response, so that the ECS task will fail. + tokio::spawn(async move { + // Note: The timeout is quite low as we are not actually provisioning resources after + // sending the load response. + tokio::time::sleep(Duration::from_secs(180)).await; + if !matches!(state.lock().unwrap().deref(), State::Running) { + println!("the runtime failed to enter the running state before timing out"); + + runtime_kill_tx.send(()).unwrap(); + } + }); + Ok(Response::new(LoadResponse { success: true, message: String::new(), @@ -355,6 +408,8 @@ where ..Default::default() }; + *self.state.lock().unwrap() = State::Running; + Ok(Response::new(message)) } @@ -398,4 +453,15 @@ where Ok(Response::new(ReceiverStream::new(rx))) } + + async fn health_check(&self, _request: Request) -> Result, Status> { + if matches!(self.state.lock().unwrap().deref(), State::Unhealthy) { + println!("runtime health check failed"); + return Err(Status::unavailable( + "runtime has not reached a healthy state", + )); + } + + Ok(Response::new(Pong {})) + } } diff --git a/service/src/runner.rs b/service/src/runner.rs index 5cb949558..b772e573f 100644 --- a/service/src/runner.rs +++ b/service/src/runner.rs @@ -13,8 +13,8 @@ pub async fn start( runtime_executable: PathBuf, project_path: &Path, ) -> anyhow::Result<(process::Child, runtime::Client)> { - let port = &port.to_string(); - let args = vec!["--port", port]; + let port_str = port.to_string(); + let args = vec!["--port", &port_str]; info!( args = %format!("{} {}", runtime_executable.display(), args.join(" ")), @@ -30,7 +30,7 @@ pub async fn start( .spawn() .context("spawning runtime process")?; - let runtime_client = runtime::get_client(port).await?; + let runtime_client = runtime::get_client(format!("http://0.0.0.0:{port}")).await?; Ok((runtime, runtime_client)) } From 45e5d4ed29915d6ae43fd37a895794f5d32b37cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oddbj=C3=B8rn=20Gr=C3=B8dem?= <29732646+oddgrd@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:37:16 +0200 Subject: [PATCH 04/26] feat: add resource request struct to backends (#1718) --- backends/src/headers.rs | 33 +++++++++++++++++++++++++++++++++ backends/src/lib.rs | 1 + backends/src/resource.rs | 4 ++++ 3 files changed, 38 insertions(+) create mode 100644 backends/src/resource.rs diff --git a/backends/src/headers.rs b/backends/src/headers.rs index 1f9009b7a..1cf61857e 100644 --- a/backends/src/headers.rs +++ b/backends/src/headers.rs @@ -33,6 +33,39 @@ impl Header for XShuttleAdminSecret { } } +pub static X_SHUTTLE_PROJECT_SECRET: HeaderName = + HeaderName::from_static("x-shuttle-project-secret"); + +/// Typed header for sending admin secrets to Shuttle components +pub struct XShuttleProjectSecret(pub String); + +impl Header for XShuttleProjectSecret { + fn name() -> &'static HeaderName { + &X_SHUTTLE_PROJECT_SECRET + } + + fn decode<'i, I>(values: &mut I) -> Result + where + Self: Sized, + I: Iterator, + { + let value = values + .next() + .ok_or_else(headers::Error::invalid)? + .to_str() + .map_err(|_| headers::Error::invalid())? + .to_string(); + + Ok(Self(value)) + } + + fn encode>(&self, values: &mut E) { + if let Ok(value) = HeaderValue::from_str(&self.0) { + values.extend(std::iter::once(value)); + } + } +} + /// Used by deployers <=0.38.0. Can be removed when those are no longer supported pub static X_SHUTTLE_PROJECT: HeaderName = HeaderName::from_static("x-shuttle-project"); diff --git a/backends/src/lib.rs b/backends/src/lib.rs index 7e473ff6c..7dad2b884 100644 --- a/backends/src/lib.rs +++ b/backends/src/lib.rs @@ -13,6 +13,7 @@ pub mod headers; pub mod metrics; mod otlp_tracing_bridge; pub mod project_name; +pub mod resource; pub mod trace; #[cfg(any(test, feature = "test-utils"))] diff --git a/backends/src/resource.rs b/backends/src/resource.rs new file mode 100644 index 000000000..5183ff061 --- /dev/null +++ b/backends/src/resource.rs @@ -0,0 +1,4 @@ +#[derive(serde::Serialize, serde::Deserialize)] +pub struct ResourceRequest { + pub resources: Vec>, +} From 72839f07bf5b92063decae2393016c792852a6a0 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:20:10 +0200 Subject: [PATCH 05/26] feat(cargo-shuttle): beta flag, remove project list pagination logic (#1732) * feat(cargo-shuttle): beta flag * nit: client name * fix: delete beta endpoint --- cargo-shuttle/Cargo.toml | 6 +- cargo-shuttle/src/args.rs | 9 +- cargo-shuttle/src/client.rs | 76 ++++++++-------- cargo-shuttle/src/config.rs | 8 +- cargo-shuttle/src/lib.rs | 113 +++++++++++++----------- cargo-shuttle/tests/integration/main.rs | 1 + common-tests/src/cargo_shuttle.rs | 1 + common/src/lib.rs | 3 - common/src/models/project.rs | 24 +---- 9 files changed, 119 insertions(+), 122 deletions(-) diff --git a/cargo-shuttle/Cargo.toml b/cargo-shuttle/Cargo.toml index df95b5e24..bd541b49c 100644 --- a/cargo-shuttle/Cargo.toml +++ b/cargo-shuttle/Cargo.toml @@ -4,7 +4,7 @@ version = "0.43.0" edition.workspace = true license.workspace = true repository.workspace = true -description = "A cargo command for the shuttle platform (https://www.shuttle.rs/)" +description = "A cargo command for the Shuttle platform (https://www.shuttle.rs/)" homepage = "https://www.shuttle.rs" [dependencies] @@ -32,10 +32,10 @@ gix = { version = "0.55.2", default-features = false, features = [ "worktree-mutation", ] } globset = "0.4.13" -home = { workspace = true } headers = { workspace = true } -indicatif = "0.17.3" +home = { workspace = true } ignore = "0.4.20" +indicatif = "0.17.3" indoc = "2.0.1" percent-encoding = { workspace = true } portpicker = { workspace = true } diff --git a/cargo-shuttle/src/args.rs b/cargo-shuttle/src/args.rs index 705583507..60b31e89f 100644 --- a/cargo-shuttle/src/args.rs +++ b/cargo-shuttle/src/args.rs @@ -39,6 +39,9 @@ pub struct ShuttleArgs { /// Turn on tracing output for cargo-shuttle and shuttle libraries. #[arg(long, env = "SHUTTLE_DEBUG")] pub debug: bool, + /// Target Shuttle's development environment + #[arg(long, env = "SHUTTLE_BETA")] + pub beta: bool, #[command(subcommand)] pub cmd: Command, @@ -158,7 +161,7 @@ pub enum DeploymentCommand { limit: u32, #[arg(long, default_value_t = false)] - /// Output table in `raw` format + /// Output table without borders raw: bool, }, /// View status of a deployment @@ -173,7 +176,7 @@ pub enum ResourceCommand { /// List all the resources for a project List { #[arg(long, default_value_t = false)] - /// Output table in `raw` format + /// Output table without borders raw: bool, #[arg( @@ -219,7 +222,7 @@ pub enum ProjectCommand { limit: u32, #[arg(long, default_value_t = false)] - /// Output table in `raw` format + /// Output table without borders raw: bool, }, /// Delete a project and all linked data diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index 02fed8a17..91d01a110 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -11,8 +11,7 @@ use serde::{Deserialize, Serialize}; use shuttle_common::constants::headers::X_CARGO_SHUTTLE_VERSION; use shuttle_common::models::deployment::DeploymentRequest; use shuttle_common::models::{deployment, project, service, ToJson}; -use shuttle_common::secrets::Secret; -use shuttle_common::{resource, ApiKey, ApiUrl, LogItem, VersionInfo}; +use shuttle_common::{resource, ApiKey, LogItem, VersionInfo}; use tokio::net::TcpStream; use tokio_tungstenite::tungstenite::client::IntoClientRequest; use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream}; @@ -20,17 +19,17 @@ use tracing::error; use uuid::Uuid; #[derive(Clone)] -pub struct Client { - api_url: ApiUrl, - api_key: Option>, +pub struct ShuttleApiClient { client: reqwest::Client, + api_url: String, + api_key: Option, + /// alter behaviour to interact with the new platform + beta: bool, } -impl Client { - pub fn new(api_url: ApiUrl) -> Self { +impl ShuttleApiClient { + pub fn new(api_url: String, api_key: Option, beta: bool) -> Self { Self { - api_url, - api_key: None, client: reqwest::Client::builder() .default_headers( HeaderMap::try_from(&HashMap::from([( @@ -42,11 +41,22 @@ impl Client { .timeout(Duration::from_secs(60)) .build() .unwrap(), + api_url, + api_key, + beta, } } pub fn set_api_key(&mut self, api_key: ApiKey) { - self.api_key = Some(Secret::new(api_key)); + self.api_key = Some(api_key); + } + + fn set_auth_bearer(&self, builder: RequestBuilder) -> RequestBuilder { + if let Some(ref api_key) = self.api_key { + builder.bearer_auth(api_key.as_ref()) + } else { + builder + } } pub async fn get_api_versions(&self) -> Result { @@ -79,13 +89,17 @@ impl Client { project: &str, deployment_req: DeploymentRequest, ) -> Result { - let path = format!("/projects/{project}/services/{project}"); + let path = if self.beta { + format!("/projects/{project}") + } else { + format!("/projects/{project}/services/{project}") + }; let deployment_req = rmp_serde::to_vec(&deployment_req) .context("serialize DeploymentRequest as a MessagePack byte vector")?; let url = format!("{}{}", self.api_url, path); let mut builder = self.client.post(url); - builder = self.set_builder_auth(builder); + builder = self.set_auth_bearer(builder); builder .header("Transfer-Encoding", "chunked") @@ -161,10 +175,8 @@ impl Client { self.get(path).await } - pub async fn get_projects_list(&self, page: u32, limit: u32) -> Result> { - let path = format!("/projects?page={}&limit={}", page.saturating_sub(1), limit); - - self.get(path).await + pub async fn get_projects_list(&self) -> Result> { + self.get("/projects".to_owned()).await } pub async fn stop_project(&self, project: &str) -> Result { @@ -174,7 +186,11 @@ impl Client { } pub async fn delete_project(&self, project: &str) -> Result { - let path = format!("/projects/{project}/delete"); + let path = if self.beta { + format!("/projects/{project}") + } else { + format!("/projects/{project}/delete") + }; self.delete(path).await } @@ -228,12 +244,12 @@ impl Client { } async fn ws_get(&self, path: String) -> Result>> { - let ws_scheme = self.api_url.clone().replace("http", "ws"); - let url = format!("{ws_scheme}{path}"); + let ws_url = self.api_url.clone().replace("http", "ws"); + let url = format!("{ws_url}{path}"); let mut request = url.into_client_request()?; if let Some(ref api_key) = self.api_key { - let auth_header = Authorization::bearer(api_key.expose().as_ref())?; + let auth_header = Authorization::bearer(api_key.as_ref())?; request.headers_mut().typed_insert(auth_header); } @@ -252,8 +268,7 @@ impl Client { let url = format!("{}{}", self.api_url, path); let mut builder = self.client.get(url); - - builder = self.set_builder_auth(builder); + builder = self.set_auth_bearer(builder); builder .send() @@ -267,8 +282,7 @@ impl Client { let url = format!("{}{}", self.api_url, path); let mut builder = self.client.post(url); - - builder = self.set_builder_auth(builder); + builder = self.set_auth_bearer(builder); if let Some(body) = body { let body = serde_json::to_string(&body)?; @@ -283,8 +297,7 @@ impl Client { let url = format!("{}{}", self.api_url, path); let mut builder = self.client.put(url); - - builder = self.set_builder_auth(builder); + builder = self.set_auth_bearer(builder); if let Some(body) = body { let body = serde_json::to_string(&body)?; @@ -302,8 +315,7 @@ impl Client { let url = format!("{}{}", self.api_url, path); let mut builder = self.client.delete(url); - - builder = self.set_builder_auth(builder); + builder = self.set_auth_bearer(builder); builder .send() @@ -312,12 +324,4 @@ impl Client { .to_json() .await } - - fn set_builder_auth(&self, builder: RequestBuilder) -> RequestBuilder { - if let Some(ref api_key) = self.api_key { - builder.bearer_auth(api_key.expose().as_ref()) - } else { - builder - } - } } diff --git a/cargo-shuttle/src/config.rs b/cargo-shuttle/src/config.rs index 73d390d10..7d640081b 100644 --- a/cargo-shuttle/src/config.rs +++ b/cargo-shuttle/src/config.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use anyhow::{anyhow, Context, Result}; use serde::{Deserialize, Serialize}; -use shuttle_common::{constants::API_URL_DEFAULT, ApiKey, ApiUrl}; +use shuttle_common::{constants::API_URL_DEFAULT, ApiKey}; use tracing::trace; use crate::args::ProjectArgs; @@ -122,7 +122,7 @@ impl ConfigManager for LocalConfigManager { #[derive(Deserialize, Serialize, Default)] pub struct GlobalConfig { api_key: Option, - pub api_url: Option, + pub api_url: Option, } impl GlobalConfig { @@ -138,7 +138,7 @@ impl GlobalConfig { self.api_key = None; } - pub fn api_url(&self) -> Option { + pub fn api_url(&self) -> Option { self.api_url.clone() } } @@ -315,7 +315,7 @@ impl RequestContext { self.api_url = api_url; } - pub fn api_url(&self) -> ApiUrl { + pub fn api_url(&self) -> String { if let Some(api_url) = self.api_url.clone() { api_url } else if let Some(api_url) = self.global.as_ref().unwrap().api_url() { diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index 23b2dbb08..81d3758f1 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -75,7 +75,7 @@ use crate::args::{ DeployArgs, DeploymentCommand, InitArgs, LoginArgs, LogoutArgs, LogsArgs, ProjectCommand, ProjectStartArgs, ResourceCommand, TemplateLocation, }; -use crate::client::Client; +use crate::client::ShuttleApiClient; use crate::provisioner_server::LocalProvisioner; const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -96,9 +96,11 @@ pub fn parse_args() -> (ShuttleArgs, bool) { pub struct Shuttle { ctx: RequestContext, - client: Option, + client: Option, version_info: Option, version_warnings: Vec, + /// alter behaviour to interact with the new platform + beta: bool, } impl Shuttle { @@ -109,40 +111,36 @@ impl Shuttle { client: None, version_info: None, version_warnings: vec![], + beta: false, }) } - fn find_available_port(run_args: &mut RunArgs, services_len: usize) { - let default_port = run_args.port; - 'outer: for port in (run_args.port..=std::u16::MAX).step_by(services_len.max(10)) { - for inner_port in port..(port + services_len as u16) { - if !portpicker::is_free_tcp(inner_port) { - continue 'outer; - } - } - run_args.port = port; - break; - } - - if run_args.port != default_port - && !Confirm::with_theme(&ColorfulTheme::default()) - .with_prompt(format!( - "Port {} is already in use. Would you like to continue on port {}?", - default_port, run_args.port - )) - .default(true) - .interact() - .unwrap() - { - exit(0); - } - } - pub async fn run( mut self, args: ShuttleArgs, provided_path_to_init: bool, ) -> Result { + self.beta = args.beta; + if self.beta { + if matches!( + args.cmd, + Command::Project(ProjectCommand::Stop { .. } | ProjectCommand::Restart { .. }) + ) { + unimplemented!("This command is deprecated on the beta platform"); + } + if matches!( + args.cmd, + Command::Deployment(..) + | Command::Resource(..) + | Command::Stop + | Command::Clean + | Command::Status + | Command::Logs { .. } + ) { + unimplemented!("This command is not yet implemented on the beta platform"); + } + eprintln!("INFO: Using beta platform API"); + } if let Some(ref url) = args.api_url { if url != API_URL_DEFAULT { eprintln!("INFO: Targeting non-standard API: {url}"); @@ -190,13 +188,11 @@ impl Shuttle { | Command::Clean | Command::Project(..) ) { - let mut client = Client::new(self.ctx.api_url()); - if !matches!(args.cmd, Command::Init(..)) { - // init command will handle this by itself (log in and set key) if there is no key yet - client.set_api_key(self.ctx.api_key()?); - } + let client = + ShuttleApiClient::new(self.ctx.api_url(), self.ctx.api_key().ok(), self.beta); self.client = Some(client); - if !args.offline { + if !args.offline && !self.beta { + // TODO: re-implement version checking in control to use the c-s version http header self.check_api_versions().await?; } } @@ -244,9 +240,7 @@ impl Shuttle { Command::Project(ProjectCommand::Status { follow }) => { self.project_status(follow).await } - Command::Project(ProjectCommand::List { page, limit, raw }) => { - self.projects_list(page, limit, raw).await - } + Command::Project(ProjectCommand::List { raw, .. }) => self.projects_list(raw).await, Command::Project(ProjectCommand::Stop) => self.project_stop().await, Command::Project(ProjectCommand::Delete(ConfirmationArgs { yes })) => { self.project_delete(yes).await @@ -1392,6 +1386,32 @@ impl Shuttle { build_workspace(working_directory, run_args.release, tx, false).await } + fn find_available_port(run_args: &mut RunArgs, services_len: usize) { + let default_port = run_args.port; + 'outer: for port in (run_args.port..=std::u16::MAX).step_by(services_len.max(10)) { + for inner_port in port..(port + services_len as u16) { + if !portpicker::is_free_tcp(inner_port) { + continue 'outer; + } + } + run_args.port = port; + break; + } + + if run_args.port != default_port + && !Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt(format!( + "Port {} is already in use. Would you like to continue on port {}?", + default_port, run_args.port + )) + .default(true) + .interact() + .unwrap() + { + exit(0); + } + } + #[cfg(target_family = "unix")] async fn local_run(&self, mut run_args: RunArgs) -> Result { debug!("starting local run"); @@ -1920,7 +1940,7 @@ impl Shuttle { ) })?; - if idle_minutes > 0 { + if idle_minutes > 0 && !self.beta { let idle_msg = format!( "Your project will sleep if it is idle for {} minutes.", idle_minutes @@ -1946,15 +1966,10 @@ impl Shuttle { Ok(CommandOutcome::Ok) } - async fn projects_list(&self, page: u32, limit: u32, raw: bool) -> Result { + async fn projects_list(&self, raw: bool) -> Result { let client = self.client.as_ref().unwrap(); - if limit == 0 { - println!(); - return Ok(CommandOutcome::Ok); - } - let limit = limit + 1; - let mut projects = client.get_projects_list(page, limit).await.map_err(|err| { + let projects = client.get_projects_list().await.map_err(|err| { suggestions::project::project_request_failure( err, "Getting projects list failed", @@ -1962,13 +1977,7 @@ impl Shuttle { "getting the projects list fails repeatedly", ) })?; - let page_hint = if projects.len() == limit as usize { - projects.pop(); - true - } else { - false - }; - let projects_table = project::get_projects_table(&projects, page, raw, page_hint); + let projects_table = project::get_projects_table(&projects, raw); println!("{projects_table}"); diff --git a/cargo-shuttle/tests/integration/main.rs b/cargo-shuttle/tests/integration/main.rs index fd16de68a..60516f6a7 100644 --- a/cargo-shuttle/tests/integration/main.rs +++ b/cargo-shuttle/tests/integration/main.rs @@ -22,6 +22,7 @@ async fn cargo_shuttle_command( }, offline: false, debug: false, + beta: false, cmd, }, false, diff --git a/common-tests/src/cargo_shuttle.rs b/common-tests/src/cargo_shuttle.rs index 1cfe17d22..9414f6142 100644 --- a/common-tests/src/cargo_shuttle.rs +++ b/common-tests/src/cargo_shuttle.rs @@ -43,6 +43,7 @@ pub async fn cargo_shuttle_run(working_directory: &str, external: bool) -> Strin }, offline: false, debug: false, + beta: false, cmd: Command::Run(run_args), }, false, diff --git a/common/src/lib.rs b/common/src/lib.rs index c08f3ecc8..1cfd71381 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -29,9 +29,6 @@ use anyhow::bail; use serde::{Deserialize, Serialize}; use zeroize::Zeroize; -pub type ApiUrl = String; -pub type Host = String; - #[derive(Clone, Serialize, Deserialize)] #[cfg_attr(feature = "persist", derive(PartialEq, Eq, Hash, sqlx::Type))] #[cfg_attr(feature = "persist", serde(transparent))] diff --git a/common/src/models/project.rs b/common/src/models/project.rs index b3f423640..5eacf563a 100644 --- a/common/src/models/project.rs +++ b/common/src/models/project.rs @@ -164,19 +164,9 @@ pub struct Config { pub idle_minutes: u64, } -pub fn get_projects_table( - projects: &Vec, - page: u32, - raw: bool, - page_hint: bool, -) -> String { +pub fn get_projects_table(projects: &Vec, raw: bool) -> String { if projects.is_empty() { - // The page starts at 1 in the CLI. - let mut s = if page <= 1 { - "No projects are linked to this account\n".to_string() - } else { - "No more projects are linked to this account\n".to_string() - }; + let mut s = "No projects are linked to this account\n".to_string(); if !raw { s = s.yellow().bold().to_string(); } @@ -222,14 +212,6 @@ pub fn get_projects_table( } } - let formatted_table = format!("\nThese projects are linked to this account\n{table}\n"); - if page_hint { - format!( - "{formatted_table}More projects are available on the next page using `--page {}`\n", - page + 1 - ) - } else { - formatted_table - } + format!("\nThese projects are linked to this account\n{table}\n") } } From d09d8036c7374d009d77f0bfb3ad19f706c1d081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oddbj=C3=B8rn=20Gr=C3=B8dem?= <29732646+oddgrd@users.noreply.github.com> Date: Thu, 11 Apr 2024 10:17:38 +0200 Subject: [PATCH 06/26] feat: add models and header for new ecs provisioner (#1730) --- backends/src/headers.rs | 32 ++++++++++++++++++++++++++++++++ backends/src/resource.rs | 14 +++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/backends/src/headers.rs b/backends/src/headers.rs index 1cf61857e..27aa05b98 100644 --- a/backends/src/headers.rs +++ b/backends/src/headers.rs @@ -66,6 +66,38 @@ impl Header for XShuttleProjectSecret { } } +/// Used to ensure requests originate from the control service. +pub static X_SHUTTLE_CTL_SECRET: HeaderName = HeaderName::from_static("x-shuttle-ctl-secret"); + +pub struct XShuttleCtlSecret(pub String); + +impl Header for XShuttleCtlSecret { + fn name() -> &'static HeaderName { + &X_SHUTTLE_CTL_SECRET + } + + fn decode<'i, I>(values: &mut I) -> Result + where + Self: Sized, + I: Iterator, + { + let value = values + .next() + .ok_or_else(headers::Error::invalid)? + .to_str() + .map_err(|_| headers::Error::invalid())? + .to_string(); + + Ok(Self(value)) + } + + fn encode>(&self, values: &mut E) { + if let Ok(value) = HeaderValue::from_str(self.0.as_str()) { + values.extend(std::iter::once(value)); + } + } +} + /// Used by deployers <=0.38.0. Can be removed when those are no longer supported pub static X_SHUTTLE_PROJECT: HeaderName = HeaderName::from_static("x-shuttle-project"); diff --git a/backends/src/resource.rs b/backends/src/resource.rs index 5183ff061..ccc6124db 100644 --- a/backends/src/resource.rs +++ b/backends/src/resource.rs @@ -1,4 +1,16 @@ -#[derive(serde::Serialize, serde::Deserialize)] +use serde::{Deserialize, Serialize}; + +/// Used by the runner service to send requests to control plane, where the requested resources +/// will be provisioned. +#[derive(Serialize, Deserialize)] pub struct ResourceRequest { + /// The resource input returned from the runtime::load call. pub resources: Vec>, } + +/// Used to request the provisioning or deletion of a shared DB from the provisioner service. +#[derive(Deserialize, Serialize)] +pub struct SharedDbRequest { + pub db_name: String, + pub role_name: String, +} From 2286c0406669f170e69c73c665428b12b5ff2558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oddbj=C3=B8rn=20Gr=C3=B8dem?= <29732646+oddgrd@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:27:00 +0200 Subject: [PATCH 07/26] fix: runtime panic (#1735) * fix: debug runtime panic * fix: try without service stop channel * fix: move tx take into conditional kill block * fix: revert other changes, use arc for kill tx * refactor: use cancellation token instead of oneshot * misc: revert timeout change * misc: remove extra clone, switch panic to print * fix: panic on error or cancellation --- Cargo.lock | 1 + runtime/Cargo.toml | 1 + runtime/src/alpha.rs | 34 ++++++++++++++-------------------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ea8b9ba6..cc474b1d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5568,6 +5568,7 @@ dependencies = [ "strfmt", "tokio", "tokio-stream", + "tokio-util", "tonic 0.10.2", "tracing-subscriber", "uuid", diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 4c428fad1..ab38747ac 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -22,6 +22,7 @@ serde = { workspace = true } serde_json = { workspace = true } strfmt = { workspace = true } tokio = { workspace = true, features = ["full"] } +tokio-util = "0.7.10" tokio-stream = { workspace = true } tonic = { workspace = true } tracing-subscriber = { workspace = true, optional = true } diff --git a/runtime/src/alpha.rs b/runtime/src/alpha.rs index a3d5070bd..3c2645950 100644 --- a/runtime/src/alpha.rs +++ b/runtime/src/alpha.rs @@ -26,6 +26,7 @@ use tokio::sync::{ mpsc, oneshot, }; use tokio_stream::wrappers::ReceiverStream; +use tokio_util::sync::CancellationToken; use tonic::{transport::Server, Request, Response, Status}; use crate::args::args; @@ -93,11 +94,12 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S .http2_keepalive_interval(Some(Duration::from_secs(60))) .layer(ExtractPropagationLayer); - // A channel we can use to kill the runtime if it does not become healthy in time. - let (tx, rx) = tokio::sync::oneshot::channel::<()>(); + // A cancellation token we can use to kill the runtime if it does not start in time. + let token = CancellationToken::new(); + let cloned_token = token.clone(); let router = { - let alpha = Alpha::new(loader, runner, tx); + let alpha = Alpha::new(loader, runner, token); let svc = RuntimeServer::new(alpha); server_builder.add_service(svc) @@ -106,15 +108,12 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S tokio::select! { res = router.serve(addr) => { match res{ - Ok(_) => {} + Ok(_) => println!("router completed on its own"), Err(e) => panic!("Error while serving address {addr}: {e}") } } - res = rx => { - match res{ - Ok(_) => panic!("Received runtime kill signal"), - Err(e) => panic!("Receiver error: {e}") - } + _ = cloned_token.cancelled() => { + panic!("runtime future was cancelled") } } } @@ -134,11 +133,12 @@ pub struct Alpha { /// The current state of the runtime, which is used by the ECS task to determine if the runtime /// is healthy. state: Arc>, - runtime_kill_tx: Mutex>>, + // A cancellation token we can use to kill the runtime if it does not start in time. + cancellation_token: CancellationToken, } impl Alpha { - pub fn new(loader: L, runner: R, runtime_kill_tx: tokio::sync::oneshot::Sender<()>) -> Self { + pub fn new(loader: L, runner: R, cancellation_token: CancellationToken) -> Self { let (stopped_tx, _stopped_rx) = broadcast::channel(10); Self { @@ -147,7 +147,7 @@ impl Alpha { loader: Mutex::new(Some(loader)), runner: Mutex::new(Some(runner)), state: Arc::new(Mutex::new(State::Unhealthy)), - runtime_kill_tx: Mutex::new(Some(runtime_kill_tx)), + cancellation_token, } } } @@ -255,13 +255,7 @@ where *self.state.lock().unwrap() = State::Loading; let state = self.state.clone(); - let runtime_kill_tx = self - .runtime_kill_tx - .lock() - .unwrap() - .deref_mut() - .take() - .unwrap(); + let cancellation_token = self.cancellation_token.clone(); // Ensure that the runtime is set to unhealthy if it doesn't reach the running state after // it has sent a load response, so that the ECS task will fail. @@ -272,7 +266,7 @@ where if !matches!(state.lock().unwrap().deref(), State::Running) { println!("the runtime failed to enter the running state before timing out"); - runtime_kill_tx.send(()).unwrap(); + cancellation_token.cancel(); } }); From cd7b71c1c672078c7865da2be42471cc33ff06e5 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Thu, 11 Apr 2024 22:41:56 +0200 Subject: [PATCH 08/26] fix(cargo-shuttle): deploy http method --- cargo-shuttle/src/client.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index 91d01a110..acc15c85c 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -98,7 +98,11 @@ impl ShuttleApiClient { .context("serialize DeploymentRequest as a MessagePack byte vector")?; let url = format!("{}{}", self.api_url, path); - let mut builder = self.client.post(url); + let mut builder = if self.beta { + self.client.put(url) + } else { + self.client.post(url) + }; builder = self.set_auth_bearer(builder); builder From d3f6c6b9d4818cc39aff1afe33a4e7af504a0193 Mon Sep 17 00:00:00 2001 From: Iulian Barbu <14218860+iulianbarbu@users.noreply.github.com> Date: Tue, 16 Apr 2024 10:43:18 +0300 Subject: [PATCH 09/26] cargo-shuttle: update deploy cmd for beta platform (#1734) * common: updated deployment models * cargo-shuttle: update deploy cmd * common: add more information in a deployment response * cargo-shuttle: add project uri in deploy output * fix: Jocelyn's comments on fronted output * cargo-shuttle: when deploying use the beta field on the Shuttle type * cargo-shuttle: split beta/alpha deploy functions in client * cargo-shuttle: addressed left over of alpha deployments table change * cargo-shuttle: remove pub for beta flag on client * cargo-shuttle: remove leftover comment * address Jocelyn review comments --- Cargo.lock | 711 +++++++++++++++----------------- cargo-shuttle/src/client.rs | 38 +- cargo-shuttle/src/lib.rs | 11 + common/src/deployment.rs | 11 + common/src/models/deployment.rs | 69 +++- 5 files changed, 452 insertions(+), 388 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc474b1d1..894412d79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.14", "once_cell", "version_check", "zerocopy", @@ -32,9 +32,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -110,15 +110,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "arc-swap" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "arrayvec" @@ -233,7 +233,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -258,13 +258,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -276,21 +276,11 @@ dependencies = [ "num-traits", ] -[[package]] -name = "atomic-write-file" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8204db279bf648d64fe845bd8840f78b39c8132ed4d6a4194c3b10d4b4cfb0b" -dependencies = [ - "nix 0.28.0", - "rand 0.8.5", -] - [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "aws-config" @@ -310,7 +300,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.0.1", + "fastrand 2.0.2", "hex", "http 0.2.12", "hyper 0.14.28", @@ -330,7 +320,7 @@ checksum = "70a66ac8ef5fa9cf01c2d999f39d16812e90ec1467bd382cbbb74ba23ea86201" dependencies = [ "aws-smithy-async", "aws-smithy-types", - "fastrand 2.0.1", + "fastrand 2.0.2", "tokio", "tracing", "zeroize", @@ -369,7 +359,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", - "fastrand 2.0.1", + "fastrand 2.0.2", "http 0.2.12", "percent-encoding", "tracing", @@ -491,7 +481,7 @@ dependencies = [ "aws-smithy-http-tower", "aws-smithy-types", "bytes", - "fastrand 2.0.1", + "fastrand 2.0.2", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", @@ -573,7 +563,7 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "bytes", - "fastrand 2.0.1", + "fastrand 2.0.2", "http 0.2.12", "http-body 0.4.6", "once_cell", @@ -733,9 +723,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -758,6 +748,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "base64-simd" version = "0.8.0" @@ -774,15 +770,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "basic-toml" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5" -dependencies = [ - "serde", -] - [[package]] name = "bit-set" version = "0.5.3" @@ -806,9 +793,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" dependencies = [ "serde", ] @@ -871,20 +858,20 @@ checksum = "b58071e8fd9ec1e930efd28e3a90c1251015872a2ce49f81f36421b86466932e" dependencies = [ "serde", "serde_repr", - "serde_with 3.6.1", + "serde_with 3.7.0", ] [[package]] name = "bson" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce21468c1c9c154a85696bb25c20582511438edb6ad67f846ba1378ffdd80222" +checksum = "4d43b38e074cc0de2957f10947e376a1d88b9c4dbab340b590800cc1b2e066b2" dependencies = [ "ahash", "base64 0.13.1", "bitvec", "hex", - "indexmap 2.2.5", + "indexmap 2.2.6", "js-sys", "once_cell", "rand 0.8.5", @@ -917,9 +904,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.3" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -929,9 +916,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bytes-utils" @@ -954,9 +941,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -1001,7 +988,7 @@ dependencies = [ "shuttle-common-tests", "shuttle-proto", "shuttle-service", - "strum 0.26.1", + "strum 0.26.2", "tar", "tempfile", "tokio", @@ -1033,9 +1020,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" dependencies = [ "jobserver", "libc", @@ -1053,17 +1040,11 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1076,9 +1057,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.1" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -1086,35 +1067,35 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.0", + "strsim 0.11.1", ] [[package]] name = "clap_complete" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c" +checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1157,9 +1138,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -1244,9 +1225,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.0.1" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] @@ -1331,7 +1312,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "crossterm_winapi", "libc", "mio", @@ -1367,7 +1348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c" dependencies = [ "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1415,7 +1396,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1437,7 +1418,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core 0.20.8", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1479,9 +1460,9 @@ checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", @@ -1601,7 +1582,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1639,9 +1620,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -1652,7 +1633,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 1.0.109", @@ -1664,10 +1645,10 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1732,9 +1713,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "filetime" @@ -1884,7 +1865,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -1940,9 +1921,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "js-sys", @@ -1959,11 +1940,11 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "git2" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" +checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "libgit2-sys", "log", @@ -2058,18 +2039,18 @@ dependencies = [ [[package]] name = "gix-bitmap" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b6cd0f246180034ddafac9b00a112f19178135b21eb031b3f79355891f7325" +checksum = "a371db66cbd4e13f0ed9dc4c0fea712d7276805fccc877f77e96374d317e87ae" dependencies = [ "thiserror", ] [[package]] name = "gix-chunk" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003ec6deacf68076a0c157271a127e0bb2c031c1a41f7168cbe5d248d9b85c78" +checksum = "45c8751169961ba7640b513c3b24af61aa962c967aaf04116734975cd5af0c52" dependencies = [ "thiserror", ] @@ -2120,11 +2101,11 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ab5d22bc21840f4be0ba2e78df947ba14d8ba6999ea798f86b5bdb999edd0c" +checksum = "fbd06203b1a9b33a78c88252a625031b094d9e1b647260070c25b09910c0a804" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bstr", "gix-path", "libc", @@ -2149,9 +2130,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17077f0870ac12b55d2eed9cb3f56549e40def514c8a783a0a79177a8a76b7c5" +checksum = "180b130a4a41870edfbd36ce4169c7090bca70e195da783dea088dd973daa59c" dependencies = [ "bstr", "itoa", @@ -2239,7 +2220,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5db19298c5eeea2961e5b3bf190767a2d1f09b8802aeb5f258e42276350aff19" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bstr", "gix-features", "gix-path", @@ -2284,7 +2265,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c83a4fcc121b2f2e109088f677f89f85e7a8ebf39e8e6659c0ae54d4283b1650" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bstr", "btoi", "filetime", @@ -2314,13 +2295,13 @@ dependencies = [ [[package]] name = "gix-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75e7ab728059f595f6ddc1ad8771b8d6a231971ae493d9d5948ecad366ee8bb" +checksum = "1dff438f14e67e7713ab9332f5fd18c8f20eb7eb249494f6c2bf170522224032" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -2329,7 +2310,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a5cdcf491ecc9ce39dcc227216c540355fe0024ae7c38e94557752ca5ebb67f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "gix-commitgraph", "gix-date", "gix-hash", @@ -2421,9 +2402,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e0b521a5c345b7cd6a81e3e6f634407360a038c8b74ba14c621124304251b8" +checksum = "23623cf0f475691a6d943f898c4d0b89f5c1a2a64d0f92bce0e0322ee6528783" dependencies = [ "bstr", "gix-trace", @@ -2438,7 +2419,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dbbb92f75a38ef043c8bb830b339b38d0698d7f3746968b5fcbade7a880494d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bstr", "gix-attributes", "gix-config-value", @@ -2480,9 +2461,9 @@ dependencies = [ [[package]] name = "gix-quote" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d1b102957d975c6eb56c2b7ad9ac7f26d117299b910812b2e9bf086ec43496d" +checksum = "cbff4f9b9ea3fa7a25a70ee62f545143abef624ac6aa5884344e70c8b0a1d9ff" dependencies = [ "bstr", "gix-utils", @@ -2557,11 +2538,11 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022592a0334bdf77c18c06e12a7c0eaff28845c37e73c51a3e37d56dd495fb35" +checksum = "fddc27984a643b20dd03e97790555804f98cf07404e0e552c0ad8133266a79a1" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "gix-path", "libc", "windows-sys 0.52.0", @@ -2597,9 +2578,9 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b202d766a7fefc596e2cc6a89cda8ad8ad733aed82da635ac120691112a9b1" +checksum = "9b838b2db8f62c9447d483a4c28d251b67fee32741a82cb4d35e9eb4e9fdc5ab" [[package]] name = "gix-transport" @@ -2652,19 +2633,19 @@ dependencies = [ [[package]] name = "gix-utils" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60157a15b9f14b11af1c6817ad7a93b10b50b4e5136d98a127c46a37ff16eeb6" +checksum = "0066432d4c277f9877f091279a597ea5331f68ca410efc874f0bdfb1cd348f92" dependencies = [ - "fastrand 2.0.1", + "fastrand 2.0.2", "unicode-normalization", ] [[package]] name = "gix-validate" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac7cc36f496bd5d96cdca0f9289bb684480725d40db60f48194aa7723b883854" +checksum = "e39fc6e06044985eac19dd34d474909e517307582e462b2eb4c8fa51b6241545" dependencies = [ "bstr", "thiserror", @@ -2724,7 +2705,7 @@ dependencies = [ "bstr", "log", "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -2739,7 +2720,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.5", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -2758,7 +2739,7 @@ dependencies = [ "futures-sink", "futures-util", "http 1.1.0", - "indexmap 2.2.5", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -2823,6 +2804,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -2835,6 +2822,51 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hickory-proto" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "091a6fbccf4860009355e3efc52ff4acf37a63489aad7435372d44ceeb6fbbcf" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner 0.6.0", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand 0.8.5", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b8f021164e6a984c9030023544c57789c51760065cd510572fedcfb04164e8" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -2918,12 +2950,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" dependencies = [ "bytes", - "futures-util", + "futures-core", "http 1.1.0", "http-body 1.0.0", "pin-project-lite", @@ -2985,7 +3017,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.6", "tokio", "tower-service", "tracing", @@ -3170,9 +3202,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -3194,9 +3226,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "infer" @@ -3265,15 +3297,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.1" @@ -3285,9 +3308,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jni" @@ -3331,13 +3354,13 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "9.2.0" +version = "9.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" dependencies = [ "base64 0.21.7", "js-sys", - "pem 3.0.3", + "pem 3.0.4", "ring 0.17.8", "serde", "serde_json", @@ -3388,13 +3411,12 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] @@ -3410,9 +3432,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.15" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" dependencies = [ "cc", "libc", @@ -3501,7 +3523,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -3516,9 +3538,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" @@ -3592,9 +3614,9 @@ dependencies = [ [[package]] name = "mongodb" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de59562e5c71656c098d8e966641b31da87b89dc3dcb6e761d3b37dcdfa0cb72" +checksum = "ef206acb1b72389b49bc9985efe7eb1f8a9bb18e5680d262fac26c07f44025f1" dependencies = [ "async-trait", "base64 0.13.1", @@ -3630,8 +3652,8 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-util", - "trust-dns-proto 0.21.2", - "trust-dns-resolver 0.21.2", + "trust-dns-proto", + "trust-dns-resolver", "typed-builder", "uuid", "webpki-roots", @@ -3657,18 +3679,6 @@ dependencies = [ "pin-utils", ] -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "nom" version = "7.1.3" @@ -3841,7 +3851,7 @@ checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a" dependencies = [ "futures-core", "futures-sink", - "indexmap 2.2.5", + "indexmap 2.2.6", "js-sys", "once_cell", "pin-project-lite", @@ -4059,11 +4069,11 @@ dependencies = [ [[package]] name = "pem" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "base64 0.21.7", + "base64 0.22.0", "serde", ] @@ -4112,29 +4122,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -4270,9 +4280,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -4291,13 +4301,13 @@ checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.2", + "bitflags 2.5.0", "lazy_static", "num-traits", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", "rusty-fork", "tempfile", "unarray", @@ -4315,12 +4325,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", - "prost-derive 0.12.3", + "prost-derive 0.12.4", ] [[package]] @@ -4338,24 +4348,24 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] name = "prost-types" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" dependencies = [ - "prost 0.12.3", + "prost 0.12.4", ] [[package]] @@ -4366,9 +4376,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -4438,7 +4448,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.14", ] [[package]] @@ -4471,7 +4481,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52c4f3084aa3bc7dfbba4eff4fab2a54db4324965d8872ab933565e6fbd83bc6" dependencies = [ - "pem 3.0.3", + "pem 3.0.4", "ring 0.16.20", "time", "yasna", @@ -4488,25 +4498,25 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.14", "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.6", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -4526,7 +4536,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -4537,15 +4547,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.24" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", @@ -4553,6 +4563,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", + "hickory-resolver", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", @@ -4575,7 +4586,6 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "trust-dns-resolver 0.23.2", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -4601,7 +4611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01ff60778f96fb5a48adbe421d21bf6578ed58c0872d712e7e08593c195adff8" dependencies = [ "comma", - "nix 0.25.1", + "nix", "regex", "tempfile", "thiserror", @@ -4630,7 +4640,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.14", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -4736,11 +4746,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -4809,9 +4819,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" [[package]] name = "rusty-fork" @@ -4867,9 +4877,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -4880,9 +4890,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -4938,16 +4948,16 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -4955,9 +4965,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" dependencies = [ "itoa", "serde", @@ -4987,13 +4997,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -5045,15 +5055,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" +checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" dependencies = [ "base64 0.21.7", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.5", + "indexmap 2.2.6", "serde", "serde_derive", "serde_json", @@ -5081,7 +5091,7 @@ dependencies = [ "darling 0.20.8", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -5106,7 +5116,7 @@ checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -5254,7 +5264,7 @@ dependencies = [ "shuttle-common-tests", "shuttle-proto", "sqlx", - "strum 0.26.1", + "strum 0.26.2", "test-context", "thiserror", "tokio", @@ -5282,7 +5292,7 @@ dependencies = [ "serde", "serde_json", "shuttle-common-tests", - "syn 2.0.52", + "syn 2.0.58", "tokio", "trybuild", ] @@ -5312,7 +5322,7 @@ dependencies = [ "serde", "serde_json", "sqlx", - "strum 0.26.1", + "strum 0.26.2", "thiserror", "tonic 0.10.2", "tower", @@ -5373,7 +5383,7 @@ dependencies = [ "shuttle-proto", "shuttle-service", "sqlx", - "strum 0.26.1", + "strum 0.26.2", "tar", "tempfile", "thiserror", @@ -5435,7 +5445,7 @@ dependencies = [ "shuttle-proto", "snailquote", "sqlx", - "strum 0.26.1", + "strum 0.26.2", "tar", "tempfile", "test-context", @@ -5489,7 +5499,7 @@ dependencies = [ "futures-core", "http 0.2.12", "portpicker", - "prost 0.12.3", + "prost 0.12.4", "prost-types", "serde_json", "shuttle-common", @@ -5511,7 +5521,7 @@ dependencies = [ "mongodb", "once_cell", "portpicker", - "prost 0.12.3", + "prost 0.12.4", "rand 0.8.5", "serde_json", "shuttle-backends", @@ -5542,7 +5552,7 @@ dependencies = [ "shuttle-common-tests", "shuttle-proto", "sqlx", - "strum 0.26.1", + "strum 0.26.2", "thiserror", "tokio", "tonic 0.10.2", @@ -5655,9 +5665,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smart-default" @@ -5747,9 +5757,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" dependencies = [ "sqlx-core", "sqlx-macros", @@ -5760,9 +5770,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" dependencies = [ "ahash", "atoi", @@ -5771,7 +5781,6 @@ dependencies = [ "chrono", "crc", "crossbeam-queue", - "dotenvy", "either", "event-listener", "futures-channel", @@ -5781,7 +5790,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.2.5", + "indexmap 2.2.6", "log", "memchr", "once_cell", @@ -5805,9 +5814,9 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" dependencies = [ "proc-macro2", "quote", @@ -5818,14 +5827,13 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ - "atomic-write-file", "dotenvy", "either", - "heck", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -5845,13 +5853,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.4.2", + "bitflags 2.5.0", "byteorder", "bytes", "chrono", @@ -5889,13 +5897,13 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.4.2", + "bitflags 2.5.0", "byteorder", "chrono", "crc", @@ -5917,7 +5925,6 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha1", "sha2", "smallvec", "sqlx-core", @@ -5930,9 +5937,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" dependencies = [ "atoi", "chrono", @@ -5984,9 +5991,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" @@ -5996,11 +6003,11 @@ checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" [[package]] name = "strum" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ - "strum_macros 0.26.1", + "strum_macros 0.26.2", ] [[package]] @@ -6009,7 +6016,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", @@ -6018,15 +6025,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -6048,9 +6055,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -6126,7 +6133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.1", + "fastrand 2.0.2", "rustix", "windows-sys 0.52.0", ] @@ -6164,27 +6171,27 @@ checksum = "78ea17a2dc368aeca6f554343ced1b1e31f76d63683fa8016e5844bd7a5144a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -6199,9 +6206,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -6222,9 +6229,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", @@ -6247,9 +6254,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -6282,7 +6289,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -6297,9 +6304,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -6338,14 +6345,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.10" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.6", + "toml_edit 0.22.9", ] [[package]] @@ -6363,18 +6370,18 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.6" +version = "0.22.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -6427,7 +6434,7 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost 0.12.3", + "prost 0.12.4", "tokio", "tokio-stream", "tower", @@ -6462,7 +6469,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "bytes", "futures-core", "futures-util", @@ -6519,7 +6526,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] @@ -6628,31 +6635,6 @@ dependencies = [ "url", ] -[[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", - "data-encoding", - "enum-as-inner 0.6.0", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.4.0", - "ipnet", - "once_cell", - "rand 0.8.5", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] - [[package]] name = "trust-dns-resolver" version = "0.21.2" @@ -6670,28 +6652,7 @@ dependencies = [ "smallvec", "thiserror", "tokio", - "trust-dns-proto 0.21.2", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a3e6c3aff1718b3c73e395d1f35202ba2ffa847c6a62eea0db8fb4cfe30be6" -dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lru-cache", - "once_cell", - "parking_lot", - "rand 0.8.5", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto 0.23.2", + "trust-dns-proto", ] [[package]] @@ -6702,17 +6663,17 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9d3ba662913483d6722303f619e75ea10b7855b0f8e0d72799cf8621bb488f" +checksum = "8ad7eb6319ebadebca3dacf1f85a93bc54b73dd81b9036795f73de7ddfe27d5a" dependencies = [ - "basic-toml", "glob", "once_cell", "serde", "serde_derive", "serde_json", "termcolor", + "toml", ] [[package]] @@ -6767,7 +6728,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34778c17965aa2a08913b57e1f34db9b4a63f5de31768b55bf20d2795f921259" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.14", "rand 0.8.5", "serde", "web-time 1.1.0", @@ -6892,11 +6853,11 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.14", "serde", ] @@ -6997,7 +6958,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -7031,7 +6992,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7074,9 +7035,9 @@ dependencies = [ [[package]] name = "webbrowser" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b2391658b02c27719fc5a0a73d6e696285138e8b12fba9d4baa70451023c71" +checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" dependencies = [ "core-foundation", "home", @@ -7097,9 +7058,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "whoami" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fec781d48b41f8163426ed18e8fc2864c12937df9ce54c88ede7bd47270893e" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ "redox_syscall", "wasite", @@ -7107,9 +7068,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" [[package]] name = "winapi" @@ -7476,7 +7437,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.58", ] [[package]] diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index acc15c85c..e10486e81 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -5,8 +5,7 @@ use anyhow::{Context, Result}; use headers::{Authorization, HeaderMapExt}; use percent_encoding::utf8_percent_encode; use reqwest::header::HeaderMap; -use reqwest::RequestBuilder; -use reqwest::Response; +use reqwest::{RequestBuilder, Response}; use serde::{Deserialize, Serialize}; use shuttle_common::constants::headers::X_CARGO_SHUTTLE_VERSION; use shuttle_common::models::deployment::DeploymentRequest; @@ -89,20 +88,35 @@ impl ShuttleApiClient { project: &str, deployment_req: DeploymentRequest, ) -> Result { - let path = if self.beta { - format!("/projects/{project}") - } else { - format!("/projects/{project}/services/{project}") - }; + let path = format!("/projects/{project}/services/{project}"); let deployment_req = rmp_serde::to_vec(&deployment_req) .context("serialize DeploymentRequest as a MessagePack byte vector")?; let url = format!("{}{}", self.api_url, path); - let mut builder = if self.beta { - self.client.put(url) - } else { - self.client.post(url) - }; + let mut builder = self.client.post(url); + builder = self.set_auth_bearer(builder); + + builder + .header("Transfer-Encoding", "chunked") + .body(deployment_req) + .send() + .await + .context("failed to send deployment to the Shuttle server")? + .to_json() + .await + } + + pub async fn deploy_beta( + &self, + project: &str, + deployment_req: DeploymentRequest, + ) -> Result { + let path = format!("/projects/{project}"); + let deployment_req = rmp_serde::to_vec(&deployment_req) + .context("serialize DeploymentRequest as a MessagePack byte vector")?; + + let url = format!("{}{}", self.api_url, path); + let mut builder = self.client.put(url); builder = self.set_auth_bearer(builder); builder diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index 81d3758f1..537f7da3b 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -1701,6 +1701,17 @@ impl Shuttle { ); } + // End this early for beta platform. + if self.beta { + let deployment = client + .deploy_beta(self.ctx.project_name(), deployment_req) + .await + .map_err(suggestions::deploy::deploy_request_failure)?; + + deployment.colored_println(); + return Ok(CommandOutcome::Ok); + } + let deployment = client .deploy(self.ctx.project_name(), deployment_req) .await diff --git a/common/src/deployment.rs b/common/src/deployment.rs index ef93e39a4..49934e22d 100644 --- a/common/src/deployment.rs +++ b/common/src/deployment.rs @@ -19,6 +19,17 @@ pub enum State { Unknown, } +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Display, Serialize, EnumString)] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +#[strum(ascii_case_insensitive)] +pub enum EcsState { + Running, + #[strum(serialize = "in progress")] + InProgress, + Stopped, +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeploymentMetadata { pub env: Environment, diff --git a/common/src/models/deployment.rs b/common/src/models/deployment.rs index 565445300..877cafe25 100644 --- a/common/src/models/deployment.rs +++ b/common/src/models/deployment.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use std::{fmt::Display, str::FromStr}; use uuid::Uuid; -use crate::deployment::State; +use crate::deployment::{EcsState, State}; /// Max length of strings in the git metadata pub const GIT_STRINGS_MAX_LENGTH: usize = 80; @@ -29,6 +29,19 @@ pub struct Response { pub git_dirty: Option, } +#[derive(Deserialize, Serialize)] +pub struct EcsResponse { + pub id: String, + pub latest_deployment_state: EcsState, + pub running_id: Option, + pub updated_at: DateTime, + pub uri: String, + pub git_commit_id: Option, + pub git_commit_msg: Option, + pub git_branch: Option, + pub git_dirty: Option, +} + impl Display for Response { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -47,6 +60,47 @@ impl Display for Response { } } +impl EcsResponse { + pub fn colored_println(&self) { + let running_deployment = self + .running_id + .as_ref() + .map(|id| { + format!( + "\nRunning deployment: '{}' - {} ({})", + id, + "running".to_string().with( + crossterm::style::Color::from_str(EcsState::Running.get_color()).unwrap() + ), + self.uri + ) + }) + .unwrap_or(String::new()); + + // Stringify the state. + let latest_state = format!( + "{}", + self.latest_deployment_state + .to_string() + // Unwrap is safe because Color::from_str returns the color white if the argument is not a Color. + .with( + crossterm::style::Color::from_str(self.latest_deployment_state.get_color()) + .unwrap() + ) + ); + + let state_with_uri = match self.running_id { + None => format!("{latest_state} ({})", self.uri), + Some(_) => latest_state, + }; + + println!( + "Current deployment: '{}' - {}{running_deployment}", + self.id, state_with_uri + ) + } +} + impl State { /// We return a &str rather than a Color here, since `comfy-table` re-exports /// crossterm::style::Color and we depend on both `comfy-table` and `crossterm` @@ -62,6 +116,19 @@ impl State { } } +impl EcsState { + /// We return a &str rather than a Color here, since `comfy-table` re-exports + /// crossterm::style::Color and we depend on both `comfy-table` and `crossterm` + /// we may end up with two different versions of Color. + pub fn get_color(&self) -> &str { + match self { + EcsState::InProgress => "cyan", + EcsState::Running => "green", + EcsState::Stopped => "blue", + } + } +} + pub fn get_deployments_table( deployments: &Vec, service_name: &str, From ae3c5b03927d06976efacb3f228cb077563a9bfb 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, 16 Apr 2024 12:09:08 +0200 Subject: [PATCH 10/26] feat: add services client constructor for default headers (#1737) --- backends/src/client/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backends/src/client/mod.rs b/backends/src/client/mod.rs index 9319e8f55..2c2f0a424 100644 --- a/backends/src/client/mod.rs +++ b/backends/src/client/mod.rs @@ -60,6 +60,13 @@ impl ServicesApiClient { } } + pub fn new_with_default_headers(base: Uri, headers: HeaderMap) -> Self { + Self { + client: Self::builder().default_headers(headers).build().unwrap(), + base, + } + } + pub async fn get( &self, path: &str, From 81ecaaea3007c798c9ac1a307a4de4192f79d4c1 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Wed, 17 Apr 2024 16:11:17 +0200 Subject: [PATCH 11/26] feat(cargo-shuttle): beta deploy zip file, package name (#1742) * feat(cargo-shuttle): make zip file on beta deploy * feat(cargo-shuttle, service): deployment package name discovery * fix: clippy --- Cargo.lock | 125 +++++++++++++++++++++++- cargo-shuttle/Cargo.toml | 1 + cargo-shuttle/src/lib.rs | 166 +++++++++++++++++++++----------- common/src/models/deployment.rs | 6 +- service/src/builder.rs | 47 +++++---- 5 files changed, 269 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 894412d79..c1fa09851 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.8.11" @@ -930,6 +941,27 @@ dependencies = [ "either", ] +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "camino" version = "1.1.6" @@ -1002,6 +1034,7 @@ dependencies = [ "uuid", "walkdir", "webbrowser", + "zip", ] [[package]] @@ -1042,9 +1075,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.37" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1055,6 +1088,16 @@ dependencies = [ "windows-targets 0.52.4", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.4" @@ -1192,6 +1235,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.4.0" @@ -3236,6 +3285,15 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -4033,6 +4091,17 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.14" @@ -4046,6 +4115,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ "digest", + "hmac", + "password-hash", + "sha2", ] [[package]] @@ -7445,3 +7517,52 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/cargo-shuttle/Cargo.toml b/cargo-shuttle/Cargo.toml index bd541b49c..b36ee6d89 100644 --- a/cargo-shuttle/Cargo.toml +++ b/cargo-shuttle/Cargo.toml @@ -65,6 +65,7 @@ url = { workspace = true } uuid = { workspace = true, features = ["v4"] } walkdir = "2.3.3" webbrowser = "0.8.2" +zip = "0.6.6" [dev-dependencies] assert_cmd = "2.0.6" diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index 537f7da3b..e4adddbb7 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -9,7 +9,7 @@ use std::collections::{BTreeMap, HashMap}; use std::ffi::OsString; use std::fmt::Write as FmtWrite; use std::fs::{read_to_string, File}; -use std::io::stdout; +use std::io::{stdout, Read, Write}; use std::net::{Ipv4Addr, SocketAddr}; use std::path::{Path, PathBuf}; use std::process::exit; @@ -57,6 +57,7 @@ use shuttle_proto::{ provisioner::{provisioner_server::Provisioner, DatabaseRequest}, runtime::{self, LoadRequest, StartRequest, StopRequest}, }; +use shuttle_service::builder::{async_cargo_metadata, find_shuttle_packages}; use shuttle_service::{ builder::{build_workspace, BuiltService}, runner, Environment, @@ -69,6 +70,7 @@ use tokio::time::{sleep, Duration}; use tonic::{Request, Status}; use tracing::{debug, error, trace, warn}; use uuid::Uuid; +use zip::write::FileOptions; pub use crate::args::{Command, ProjectArgs, RunArgs, ShuttleArgs}; use crate::args::{ @@ -1656,11 +1658,26 @@ impl Shuttle { let client = self.client.as_ref().unwrap(); let working_directory = self.ctx.working_directory(); - let mut deployment_req: DeploymentRequest = DeploymentRequest { + let mut deployment_req = DeploymentRequest { no_test: args.no_test, ..Default::default() }; + if self.beta { + let manifest_path = working_directory.join("Cargo.toml"); + if !manifest_path.exists() { + bail!("Cargo manifest file not found: {}", manifest_path.display()); + } + let metadata = async_cargo_metadata(manifest_path.as_path()).await?; + let packages = find_shuttle_packages(&metadata)?; + let package_name = packages + .first() + .expect("at least one shuttle crate in the workspace") + .name + .to_owned(); + deployment_req.package_name = Some(package_name); + } + if let Ok(repo) = Repository::discover(working_directory) { let repo_path = repo .workdir() @@ -1690,7 +1707,7 @@ impl Shuttle { } } - deployment_req.data = self.make_archive(args.secret_args.secrets.clone())?; + deployment_req.data = self.make_archive(args.secret_args.secrets.clone(), self.beta)?; if deployment_req.data.len() > CREATE_SERVICE_BODY_LIMIT { bail!( r#"The project is too large - the limit is {} MB. \ @@ -2134,10 +2151,8 @@ impl Shuttle { Ok(CommandOutcome::Ok) } - fn make_archive(&self, secrets_file: Option) -> Result> { + fn make_archive(&self, secrets_file: Option, zip: bool) -> Result> { let include_patterns = self.ctx.assets(); - let encoder = GzEncoder::new(Vec::new(), Compression::new(3)); - let mut tar = Builder::new(encoder); let working_directory = self.ctx.working_directory(); @@ -2205,8 +2220,14 @@ impl Shuttle { continue; } + // zip file puts all files in root, tar puts all files nested in a dir at root level + let prefix = if zip { + working_directory + } else { + working_directory.parent().context("get parent dir")? + }; let mut name = path - .strip_prefix(working_directory.parent().context("get parent dir")?) + .strip_prefix(prefix) .context("strip prefix of path")? .to_owned(); @@ -2224,14 +2245,34 @@ impl Shuttle { bail!("No files included in upload."); } - // Append all the entries to the archive. - for (k, v) in archive_files { - debug!("Packing {k:?}"); - tar.append_path_with_name(k, v)?; - } + let bytes = if zip { + debug!("making zip archive"); + let mut zip = zip::ZipWriter::new(std::io::Cursor::new(Vec::new())); + for (path, name) in archive_files { + debug!("Packing {path:?}"); + zip.start_file( + name.to_str().expect("valid filename"), + FileOptions::default(), + )?; + let mut b = Vec::new(); + File::open(path)?.read_to_end(&mut b)?; + zip.write_all(&b)?; + } + let r = zip.finish().context("finish encoding zip archive")?; - let encoder = tar.into_inner().context("get encoder from tar archive")?; - let bytes = encoder.finish().context("finish up encoder")?; + r.into_inner() + } else { + debug!("making tar archive"); + let encoder = GzEncoder::new(Vec::new(), Compression::new(3)); + let mut tar = Builder::new(encoder); + for (path, name) in archive_files { + debug!("Packing {path:?}"); + tar.append_path_with_name(path, name)?; + } + let encoder = tar.into_inner().context("get encoder from tar archive")?; + + encoder.finish().context("finish encoding tar archive")? + }; debug!("Archive size: {} bytes", bytes.len()); Ok(bytes) @@ -2418,10 +2459,12 @@ pub enum CommandOutcome { mod tests { use flate2::read::GzDecoder; use tar::Archive; + use zip::ZipArchive; use crate::args::{DeployArgs, ProjectArgs, SecretsArgs}; use crate::Shuttle; use std::fs::{self, canonicalize}; + use std::io::Cursor; use std::path::PathBuf; pub fn path_from_workspace_root(path: &str) -> PathBuf { @@ -2432,32 +2475,43 @@ mod tests { dunce::canonicalize(path).unwrap() } - fn get_archive_entries(project_args: ProjectArgs, deploy_args: DeployArgs) -> Vec { + fn get_archive_entries( + project_args: ProjectArgs, + deploy_args: DeployArgs, + zip: bool, + ) -> Vec { let mut shuttle = Shuttle::new().unwrap(); shuttle.load_project(&project_args).unwrap(); let archive = shuttle - .make_archive(deploy_args.secret_args.secrets) + .make_archive(deploy_args.secret_args.secrets, zip) .unwrap(); - let tar = GzDecoder::new(&archive[..]); - let mut archive = Archive::new(tar); + if zip { + let mut zip = ZipArchive::new(Cursor::new(archive)).unwrap(); + (0..zip.len()) + .map(|i| zip.by_index(i).unwrap().name().to_owned()) + .collect() + } else { + let tar = GzDecoder::new(&archive[..]); + let mut archive = Archive::new(tar); - archive - .entries() - .unwrap() - .map(|entry| { - entry - .unwrap() - .path() - .unwrap() - .components() - .skip(1) - .collect::() - .display() - .to_string() - }) - .collect() + archive + .entries() + .unwrap() + .map(|entry| { + entry + .unwrap() + .path() + .unwrap() + .components() + .skip(1) + .collect::() + .display() + .to_string() + }) + .collect() + } } #[test] @@ -2481,29 +2535,32 @@ mod tests { working_directory: working_directory.clone(), name: Some("archiving-test".to_owned()), }; - let mut entries = get_archive_entries(project_args.clone(), Default::default()); + let mut entries = get_archive_entries(project_args.clone(), Default::default(), false); entries.sort(); - assert_eq!( - entries, - vec![ - ".gitignore", - ".ignore", - "Cargo.toml", - "Secrets.toml", // always included by default - "Secrets.toml.example", - "Shuttle.toml", - "asset1", // normal file - "asset2", // .gitignore'd, but included in Shuttle.toml - // asset3 is .ignore'd - "asset4", // .gitignore'd, but un-ignored in .ignore - "asset5", // .ignore'd, but included in Shuttle.toml - "dist/dist1", // .gitignore'd, but included in Shuttle.toml - "nested/static/nested1", // normal file - // nested/static/nestedignore is .gitignore'd - "src/main.rs", - ] - ); + let expected = vec![ + ".gitignore", + ".ignore", + "Cargo.toml", + "Secrets.toml", // always included by default + "Secrets.toml.example", + "Shuttle.toml", + "asset1", // normal file + "asset2", // .gitignore'd, but included in Shuttle.toml + // asset3 is .ignore'd + "asset4", // .gitignore'd, but un-ignored in .ignore + "asset5", // .ignore'd, but included in Shuttle.toml + "dist/dist1", // .gitignore'd, but included in Shuttle.toml + "nested/static/nested1", // normal file + // nested/static/nestedignore is .gitignore'd + "src/main.rs", + ]; + assert_eq!(entries, expected); + + // check that zip behaves the same way + let mut entries = get_archive_entries(project_args.clone(), Default::default(), true); + entries.sort(); + assert_eq!(entries, expected); fs::remove_file(working_directory.join("Secrets.toml")).unwrap(); let mut entries = get_archive_entries( @@ -2514,6 +2571,7 @@ mod tests { }, ..Default::default() }, + false, ); entries.sort(); diff --git a/common/src/models/deployment.rs b/common/src/models/deployment.rs index 877cafe25..475d4e37f 100644 --- a/common/src/models/deployment.rs +++ b/common/src/models/deployment.rs @@ -75,7 +75,7 @@ impl EcsResponse { self.uri ) }) - .unwrap_or(String::new()); + .unwrap_or_default(); // Stringify the state. let latest_state = format!( @@ -269,7 +269,11 @@ pub fn get_deployments_table( #[derive(Default, Deserialize, Serialize)] pub struct DeploymentRequest { + /// Alpha: tar archive. Beta: zip archive. pub data: Vec, + /// The cargo package name to compile and run. Required on beta. + pub package_name: Option, + /// Ignored on beta. pub no_test: bool, pub git_commit_id: Option, pub git_commit_msg: Option, diff --git a/service/src/builder.rs b/service/src/builder.rs index e60eaa3a4..a6f86828a 100644 --- a/service/src/builder.rs +++ b/service/src/builder.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use std::process::Stdio; use anyhow::{anyhow, bail, Context}; -use cargo_metadata::Package; +use cargo_metadata::{Metadata, Package}; use shuttle_common::constants::RUNTIME_NAME; use tokio::io::AsyncBufReadExt; use tracing::{debug, error, info, trace}; @@ -99,12 +99,30 @@ pub async fn build_workspace( } notification.abort(); + let metadata = async_cargo_metadata(manifest_path.as_path()).await?; + let packages = find_shuttle_packages(&metadata)?; + + let services = compile( + packages, + release_mode, + project_path.clone(), + metadata.target_directory.clone(), + deployment, + tx.clone(), + ) + .await?; + trace!("alpha packages compiled"); + + Ok(services) +} + +pub async fn async_cargo_metadata(manifest_path: &Path) -> anyhow::Result { let metadata = { // Modified implementaion of `cargo_metadata::MetadataCommand::exec` (from v0.15.3). // Uses tokio Command instead of std, to make this operation non-blocking. let mut cmd = tokio::process::Command::from( cargo_metadata::MetadataCommand::new() - .manifest_path(&manifest_path) + .manifest_path(manifest_path) .cargo_command(), ); @@ -120,11 +138,13 @@ pub async fn build_workspace( .ok_or(cargo_metadata::Error::NoJson)?; cargo_metadata::MetadataCommand::parse(json)? }; - trace!("Cargo metadata parsed"); - let mut alpha_packages = Vec::new(); + Ok(metadata) +} +pub fn find_shuttle_packages(metadata: &Metadata) -> anyhow::Result> { + let mut packages = Vec::new(); for member in metadata.workspace_packages() { // skip non-Shuttle-related crates if !member @@ -141,23 +161,12 @@ pub async fn build_workspace( .map(|d| format!("{} '{}'", d.name, d.req)) .collect::>(); shuttle_deps.sort(); - info!(name = member.name, deps = ?shuttle_deps, "Compiling workspace member with shuttle dependencies"); + info!(name = member.name, deps = ?shuttle_deps, "Found workspace member with shuttle dependencies"); ensure_binary(member)?; - alpha_packages.push(member); + packages.push(member.to_owned()); } - let services = compile( - alpha_packages, - release_mode, - project_path.clone(), - metadata.target_directory.clone(), - deployment, - tx.clone(), - ) - .await?; - trace!("alpha packages compiled"); - - Ok(services) + Ok(packages) } // Only used in deployer @@ -191,7 +200,7 @@ fn ensure_binary(package: &Package) -> anyhow::Result<()> { } async fn compile( - packages: Vec<&Package>, + packages: Vec, release_mode: bool, project_path: PathBuf, target_path: impl Into, From 6231811da58babffe2644b13d45138e4710f499d Mon Sep 17 00:00:00 2001 From: Iulian Barbu <14218860+iulianbarbu@users.noreply.github.com> Date: Thu, 18 Apr 2024 17:25:10 +0300 Subject: [PATCH 12/26] cargo-shuttle: added beta deployment status (#1740) * common: add failed deployment state * cargo-shuttle: add stopping ecs state * cargo-shuttle: add the beta deployment status cmd handler --- cargo-shuttle/src/args.rs | 2 +- cargo-shuttle/src/client.rs | 10 +++++++++ cargo-shuttle/src/lib.rs | 36 ++++++++++++++++++++++++--------- common/src/deployment.rs | 2 ++ common/src/models/deployment.rs | 12 ++++++++--- 5 files changed, 49 insertions(+), 13 deletions(-) diff --git a/cargo-shuttle/src/args.rs b/cargo-shuttle/src/args.rs index 60b31e89f..b62f26355 100644 --- a/cargo-shuttle/src/args.rs +++ b/cargo-shuttle/src/args.rs @@ -167,7 +167,7 @@ pub enum DeploymentCommand { /// View status of a deployment Status { /// ID of deployment to get status for - id: Uuid, + id: String, }, } diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index e10486e81..355a50257 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -246,6 +246,16 @@ impl ShuttleApiClient { self.get(path).await } + pub async fn deployment_status( + &self, + project: &str, + deployment_id: &str, + ) -> Result { + let path = format!("/projects/{project}/deployments/{deployment_id}"); + + self.get(path).await + } + pub async fn get_deployment_details( &self, project: &str, diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index e4adddbb7..94d1cd6d2 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -132,8 +132,7 @@ impl Shuttle { } if matches!( args.cmd, - Command::Deployment(..) - | Command::Resource(..) + Command::Resource(..) | Command::Stop | Command::Clean | Command::Status @@ -221,9 +220,14 @@ impl Shuttle { Command::Status => self.status().await, Command::Logs(logs_args) => self.logs(logs_args).await, Command::Deployment(DeploymentCommand::List { page, limit, raw }) => { + if self.beta { + unimplemented!(); + } self.deployments_list(page, limit, raw).await } - Command::Deployment(DeploymentCommand::Status { id }) => self.deployment_get(id).await, + Command::Deployment(DeploymentCommand::Status { id }) => { + self.deployment_get(id.as_str()).await + } Command::Resource(ResourceCommand::List { raw, show_secrets }) => { self.resources_list(raw, show_secrets).await } @@ -952,14 +956,28 @@ impl Shuttle { Ok(CommandOutcome::Ok) } - async fn deployment_get(&self, deployment_id: Uuid) -> Result { + async fn deployment_get(&self, deployment_id: &str) -> Result { let client = self.client.as_ref().unwrap(); - let deployment = client - .get_deployment_details(self.ctx.project_name(), &deployment_id) - .await - .map_err(suggestions::deployment::get_deployment_status_failure)?; - println!("{deployment}"); + if self.beta { + let deployment = client + .deployment_status(self.ctx.project_name(), deployment_id) + .await + .map_err(suggestions::deployment::get_deployment_status_failure)?; + deployment.colored_println(); + } else { + let deployment = client + .get_deployment_details( + self.ctx.project_name(), + &Uuid::from_str(deployment_id).map_err(|err| { + anyhow!("Provided deployment id is not a valid UUID: {err}") + })?, + ) + .await + .map_err(suggestions::deployment::get_deployment_status_failure)?; + + println!("{deployment}"); + } Ok(CommandOutcome::Ok) } diff --git a/common/src/deployment.rs b/common/src/deployment.rs index 49934e22d..fdfae7a6d 100644 --- a/common/src/deployment.rs +++ b/common/src/deployment.rs @@ -28,6 +28,8 @@ pub enum EcsState { #[strum(serialize = "in progress")] InProgress, Stopped, + Stopping, + Failed, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/common/src/models/deployment.rs b/common/src/models/deployment.rs index 475d4e37f..6ece4d74f 100644 --- a/common/src/models/deployment.rs +++ b/common/src/models/deployment.rs @@ -90,8 +90,12 @@ impl EcsResponse { ); let state_with_uri = match self.running_id { - None => format!("{latest_state} ({})", self.uri), - Some(_) => latest_state, + None if EcsState::Running == self.latest_deployment_state + || EcsState::InProgress == self.latest_deployment_state => + { + format!("{latest_state} ({})", self.uri) + } + _ => latest_state, }; println!( @@ -124,7 +128,9 @@ impl EcsState { match self { EcsState::InProgress => "cyan", EcsState::Running => "green", - EcsState::Stopped => "blue", + EcsState::Stopped => "dark_blue", + EcsState::Stopping => "blue", + EcsState::Failed => "red", } } } From 8767db4b526f26d4dd80c152f07a58923a1ddf32 Mon Sep 17 00:00:00 2001 From: Jocelyn Boullier Date: Thu, 18 Apr 2024 17:50:02 +0200 Subject: [PATCH 13/26] Add log streaming in beta platform (#1743) * feat(common): add new line for the logger * feat(cargo): add support for logs of new platform * fix(cargo): remove useless error handling * fix(cargo): remove id from LogItemBeta --- cargo-shuttle/src/lib.rs | 41 ++++++++++++++++++++++++++++++++++++++-- common/src/lib.rs | 2 ++ common/src/log.rs | 39 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index 94d1cd6d2..c25a89f24 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -136,7 +136,6 @@ impl Shuttle { | Command::Stop | Command::Clean | Command::Status - | Command::Logs { .. } ) { unimplemented!("This command is not yet implemented on the beta platform"); } @@ -218,7 +217,13 @@ impl Shuttle { Command::Run(run_args) => self.local_run(run_args).await, Command::Deploy(deploy_args) => self.deploy(deploy_args).await, Command::Status => self.status().await, - Command::Logs(logs_args) => self.logs(logs_args).await, + Command::Logs(logs_args) => { + if self.beta { + self.logs_beta(logs_args).await + } else { + self.logs(logs_args).await + } + } Command::Deployment(DeploymentCommand::List { page, limit, raw }) => { if self.beta { unimplemented!(); @@ -838,6 +843,38 @@ impl Shuttle { Ok(CommandOutcome::Ok) } + async fn logs_beta(&self, args: LogsArgs) -> Result { + let client = self.client.as_ref().unwrap(); + let mut stream = client + // TODO: use something else than a fake Uuid + .get_logs_ws(self.ctx.project_name(), &Uuid::new_v4()) + .await + .map_err(|err| { + suggestions::logs::get_logs_failure(err, "Connecting to the logs stream failed") + })?; + + while let Some(Ok(msg)) = stream.next().await { + if let tokio_tungstenite::tungstenite::Message::Text(line) = msg { + match serde_json::from_str::(&line) { + Ok(log) => { + if args.raw { + println!("{}", log.line); + } else { + println!("[{}] ({}) {}", log.timestamp, log.source, log.line); + } + } + Err(err) => { + // TODO better handle logs, by returning a different type than the log line + // if an error happened. + bail!(err); + } + } + } + } + + Ok(CommandOutcome::Ok) + } + async fn logs(&self, args: LogsArgs) -> Result { let client = self.client.as_ref().unwrap(); let id = if let Some(id) = args.id { diff --git a/common/src/lib.rs b/common/src/lib.rs index 1cfd71381..a4b429266 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -14,6 +14,8 @@ pub mod limits; pub mod log; #[cfg(feature = "service")] pub use log::LogItem; +#[cfg(feature = "service")] +pub use log::LogItemBeta; #[cfg(feature = "models")] pub mod models; pub mod resource; diff --git a/common/src/log.rs b/common/src/log.rs index 98ffa6f7a..89b68c935 100644 --- a/common/src/log.rs +++ b/common/src/log.rs @@ -47,6 +47,45 @@ pub struct LogItem { pub line: String, } +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct LogItemBeta { + /// Time log was captured + pub timestamp: DateTime, + + /// Stdout/stderr + pub source: String, + + /// The log line + pub line: String, +} + +impl LogItemBeta { + pub fn new(timestamp: DateTime, source: String, line: String) -> Self { + Self { + timestamp, + source, + line, + } + } +} + +#[cfg(feature = "display")] +impl std::fmt::Display for LogItemBeta { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let datetime: chrono::DateTime = DateTime::from(self.timestamp); + + write!( + f, + "{} [{}] {}", + datetime + .to_rfc3339_opts(chrono::SecondsFormat::Millis, false) + .dim(), + self.source, + self.line, + ) + } +} + const LOGLINE_MAX_CHARS: usize = 2048; const TRUNC_MSG: &str = "... (truncated)"; From 82876bdf469c0b0d1430e28a9d01c9a51a1cdd08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oddbj=C3=B8rn=20Gr=C3=B8dem?= <29732646+oddgrd@users.noreply.github.com> Date: Fri, 19 Apr 2024 08:59:11 +0200 Subject: [PATCH 14/26] feat(cargo-shuttle beta): enable resource list (#1744) --- cargo-shuttle/src/client.rs | 6 +++++- cargo-shuttle/src/lib.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index 355a50257..31b82c274 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -142,7 +142,11 @@ impl ShuttleApiClient { } pub async fn get_service_resources(&self, project: &str) -> Result> { - let path = format!("/projects/{project}/services/{project}/resources"); + let path = if self.beta { + format!("/projects/{project}/resources") + } else { + format!("/projects/{project}/services/{project}/resources") + }; self.get(path).await } diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index c25a89f24..562ee7684 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -132,7 +132,7 @@ impl Shuttle { } if matches!( args.cmd, - Command::Resource(..) + Command::Resource(ResourceCommand::Delete { .. }) | Command::Stop | Command::Clean | Command::Status From a44d095a42c7967c14cf321c3293694692807948 Mon Sep 17 00:00:00 2001 From: Iulian Barbu <14218860+iulianbarbu@users.noreply.github.com> Date: Fri, 19 Apr 2024 13:29:01 +0300 Subject: [PATCH 15/26] cargo-shuttle: added beta deployment list (#1741) * cargo-shuttle: make EcsResponse uri optional * cargo-shuttle: add pending ecs state * cargo-shuttle: add deployment list for beta platform --- Cargo.lock | 189 +++++++++++++++++--------------- cargo-shuttle/src/client.rs | 6 + cargo-shuttle/src/lib.rs | 40 ++++--- common/src/deployment.rs | 1 + common/src/models/deployment.rs | 139 ++++++++++++++++++++++- 5 files changed, 266 insertions(+), 109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1fa09851..7608983f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,9 +52,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-tzdata" @@ -244,7 +244,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -269,13 +269,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -1053,9 +1053,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" dependencies = [ "jobserver", "libc", @@ -1075,9 +1075,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1085,7 +1085,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1138,7 +1138,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -1392,12 +1392,12 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -1445,7 +1445,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -1467,7 +1467,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core 0.20.8", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -1631,7 +1631,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -1654,9 +1654,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" dependencies = [ "serde", ] @@ -1697,7 +1697,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -1914,7 +1914,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -2350,7 +2350,7 @@ checksum = "1dff438f14e67e7713ab9332f5fd18c8f20eb7eb249494f6c2bf170522224032" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -2627,9 +2627,9 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b838b2db8f62c9447d483a4c28d251b67fee32741a82cb4d35e9eb4e9fdc5ab" +checksum = "f924267408915fddcd558e3f37295cc7d6a3e50f8bd8b606cee0808c3915157e" [[package]] name = "gix-transport" @@ -2682,9 +2682,9 @@ dependencies = [ [[package]] name = "gix-utils" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0066432d4c277f9877f091279a597ea5331f68ca410efc874f0bdfb1cd348f92" +checksum = "35192df7fd0fa112263bad8021e2df7167df4cc2a6e6d15892e1e55621d3d4dc" dependencies = [ "fastrand 2.0.2", "unicode-normalization", @@ -3075,9 +3075,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", @@ -3143,7 +3143,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.0", - "hyper 1.2.0", + "hyper 1.3.1", "pin-project-lite", "socket2 0.5.6", "tokio", @@ -3394,9 +3394,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "685a7d121ee3f65ae4fddd72b25a04bb36b6af81bc0828f7d5434c0fe60fa3a2" dependencies = [ "libc", ] @@ -3581,7 +3581,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -4209,7 +4209,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -4352,9 +4352,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -4428,7 +4428,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -4721,9 +4721,9 @@ dependencies = [ [[package]] name = "rmp" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" dependencies = [ "byteorder", "num-traits", @@ -4732,9 +4732,9 @@ dependencies = [ [[package]] name = "rmp-serde" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" +checksum = "938a142ab806f18b88a97b0dea523d39e0fd730a064b035726adcfc58a8a5188" dependencies = [ "byteorder", "rmp", @@ -4996,9 +4996,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] @@ -5014,20 +5014,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ "indexmap 2.2.6", "itoa", @@ -5075,7 +5075,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -5163,7 +5163,7 @@ dependencies = [ "darling 0.20.8", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -5188,7 +5188,7 @@ checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -5364,7 +5364,7 @@ dependencies = [ "serde", "serde_json", "shuttle-common-tests", - "syn 2.0.58", + "syn 2.0.59", "tokio", "trybuild", ] @@ -6105,7 +6105,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -6127,9 +6127,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a" dependencies = [ "proc-macro2", "quote", @@ -6243,7 +6243,7 @@ checksum = "78ea17a2dc368aeca6f554343ced1b1e31f76d63683fa8016e5844bd7a5144a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -6263,7 +6263,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -6361,7 +6361,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -6457,7 +6457,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.5", + "winnow 0.6.6", ] [[package]] @@ -6598,7 +6598,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] @@ -7030,7 +7030,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", "wasm-bindgen-shared", ] @@ -7064,7 +7064,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7181,7 +7181,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -7208,7 +7208,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -7243,17 +7243,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -7270,9 +7271,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -7288,9 +7289,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -7306,9 +7307,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -7324,9 +7331,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -7342,9 +7349,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -7360,9 +7367,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -7378,9 +7385,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" @@ -7393,9 +7400,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" dependencies = [ "memchr", ] @@ -7423,7 +7430,7 @@ dependencies = [ "futures", "http 1.1.0", "http-body-util", - "hyper 1.2.0", + "hyper 1.3.1", "hyper-util", "log", "once_cell", @@ -7509,7 +7516,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.59", ] [[package]] diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index 31b82c274..28d507dbc 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -235,6 +235,12 @@ impl ShuttleApiClient { self.ws_get(path).await } + pub async fn deployments_beta(&self, project: &str) -> Result> { + let path = format!("/projects/{project}/deployments",); + + self.get(path).await + } + pub async fn get_deployments( &self, project: &str, diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index 562ee7684..faf60f1b8 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -32,6 +32,7 @@ use ignore::overrides::OverrideBuilder; use ignore::WalkBuilder; use indicatif::ProgressBar; use indoc::{formatdoc, printdoc}; +use shuttle_common::models::deployment::deployments_table_beta; use shuttle_common::{ constants::{ API_URL_DEFAULT, DEFAULT_IDLE_MINUTES, EXAMPLES_REPO, EXECUTABLE_DIRNAME, @@ -225,9 +226,6 @@ impl Shuttle { } } Command::Deployment(DeploymentCommand::List { page, limit, raw }) => { - if self.beta { - unimplemented!(); - } self.deployments_list(page, limit, raw).await } Command::Deployment(DeploymentCommand::Status { id }) => { @@ -970,21 +968,33 @@ impl Shuttle { let limit = limit + 1; let proj_name = self.ctx.project_name(); - let mut deployments = client - .get_deployments(proj_name, page, limit) - .await - .map_err(suggestions::deployment::get_deployments_list_failure)?; - let page_hint = if deployments.len() == limit as usize { - deployments.pop(); - true + + let deployments_len = if self.beta { + let deployments = client + .deployments_beta(proj_name) + .await + .map_err(suggestions::deployment::get_deployments_list_failure)?; + let table = deployments_table_beta(&deployments, proj_name, raw); + println!("{table}"); + deployments.len() } else { - false - }; - let table = get_deployments_table(&deployments, proj_name, page, raw, page_hint); + let mut deployments = client + .get_deployments(proj_name, page, limit) + .await + .map_err(suggestions::deployment::get_deployments_list_failure)?; + let page_hint = if deployments.len() == limit as usize { + deployments.pop(); + true + } else { + false + }; + let table = get_deployments_table(&deployments, proj_name, page, raw, page_hint); - println!("{table}"); + println!("{table}"); + deployments.len() + }; - if deployments.is_empty() { + if deployments_len == 0 { println!("Run `cargo shuttle deploy` to deploy your project."); } else { println!("Run `cargo shuttle logs ` to get logs for a given deployment."); diff --git a/common/src/deployment.rs b/common/src/deployment.rs index fdfae7a6d..7c139507a 100644 --- a/common/src/deployment.rs +++ b/common/src/deployment.rs @@ -24,6 +24,7 @@ pub enum State { #[strum(serialize_all = "lowercase")] #[strum(ascii_case_insensitive)] pub enum EcsState { + Pending, Running, #[strum(serialize = "in progress")] InProgress, diff --git a/common/src/models/deployment.rs b/common/src/models/deployment.rs index 6ece4d74f..4402cc803 100644 --- a/common/src/models/deployment.rs +++ b/common/src/models/deployment.rs @@ -35,7 +35,7 @@ pub struct EcsResponse { pub latest_deployment_state: EcsState, pub running_id: Option, pub updated_at: DateTime, - pub uri: String, + pub uri: Option, pub git_commit_id: Option, pub git_commit_msg: Option, pub git_branch: Option, @@ -67,12 +67,15 @@ impl EcsResponse { .as_ref() .map(|id| { format!( - "\nRunning deployment: '{}' - {} ({})", + "\nRunning deployment: '{}' - {} {}", id, "running".to_string().with( crossterm::style::Color::from_str(EcsState::Running.get_color()).unwrap() ), self.uri + .as_ref() + .map(|inner| format!("({inner})")) + .unwrap_or("".to_string()) ) }) .unwrap_or_default(); @@ -93,7 +96,12 @@ impl EcsResponse { None if EcsState::Running == self.latest_deployment_state || EcsState::InProgress == self.latest_deployment_state => { - format!("{latest_state} ({})", self.uri) + let uri = self + .uri + .as_ref() + .map(|inner| format!(" ({inner})")) + .unwrap_or_default(); + format!("{latest_state}{uri}") } _ => latest_state, }; @@ -126,6 +134,7 @@ impl EcsState { /// we may end up with two different versions of Color. pub fn get_color(&self) -> &str { match self { + EcsState::Pending => "dark_yellow", EcsState::InProgress => "cyan", EcsState::Running => "green", EcsState::Stopped => "dark_blue", @@ -135,6 +144,130 @@ impl EcsState { } } +pub fn deployments_table_beta( + deployments: &Vec, + project_name: &str, + raw: bool, +) -> String { + if deployments.is_empty() { + // The page starts at 1 in the CLI. + let mut s = "No deployments are linked to this service\n".to_string(); + if !raw { + s = s.yellow().bold().to_string(); + } + + s + } else { + let mut table = Table::new(); + + if raw { + table + .load_preset(NOTHING) + .set_content_arrangement(ContentArrangement::Disabled) + .set_header(vec![ + Cell::new("Deployment ID").set_alignment(CellAlignment::Left), + Cell::new("Status").set_alignment(CellAlignment::Left), + Cell::new("Last updated").set_alignment(CellAlignment::Left), + Cell::new("Commit ID").set_alignment(CellAlignment::Left), + Cell::new("Commit Message").set_alignment(CellAlignment::Left), + Cell::new("Branch").set_alignment(CellAlignment::Left), + Cell::new("Dirty").set_alignment(CellAlignment::Left), + ]); + } else { + table + .load_preset(UTF8_FULL) + .apply_modifier(UTF8_ROUND_CORNERS) + .set_content_arrangement(ContentArrangement::DynamicFullWidth) + .set_header(vec![ + Cell::new("Deployment ID") + .set_alignment(CellAlignment::Center) + .add_attribute(Attribute::Bold), + Cell::new("Status") + .set_alignment(CellAlignment::Center) + .add_attribute(Attribute::Bold), + Cell::new("Last updated") + .set_alignment(CellAlignment::Center) + .add_attribute(Attribute::Bold), + Cell::new("Commit ID") + .set_alignment(CellAlignment::Center) + .add_attribute(Attribute::Bold), + Cell::new("Commit Message") + .set_alignment(CellAlignment::Center) + .add_attribute(Attribute::Bold), + Cell::new("Branch") + .set_alignment(CellAlignment::Center) + .add_attribute(Attribute::Bold), + Cell::new("Dirty") + .set_alignment(CellAlignment::Center) + .add_attribute(Attribute::Bold), + ]); + } + + for deploy in deployments.iter() { + let truncated_commit_id = deploy + .git_commit_id + .as_ref() + .map_or(String::from(GIT_OPTION_NONE_TEXT), |val| { + val.chars().take(7).collect() + }); + + let truncated_commit_msg = deploy + .git_commit_msg + .as_ref() + .map_or(String::from(GIT_OPTION_NONE_TEXT), |val| { + val.chars().take(24).collect::() + }); + + if raw { + table.add_row(vec![ + Cell::new(&deploy.id), + Cell::new(&deploy.latest_deployment_state), + Cell::new(deploy.updated_at.format("%Y-%m-%dT%H:%M:%SZ")), + Cell::new(truncated_commit_id), + Cell::new(truncated_commit_msg), + Cell::new( + deploy + .git_branch + .as_ref() + .map_or(GIT_OPTION_NONE_TEXT, |val| val as &str), + ), + Cell::new( + deploy + .git_dirty + .map_or(String::from(GIT_OPTION_NONE_TEXT), |val| val.to_string()), + ), + ]); + } else { + table.add_row(vec![ + Cell::new(&deploy.id), + Cell::new(&deploy.latest_deployment_state) + // Unwrap is safe because Color::from_str returns the color white if str is not a Color. + .fg(Color::from_str(deploy.latest_deployment_state.get_color()).unwrap()) + .set_alignment(CellAlignment::Center), + Cell::new(deploy.updated_at.format("%Y-%m-%dT%H:%M:%SZ")) + .set_alignment(CellAlignment::Center), + Cell::new(truncated_commit_id), + Cell::new(truncated_commit_msg), + Cell::new( + deploy + .git_branch + .as_ref() + .map_or(GIT_OPTION_NONE_TEXT, |val| val as &str), + ), + Cell::new( + deploy + .git_dirty + .map_or(String::from(GIT_OPTION_NONE_TEXT), |val| val.to_string()), + ) + .set_alignment(CellAlignment::Center), + ]); + } + } + + format!("\nMost recent deployments for {project_name}\n{table}\n") + } +} + pub fn get_deployments_table( deployments: &Vec, service_name: &str, From fe9f49c2c755f8d4eb32f7c07201f2b99a257271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oddbj=C3=B8rn=20Gr=C3=B8dem?= <29732646+oddgrd@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:52:31 +0200 Subject: [PATCH 16/26] feat(c-s beta): enable resource delete (#1745) --- cargo-shuttle/src/client.rs | 19 ++++++++++++------- cargo-shuttle/src/lib.rs | 8 +------- common/src/lib.rs | 8 ++++++++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index 28d507dbc..d5985c6b9 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -156,13 +156,18 @@ impl ShuttleApiClient { project: &str, resource_type: &resource::Type, ) -> Result<()> { - let path = format!( - "/projects/{project}/services/{project}/resources/{}", - utf8_percent_encode( - &resource_type.to_string(), - percent_encoding::NON_ALPHANUMERIC - ), - ); + let r#type = resource_type.to_string(); + + let r#type = utf8_percent_encode(&r#type, percent_encoding::NON_ALPHANUMERIC).to_owned(); + + let path = if self.beta { + format!("/projects/{project}/resources/{}", r#type) + } else { + format!( + "/projects/{project}/services/{project}/resources/{}", + r#type + ) + }; self.delete(path).await } diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index faf60f1b8..6712d01ca 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -131,13 +131,7 @@ impl Shuttle { ) { unimplemented!("This command is deprecated on the beta platform"); } - if matches!( - args.cmd, - Command::Resource(ResourceCommand::Delete { .. }) - | Command::Stop - | Command::Clean - | Command::Status - ) { + if matches!(args.cmd, Command::Stop | Command::Clean | Command::Status) { unimplemented!("This command is not yet implemented on the beta platform"); } eprintln!("INFO: Using beta platform API"); diff --git a/common/src/lib.rs b/common/src/lib.rs index a4b429266..6d2ffb36f 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -162,6 +162,14 @@ impl DatabaseInfo { self.database_name, ) } + + pub fn role_name(&self) -> String { + self.role_name.to_string() + } + + pub fn database_name(&self) -> String { + self.database_name.to_string() + } } /// Used to request a container from the local run provisioner From b84ea8fc64c237ce204e5868ab22af1a9d119b6f 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, 23 Apr 2024 08:10:35 +0200 Subject: [PATCH 17/26] feat: support secrets on beta platform (#1748) Co-authored-by: jonaro00 <54029719+jonaro00@users.noreply.github.com> --- cargo-shuttle/src/lib.rs | 31 ++++++++++++++++++++++++++++--- common/src/models/deployment.rs | 4 +++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index 6712d01ca..eb8120b34 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -1724,9 +1724,34 @@ impl Shuttle { if self.beta { let manifest_path = working_directory.join("Cargo.toml"); - if !manifest_path.exists() { - bail!("Cargo manifest file not found: {}", manifest_path.display()); - } + + // Look for a secrets file, first in the command args, and if it isn't there look + // in the root of the crate or workspace. + let secrets_file = args.secret_args.secrets.clone().or_else(|| { + let secrets_file = manifest_path.parent().unwrap().join("Secrets.toml"); + + if secrets_file.exists() && secrets_file.is_file() { + Some(secrets_file) + } else { + None + } + }); + + if let Some(secrets_file) = secrets_file { + trace!("Loading secrets from {}", secrets_file.display()); + if let Ok(secrets_str) = read_to_string(&secrets_file) { + let secrets = toml::from_str::>(&secrets_str)?; + + trace!(keys = ?secrets.keys(), "available secrets"); + + deployment_req.secrets = Some(secrets); + } else { + trace!("No secrets were loaded"); + } + } else { + trace!("No secrets file was found"); + }; + let metadata = async_cargo_metadata(manifest_path.as_path()).await?; let packages = find_shuttle_packages(&metadata)?; let package_name = packages diff --git a/common/src/models/deployment.rs b/common/src/models/deployment.rs index 4402cc803..2cafa72a0 100644 --- a/common/src/models/deployment.rs +++ b/common/src/models/deployment.rs @@ -6,7 +6,7 @@ use comfy_table::{ }; use crossterm::style::Stylize; use serde::{Deserialize, Serialize}; -use std::{fmt::Display, str::FromStr}; +use std::{collections::HashMap, fmt::Display, str::FromStr}; use uuid::Uuid; use crate::deployment::{EcsState, State}; @@ -412,6 +412,8 @@ pub struct DeploymentRequest { pub data: Vec, /// The cargo package name to compile and run. Required on beta. pub package_name: Option, + /// Secrets to add before this deployment. Ignored on alpha. + pub secrets: Option>, /// Ignored on beta. pub no_test: bool, pub git_commit_id: Option, From 90bd1118d41c2d37c10a96dc52b47eb56071fa4e Mon Sep 17 00:00:00 2001 From: Jocelyn Boullier Date: Tue, 23 Apr 2024 09:51:00 +0200 Subject: [PATCH 18/26] feat(common): add building EcsState (#1752) --- common/src/deployment.rs | 1 + common/src/models/deployment.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/common/src/deployment.rs b/common/src/deployment.rs index 7c139507a..65e464760 100644 --- a/common/src/deployment.rs +++ b/common/src/deployment.rs @@ -25,6 +25,7 @@ pub enum State { #[strum(ascii_case_insensitive)] pub enum EcsState { Pending, + Building, Running, #[strum(serialize = "in progress")] InProgress, diff --git a/common/src/models/deployment.rs b/common/src/models/deployment.rs index 2cafa72a0..39e1bdd7b 100644 --- a/common/src/models/deployment.rs +++ b/common/src/models/deployment.rs @@ -135,6 +135,7 @@ impl EcsState { pub fn get_color(&self) -> &str { match self { EcsState::Pending => "dark_yellow", + EcsState::Building => "yellow", EcsState::InProgress => "cyan", EcsState::Running => "green", EcsState::Stopped => "dark_blue", From f1f4b4e4fdee33a147c351c331c06ce824ce9d75 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:40:27 +0200 Subject: [PATCH 19/26] feat(cargo-shuttle): nits --- cargo-shuttle/src/args.rs | 2 +- cargo-shuttle/src/client.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-shuttle/src/args.rs b/cargo-shuttle/src/args.rs index 30ef92976..2fdaa65b6 100644 --- a/cargo-shuttle/src/args.rs +++ b/cargo-shuttle/src/args.rs @@ -40,7 +40,7 @@ pub struct ShuttleArgs { #[arg(long, env = "SHUTTLE_DEBUG")] pub debug: bool, /// Target Shuttle's development environment - #[arg(long, env = "SHUTTLE_BETA")] + #[arg(long, env = "SHUTTLE_BETA", hide = true)] pub beta: bool, #[command(subcommand)] diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index b052b77db..e2b0e9882 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -39,7 +39,7 @@ impl ShuttleApiClient { )])) .unwrap(), ) - .timeout(Duration::from_secs(60)) + .timeout(Duration::from_secs(300)) // TODO: adjust .build() .unwrap(), api_url, From b52786b96e8ecee7bf6ea3bfd67a17e832346618 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Tue, 23 Apr 2024 12:02:54 +0200 Subject: [PATCH 20/26] fix(cargo-shuttle): skip org project listing on beta --- cargo-shuttle/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index b55153c63..abeb93730 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -2101,6 +2101,11 @@ impl Shuttle { println!("{}", "Personal Projects".bold()); println!("{projects_table}"); + if self.beta { + println!("Not listing org projects (not implemented yet on beta)"); + return Ok(CommandOutcome::Ok); + } + let orgs = client.get_organizations_list().await?; for org in orgs { From 85a8d54da6f6dd9524f81e13ba7333fce516db61 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Tue, 23 Apr 2024 14:37:40 +0200 Subject: [PATCH 21/26] fix(backends): switch to http otel collector for compatibility with beta --- extras/otel/otel-collector-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/extras/otel/otel-collector-config.yaml b/extras/otel/otel-collector-config.yaml index 1eda42279..5f209e83e 100644 --- a/extras/otel/otel-collector-config.yaml +++ b/extras/otel/otel-collector-config.yaml @@ -2,6 +2,7 @@ receivers: otlp: protocols: grpc: + http: # The hostmetrics receiver is required to get correct infrastructure metrics in Datadog. hostmetrics: collection_interval: 10s From 3fc73ea9c788f40f099e5b91d73724f13674be90 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Tue, 23 Apr 2024 15:36:24 +0200 Subject: [PATCH 22/26] fix(runtime): make compatible with alpha & beta --- runtime/src/alpha.rs | 102 +++++++++++++++++++++++++++++++++---------- runtime/src/args.rs | 80 --------------------------------- runtime/src/lib.rs | 1 - 3 files changed, 78 insertions(+), 105 deletions(-) delete mode 100644 runtime/src/args.rs diff --git a/runtime/src/alpha.rs b/runtime/src/alpha.rs index 3c2645950..4cf6c9a75 100644 --- a/runtime/src/alpha.rs +++ b/runtime/src/alpha.rs @@ -29,20 +29,65 @@ use tokio_stream::wrappers::ReceiverStream; use tokio_util::sync::CancellationToken; use tonic::{transport::Server, Request, Response, Status}; -use crate::args::args; use crate::print_version; -// uses custom macro instead of clap to reduce dependency weight -args! { - pub struct Args { - // The port to open the gRPC control layer on. - // The address to expose for the service is given in the StartRequest. - "--port" => pub port: u16, +#[derive(Default)] +struct Args { + /// Enable compatibility with beta platform + beta: bool, + /// Alpha (required): Port to open gRPC server on + port: Option, + /// Beta (required): Address to bind the gRPC server to + address: Option, +} + +impl Args { + // uses simple arg parsing logic instead of clap to reduce dependency weight + fn parse() -> anyhow::Result { + let mut args = Self::default(); + + // The first argument is the path of the executable + let mut args_iter = std::env::args().skip(1); + + while let Some(arg) = args_iter.next() { + match arg.as_str() { + "--beta" => { + args.beta = true; + } + "--port" => { + let port = args_iter + .next() + .context("missing port value")? + .parse() + .context("invalid port value")?; + args.port = Some(port); + } + "--address" => { + let address = args_iter + .next() + .context("missing address value")? + .parse() + .context("invalid address value")?; + args.address = Some(address); + } + _ => {} + } + } + + if args.beta { + if args.address.is_none() { + return Err(anyhow::anyhow!("--address is required with --beta")); + } + } else if args.port.is_none() { + return Err(anyhow::anyhow!("--port is required")); + } + + Ok(args) } } pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + Send + 'static) { - // `--version` overrides any other arguments. + // `--version` overrides any other arguments. Used by cargo-shuttle to check compatibility on local runs. if std::env::args().any(|arg| arg == "--version") { print_version(); return; @@ -88,7 +133,11 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S } // where to serve the gRPC control layer - let addr = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), args.port); + let addr = if args.beta { + args.address.unwrap() + } else { + SocketAddr::new(Ipv4Addr::LOCALHOST.into(), args.port.unwrap()) + }; let mut server_builder = Server::builder() .http2_keepalive_interval(Some(Duration::from_secs(60))) @@ -99,7 +148,7 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S let cloned_token = token.clone(); let router = { - let alpha = Alpha::new(loader, runner, token); + let alpha = Alpha::new(args.beta, loader, runner, token); let svc = RuntimeServer::new(alpha); server_builder.add_service(svc) @@ -125,6 +174,8 @@ pub enum State { } pub struct Alpha { + /// alter behaviour to interact with the new platform + beta: bool, // Mutexes are for interior mutability stopped_tx: Sender<(StopReason, String)>, kill_tx: Mutex>>, @@ -138,10 +189,11 @@ pub struct Alpha { } impl Alpha { - pub fn new(loader: L, runner: R, cancellation_token: CancellationToken) -> Self { + pub fn new(beta: bool, loader: L, runner: R, cancellation_token: CancellationToken) -> Self { let (stopped_tx, _stopped_rx) = broadcast::channel(10); Self { + beta, stopped_tx, kill_tx: Mutex::new(None), loader: Mutex::new(Some(loader)), @@ -251,24 +303,26 @@ where } }; - println!("setting current state to healthy"); *self.state.lock().unwrap() = State::Loading; let state = self.state.clone(); let cancellation_token = self.cancellation_token.clone(); - // Ensure that the runtime is set to unhealthy if it doesn't reach the running state after - // it has sent a load response, so that the ECS task will fail. - tokio::spawn(async move { - // Note: The timeout is quite low as we are not actually provisioning resources after - // sending the load response. - tokio::time::sleep(Duration::from_secs(180)).await; - if !matches!(state.lock().unwrap().deref(), State::Running) { - println!("the runtime failed to enter the running state before timing out"); - - cancellation_token.cancel(); - } - }); + // State and cancellation is not used in alpha + if self.beta { + // Ensure that the runtime is set to unhealthy if it doesn't reach the running state after + // it has sent a load response, so that the ECS task will fail. + tokio::spawn(async move { + // Note: The timeout is quite low as we are not actually provisioning resources after + // sending the load response. + tokio::time::sleep(Duration::from_secs(180)).await; + if !matches!(state.lock().unwrap().deref(), State::Running) { + println!("the runtime failed to enter the running state before timing out"); + + cancellation_token.cancel(); + } + }); + } Ok(Response::new(LoadResponse { success: true, diff --git a/runtime/src/args.rs b/runtime/src/args.rs deleted file mode 100644 index 1c2a48b9c..000000000 --- a/runtime/src/args.rs +++ /dev/null @@ -1,80 +0,0 @@ -#[derive(Debug)] -pub enum Error { - DuplicatedArgument { arg: &'static str }, - MissingRequiredArgument { arg: &'static str }, - UnexpectedArgument { arg: String }, - - InvalidValue { arg: &'static str, value: String }, - MissingValue { arg: &'static str }, -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::DuplicatedArgument { arg } => write!(f, "duplicated argument {arg}"), - Self::MissingRequiredArgument { arg } => write!(f, "missing required argument {arg}"), - Self::UnexpectedArgument { arg } => write!(f, "unexpected argument: {arg}"), - - Self::InvalidValue { arg, value } => { - write!(f, "invalid value for argument {arg}: {value}") - } - Self::MissingValue { arg } => write!(f, "missing value for argument {arg}"), - } - } -} - -impl std::error::Error for Error {} - -macro_rules! args { - // Internal rules used to handle optional default values - (@unwrap $arg:literal, $field:ident $(,)?) => { - $field.ok_or_else(|| $crate::args::Error::MissingRequiredArgument { arg: $arg })? - }; - (@unwrap $arg:literal, $field:ident, $default:literal) => { - $field.unwrap_or_else(|| $default.parse().unwrap()) - }; - - ( - pub struct $struct:ident { - $($arg:literal => $(#[arg(default_value = $default:literal)])? pub $field:ident: $ty:ty),+ $(,)? - } - ) => { - #[derive(::std::fmt::Debug)] - pub struct $struct { - $(pub $field: $ty,)+ - } - - impl $struct { - pub fn parse() -> ::std::result::Result { - $(let mut $field: ::std::option::Option<$ty> = None;)+ - - // The first argument is the path of the executable. - let mut args_iter = ::std::env::args().skip(1); - while let ::std::option::Option::Some(arg) = args_iter.next() { - match arg.as_str() { - $($arg => { - if $field.is_some() { - return ::std::result::Result::Err($crate::args::Error::DuplicatedArgument { arg: $arg }); - } - let raw_value = args_iter - .next() - .ok_or_else(|| $crate::args::Error::MissingValue { arg: $arg })?; - let value = raw_value.parse().map_err(|_| $crate::args::Error::InvalidValue { - arg: $arg, - value: raw_value, - })?; - $field = ::std::option::Option::Some(value); - })+ - _ => return ::std::result::Result::Err($crate::args::Error::UnexpectedArgument { arg }), - } - } - - ::std::result::Result::Ok($struct { - $($field: $crate::args::args!(@unwrap $arg, $field, $($default)?),)+ - }) - } - } - } -} - -pub(crate) use args; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 02ebdd4ac..aea389e8c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -16,7 +16,6 @@ pub use async_trait::async_trait; pub use tokio; mod alpha; -mod args; const NAME: &str = env!("CARGO_PKG_NAME"); const VERSION: &str = env!("CARGO_PKG_VERSION"); From a45addb476cde6aaeab7853963eae3430b156ce2 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:08:14 +0200 Subject: [PATCH 23/26] fix: make services compatible with beta runtime --- cargo-shuttle/src/lib.rs | 9 +++++++-- deployer/src/runtime_manager.rs | 13 ++++++++++--- runtime/tests/integration/helpers.rs | 10 ++++++++-- service/src/runner.rs | 20 +++++++++++++++++--- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index abeb93730..5a48858ce 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -1092,6 +1092,7 @@ impl Shuttle { } async fn spin_local_runtime( + beta: bool, run_args: &RunArgs, service: &BuiltService, idx: u16, @@ -1155,9 +1156,13 @@ impl Shuttle { } let runtime_executable = service.executable_path.clone(); + let port = + portpicker::pick_unused_port().expect("unable to find available port for gRPC server"); // Child process and gRPC client for sending requests to it let (mut runtime, mut runtime_client) = runner::start( - portpicker::pick_unused_port().expect("unable to find available port for gRPC server"), + beta, + port, + SocketAddr::new(Ipv4Addr::LOCALHOST.into(), port), runtime_executable, service.workspace_path.as_path(), ) @@ -1502,7 +1507,7 @@ impl Shuttle { // We must cover the case of starting multiple workspace services and receiving a signal in parallel. // This must stop all the existing runtimes and creating new ones. signal_received = tokio::select! { - res = Shuttle::spin_local_runtime(&run_args, service, i as u16) => { + res = Shuttle::spin_local_runtime(self.beta, &run_args, service, i as u16) => { match res { Ok(runtime) => { Shuttle::add_runtime_info(runtime, &mut runtimes).await?; diff --git a/deployer/src/runtime_manager.rs b/deployer/src/runtime_manager.rs index a0c261adc..bd9162b4e 100644 --- a/deployer/src/runtime_manager.rs +++ b/deployer/src/runtime_manager.rs @@ -1,5 +1,6 @@ use std::{ collections::HashMap, + net::{Ipv4Addr, SocketAddr}, path::{Path, PathBuf}, sync::Arc, }; @@ -57,9 +58,15 @@ impl RuntimeManager { .unwrap_or_default() ); - let (mut process, runtime_client) = runner::start(port, runtime_executable, project_path) - .await - .context("failed to start shuttle runtime")?; + let (mut process, runtime_client) = runner::start( + false, + port, + SocketAddr::new(Ipv4Addr::LOCALHOST.into(), port), + runtime_executable, + project_path, + ) + .await + .context("failed to start shuttle runtime")?; let stdout = process .stdout diff --git a/runtime/tests/integration/helpers.rs b/runtime/tests/integration/helpers.rs index 9fe093634..2a5cf1089 100644 --- a/runtime/tests/integration/helpers.rs +++ b/runtime/tests/integration/helpers.rs @@ -45,8 +45,14 @@ pub async fn spawn_runtime(project_path: &str) -> Result { let runtime_executable = service.executable_path.clone(); - let (runtime, runtime_client) = - runner::start(runtime_port, runtime_executable, Path::new(project_path)).await?; + let (runtime, runtime_client) = runner::start( + false, + runtime_port, + runtime_address, + runtime_executable, + Path::new(project_path), + ) + .await?; Ok(TestRuntime { runtime_client, diff --git a/service/src/runner.rs b/service/src/runner.rs index b772e573f..b324c62f1 100644 --- a/service/src/runner.rs +++ b/service/src/runner.rs @@ -1,4 +1,5 @@ use std::{ + net::SocketAddr, path::{Path, PathBuf}, process::Stdio, }; @@ -9,12 +10,24 @@ use tokio::process; use tracing::info; pub async fn start( + beta: bool, port: u16, + // only used on beta. must match port. + address: SocketAddr, runtime_executable: PathBuf, project_path: &Path, ) -> anyhow::Result<(process::Child, runtime::Client)> { - let port_str = port.to_string(); - let args = vec!["--port", &port_str]; + let mut args = vec![]; + if beta { + let addr_str = address.to_string(); + args.push("--beta".to_owned()); + args.push("--address".to_owned()); + args.push(addr_str); + } else { + let port_str = port.to_string(); + args.push("--port".to_owned()); + args.push(port_str); + } info!( args = %format!("{} {}", runtime_executable.display(), args.join(" ")), @@ -30,7 +43,8 @@ pub async fn start( .spawn() .context("spawning runtime process")?; - let runtime_client = runtime::get_client(format!("http://0.0.0.0:{port}")).await?; + // runtime might start on localhost or 0.0.0.0, but we can reach it on localhost:port + let runtime_client = runtime::get_client(format!("http://localhost:{port}")).await?; Ok((runtime, runtime_client)) } From 3757bfe55214ee19e9096661e20e4d369a7073f8 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Wed, 24 Apr 2024 12:13:53 +0200 Subject: [PATCH 24/26] feat(runtime): version endpoint for runner version check --- proto/runtime.proto | 5 +++ proto/src/generated/runtime.rs | 62 ++++++++++++++++++++++++++++++++++ runtime/src/alpha.rs | 19 ++++++----- runtime/src/lib.rs | 4 +-- 4 files changed, 79 insertions(+), 11 deletions(-) diff --git a/proto/runtime.proto b/proto/runtime.proto index fd0c974b0..1b3617808 100644 --- a/proto/runtime.proto +++ b/proto/runtime.proto @@ -14,6 +14,7 @@ service Runtime { // Channel to notify a service has been stopped rpc SubscribeStop(SubscribeStopRequest) returns (stream SubscribeStopResponse); + rpc Version(Ping) returns (VersionInfo); rpc HealthCheck(Ping) returns (Pong); } @@ -83,3 +84,7 @@ enum StopReason { message Ping {} message Pong {} + +message VersionInfo { + string version = 1; +} diff --git a/proto/src/generated/runtime.rs b/proto/src/generated/runtime.rs index fa7097a29..18a3dde62 100644 --- a/proto/src/generated/runtime.rs +++ b/proto/src/generated/runtime.rs @@ -79,6 +79,12 @@ pub struct Ping {} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Pong {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct VersionInfo { + #[prost(string, tag = "1")] + pub version: ::prost::alloc::string::String, +} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum StopReason { @@ -270,6 +276,23 @@ pub mod runtime_client { .insert(GrpcMethod::new("runtime.Runtime", "SubscribeStop")); self.inner.server_streaming(req, path, codec).await } + pub async fn version( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/runtime.Runtime/Version"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("runtime.Runtime", "Version")); + self.inner.unary(req, path, codec).await + } pub async fn health_check( &mut self, request: impl tonic::IntoRequest, @@ -321,6 +344,10 @@ pub mod runtime_server { &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; + async fn version( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; async fn health_check( &self, request: tonic::Request, @@ -561,6 +588,41 @@ pub mod runtime_server { }; Box::pin(fut) } + "/runtime.Runtime/Version" => { + #[allow(non_camel_case_types)] + struct VersionSvc(pub Arc); + impl tonic::server::UnaryService for VersionSvc { + type Response = super::VersionInfo; + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::version(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = VersionSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/runtime.Runtime/HealthCheck" => { #[allow(non_camel_case_types)] struct HealthCheckSvc(pub Arc); diff --git a/runtime/src/alpha.rs b/runtime/src/alpha.rs index 4cf6c9a75..d1820c94e 100644 --- a/runtime/src/alpha.rs +++ b/runtime/src/alpha.rs @@ -12,13 +12,10 @@ use anyhow::Context; use async_trait::async_trait; use core::future::Future; use shuttle_common::{extract_propagation::ExtractPropagationLayer, secrets::Secret}; -use shuttle_proto::{ - runtime::{ - runtime_server::{Runtime, RuntimeServer}, - LoadRequest, LoadResponse, StartRequest, StartResponse, StopReason, StopRequest, - StopResponse, SubscribeStopRequest, SubscribeStopResponse, - }, - runtime::{Ping, Pong}, +use shuttle_proto::runtime::{ + runtime_server::{Runtime, RuntimeServer}, + LoadRequest, LoadResponse, Ping, Pong, StartRequest, StartResponse, StopReason, StopRequest, + StopResponse, SubscribeStopRequest, SubscribeStopResponse, VersionInfo, }; use shuttle_service::{ResourceFactory, Service}; use tokio::sync::{ @@ -29,7 +26,7 @@ use tokio_stream::wrappers::ReceiverStream; use tokio_util::sync::CancellationToken; use tonic::{transport::Server, Request, Response, Status}; -use crate::print_version; +use crate::version; #[derive(Default)] struct Args { @@ -89,7 +86,7 @@ impl Args { pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + Send + 'static) { // `--version` overrides any other arguments. Used by cargo-shuttle to check compatibility on local runs. if std::env::args().any(|arg| arg == "--version") { - print_version(); + println!("{}", version()); return; } @@ -502,6 +499,10 @@ where Ok(Response::new(ReceiverStream::new(rx))) } + async fn version(&self, _requset: Request) -> Result, Status> { + Ok(Response::new(VersionInfo { version: version() })) + } + async fn health_check(&self, _request: Request) -> Result, Status> { if matches!(self.state.lock().unwrap().deref(), State::Unhealthy) { println!("runtime health check failed"); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index aea389e8c..adb3157f6 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -19,8 +19,8 @@ mod alpha; const NAME: &str = env!("CARGO_PKG_NAME"); const VERSION: &str = env!("CARGO_PKG_VERSION"); -fn print_version() { - println!("{} {}", crate::NAME, crate::VERSION); +fn version() -> String { + format!("{} {}", crate::NAME, crate::VERSION) } // Not part of public API From cd2c7a8b7f2f2c73fd8aa77ec0b3e8705970c71a Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:52:38 +0200 Subject: [PATCH 25/26] fix: review comments on ecs-common --- Cargo.toml | 1 + cargo-shuttle/src/client.rs | 2 +- cargo-shuttle/src/lib.rs | 2 +- runtime/Cargo.toml | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 17e043240..35d38d1ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ test-context = "0.3.0" thiserror = "1.0.37" tokio = "1.22.0" tokio-stream = "0.1.11" +tokio-util = "0.7.10" toml = "0.8.2" toml_edit = "0.20.2" tonic = "0.10.2" diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index b61289771..3991dd15a 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -39,7 +39,7 @@ impl ShuttleApiClient { )])) .unwrap(), ) - .timeout(Duration::from_secs(300)) // TODO: adjust + .timeout(Duration::from_secs(60)) .build() .unwrap(), api_url, diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index ab80ddcfc..78c6d781f 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -853,7 +853,7 @@ impl Shuttle { if args.raw { println!("{}", log.line); } else { - println!("[{}] ({}) {}", log.timestamp, log.source, log.line); + println!("{log}"); } } Err(err) => { diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 76b875575..9002708f6 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -22,13 +22,13 @@ serde = { workspace = true } serde_json = { workspace = true } strfmt = { workspace = true } tokio = { workspace = true, features = ["full"] } -tokio-util = "0.7.10" +tokio-util = { workspace = true } tokio-stream = { workspace = true } tonic = { workspace = true } tracing-subscriber = { workspace = true, optional = true } [dev-dependencies] -portpicker = "0.1.1" +portpicker = { workspace = true } shuttle-service = { workspace = true, features = ["builder", "runner"] } shuttle-proto = { workspace = true, features = ["provisioner"] } uuid = { workspace = true } From 95c155bf9504c3f4630f34302c29d93eb16fb488 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Wed, 24 Apr 2024 15:18:02 +0200 Subject: [PATCH 26/26] nit: update timeout comment --- runtime/src/alpha.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/runtime/src/alpha.rs b/runtime/src/alpha.rs index d1820c94e..8bf0ff543 100644 --- a/runtime/src/alpha.rs +++ b/runtime/src/alpha.rs @@ -310,8 +310,7 @@ where // Ensure that the runtime is set to unhealthy if it doesn't reach the running state after // it has sent a load response, so that the ECS task will fail. tokio::spawn(async move { - // Note: The timeout is quite low as we are not actually provisioning resources after - // sending the load response. + // Note: The timeout is quite long since RDS can take a long time to provision. tokio::time::sleep(Duration::from_secs(180)).await; if !matches!(state.lock().unwrap().deref(), State::Running) { println!("the runtime failed to enter the running state before timing out");