diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index ea1527055..a70fbd885 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -266,7 +266,7 @@ impl Shuttle { Command::Account => self.account().await, Command::Login(login_args) => self.login(login_args, args.offline).await, Command::Logout(logout_args) => self.logout(logout_args).await, - Command::Feedback => self.feedback(), + Command::Feedback => feedback(), Command::Run(run_args) => { if self.beta { self.local_run_beta(run_args, args.debug).await @@ -774,14 +774,6 @@ impl Shuttle { self.ctx.load_local(project_args) } - /// Provide feedback on GitHub. - fn feedback(&self) -> Result<()> { - let _ = webbrowser::open(SHUTTLE_GH_ISSUE_URL); - println!("If your browser did not open automatically, go to {SHUTTLE_GH_ISSUE_URL}"); - - Ok(()) - } - async fn account(&self) -> Result<()> { let client = self.client.as_ref().unwrap(); let user = client.get_current_user_beta().await?; @@ -2358,7 +2350,9 @@ impl Shuttle { } } - eprintln!("Packing files..."); + if self.beta { + eprintln!("Packing files..."); + } let archive = self.make_archive(args.secret_args.secrets.clone(), self.beta)?; if let Some(path) = args.output_archive { @@ -3237,6 +3231,13 @@ fn create_spinner() -> ProgressBar { pb } +fn feedback() -> Result<()> { + let _ = webbrowser::open(SHUTTLE_GH_ISSUE_URL); + eprintln!("If your browser did not open automatically, go to {SHUTTLE_GH_ISSUE_URL}"); + + Ok(()) +} + async fn update_cargo_shuttle(preview: bool) -> Result<()> { if preview { let _ = tokio::process::Command::new("cargo") diff --git a/cargo-shuttle/src/provisioner_server.rs b/cargo-shuttle/src/provisioner_server.rs index 70031157a..9f3d9ee96 100644 --- a/cargo-shuttle/src/provisioner_server.rs +++ b/cargo-shuttle/src/provisioner_server.rs @@ -508,6 +508,7 @@ pub mod beta { }; use shuttle_common::{ database, + models::resource::get_resource_tables_beta, resource::{ self, ProvisionResourceRequestBeta, ResourceResponseBeta, ResourceState, ResourceTypeBeta, @@ -577,13 +578,16 @@ pub mod beta { ) -> Result> { Ok(match (method, uri) { (Method::GET, "/projects/proj_LOCAL/resources/secrets") => { - serde_json::to_vec(&ResourceResponseBeta { + let response = ResourceResponseBeta { r#type: ResourceTypeBeta::Secrets, state: ResourceState::Ready, config: serde_json::Value::Null, output: serde_json::to_value(&state.secrets).unwrap(), - }) - .unwrap() + }; + let table = + get_resource_tables_beta(&[response.clone()], "local service", false, true); + println!("{table}"); + serde_json::to_vec(&response).unwrap() } (Method::POST, "/projects/proj_LOCAL/resources") => { let prov = LocalProvisioner::new().unwrap(); @@ -595,20 +599,16 @@ pub mod beta { let config: DbInput = serde_json::from_value(shuttle_resource.config.clone()) .context("deserializing resource config")?; - let res = match config.local_uri { - Some(local_uri) => DatabaseResource::ConnectionString(local_uri), - None => DatabaseResource::Info( - prov.provision_database(Request::new(DatabaseRequest { - project_name: state.project_name.clone(), - db_type: Some(database::Type::Shared(database::SharedEngine::Postgres).into()), - db_name: config.db_name, - })) - .await - .context("Failed to start database container. Make sure that a Docker engine is running.")? - .into_inner() - .into(), - ), - }; + let res = DatabaseResource::Info( + prov.provision_database(Request::new(DatabaseRequest { + project_name: state.project_name.clone(), + db_type: Some(database::Type::Shared(database::SharedEngine::Postgres).into()), + db_name: config.db_name, + })) + .await + .context("Failed to start database container. Make sure that a Docker engine is running.")? + .into_inner() + .into()); ResourceResponseBeta { r#type: shuttle_resource.r#type, state: resource::ResourceState::Ready, @@ -638,6 +638,10 @@ pub mod beta { other => unimplemented!("Resource {other} not supported yet"), }; + let table = + get_resource_tables_beta(&[response.clone()], "local service", false, true); + println!("{table}"); + serde_json::to_vec(&response).unwrap() } _ => bail!("Received unsupported resource request"), diff --git a/common/src/lib.rs b/common/src/lib.rs index b03aab0db..da508e910 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -183,6 +183,7 @@ pub struct DatabaseInfoBeta { role_password: String, database_name: String, port: String, + #[serde(alias = "hostname_shuttle")] // compatibility to parse from a `DatabaseInfo` hostname: String, /// The RDS instance name, which is required for deleting provisioned RDS instances, it's /// optional because it isn't needed for shared PG deletion. diff --git a/common/src/models/resource.rs b/common/src/models/resource.rs index 72599f7d9..6f01c92d7 100644 --- a/common/src/models/resource.rs +++ b/common/src/models/resource.rs @@ -277,5 +277,5 @@ fn get_secrets_table_beta( table.add_row(vec![key]); } - format!("These secrets can be accessed by {service_name}\n{table}\n") + format!("These secrets can be accessed by {service_name}\n{table}") } diff --git a/resources/shared-db/src/postgres.rs b/resources/shared-db/src/postgres.rs index 1489436db..49b39352f 100644 --- a/resources/shared-db/src/postgres.rs +++ b/resources/shared-db/src/postgres.rs @@ -3,7 +3,8 @@ use serde::{Deserialize, Serialize}; use shuttle_service::{ database, resource::{ProvisionResourceRequest, ShuttleResourceOutput, Type}, - DatabaseResource, DbInput, Error, IntoResource, ResourceFactory, ResourceInputBuilder, + DatabaseResource, DbInput, Environment, Error, IntoResource, ResourceFactory, + ResourceInputBuilder, }; #[cfg(any(feature = "diesel-async-bb8", feature = "diesel-async-deadpool"))] @@ -33,17 +34,38 @@ impl Postgres { } } +/// Conditionally request a Shuttle resource +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +pub enum MaybeRequest { + Request(ProvisionResourceRequest), + NotRequest(DatabaseResource), +} + #[async_trait] impl ResourceInputBuilder for Postgres { - type Input = ProvisionResourceRequest; + type Input = MaybeRequest; type Output = OutputWrapper; - async fn build(self, _factory: &ResourceFactory) -> Result { - Ok(ProvisionResourceRequest::new( - Type::Database(database::Type::Shared(database::SharedEngine::Postgres)), - serde_json::to_value(self.0).unwrap(), - serde_json::Value::Null, - )) + async fn build(self, factory: &ResourceFactory) -> Result { + let md = factory.get_metadata(); + Ok(match md.env { + Environment::Deployment => MaybeRequest::Request(ProvisionResourceRequest::new( + Type::Database(database::Type::Shared(database::SharedEngine::Postgres)), + serde_json::to_value(self.0).unwrap(), + serde_json::Value::Null, + )), + Environment::Local => match self.0.local_uri { + Some(local_uri) => { + MaybeRequest::NotRequest(DatabaseResource::ConnectionString(local_uri)) + } + None => MaybeRequest::Request(ProvisionResourceRequest::new( + Type::Database(database::Type::Shared(database::SharedEngine::Postgres)), + serde_json::to_value(self.0).unwrap(), + serde_json::Value::Null, + )), + }, + }) } } @@ -62,7 +84,7 @@ impl IntoResource for OutputWrapper { Self::Beta(o) => o, }; Ok(match output { - DatabaseResource::ConnectionString(s) => s.clone(), + DatabaseResource::ConnectionString(s) => s, DatabaseResource::Info(info) => info.connection_string_shuttle(), }) } diff --git a/runtime/src/beta.rs b/runtime/src/beta.rs index 0aed1a9d7..47da32662 100644 --- a/runtime/src/beta.rs +++ b/runtime/src/beta.rs @@ -31,7 +31,7 @@ struct BetaEnvArgs { ip: IpAddr, /// Port to open service on port: u16, - /// Port to open health check on + /// Optional port to open health check on healthz_port: Option, /// Where to reach the required Shuttle API endpoints (mainly for provisioning) api_url: String, @@ -89,7 +89,8 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S // start a health check server if requested if let Some(healthz_port) = healthz_port { trace!("Starting health check server on port {healthz_port}"); - tokio::task::spawn(async move { + tokio::spawn(async move { + // light hyper server let make_service = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(|_req| async move { trace!("Receivied health check");