diff --git a/Cargo.lock b/Cargo.lock index f1c5b67c2c..717625f1b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5266,6 +5266,7 @@ dependencies = [ "tracing-opentelemetry", "tracing-subscriber", "ttl_cache", + "ulid", "utoipa", "uuid", ] @@ -5324,6 +5325,7 @@ dependencies = [ "tracing", "tracing-opentelemetry", "tracing-subscriber", + "ulid", "utoipa", "utoipa-swagger-ui", "uuid", @@ -6615,6 +6617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13a3aaa69b04e5b66cc27309710a569ea23593612387d67daaf102e73aa974fd" dependencies = [ "rand", + "serde", ] [[package]] diff --git a/common/Cargo.toml b/common/Cargo.toml index af03489711..199fe817d0 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -43,6 +43,7 @@ tracing-opentelemetry = { workspace = true, optional = true } tracing-subscriber = { workspace = true, optional = true } ttl_cache = { workspace = true, optional = true } utoipa = { workspace = true, optional = true } +ulid = { workspace = true, features = ["serde"] } uuid = { workspace = true, features = ["v4", "serde"], optional = true } [features] diff --git a/common/src/models/deployment.rs b/common/src/models/deployment.rs index 00b586dbc3..a049520336 100644 --- a/common/src/models/deployment.rs +++ b/common/src/models/deployment.rs @@ -7,18 +7,33 @@ use comfy_table::{ use crossterm::style::Stylize; use serde::{Deserialize, Serialize}; use std::{fmt::Display, str::FromStr}; +use ulid::Ulid; #[cfg(feature = "openapi")] -use utoipa::ToSchema; +use utoipa::{ + openapi::{Object, ObjectBuilder}, + ToSchema, +}; use uuid::Uuid; +#[cfg(feature = "openapi")] +fn ulid_type() -> Object { + ObjectBuilder::new() + .schema_type(utoipa::openapi::SchemaType::String) + .format(Some(utoipa::openapi::SchemaFormat::Custom( + "ulid".to_string(), + ))) + .description(Some("String represention of an Ulid according to the spec found here: https://github.com/ulid/spec.")) + .build() +} + #[derive(Deserialize, Serialize)] #[cfg_attr(feature = "openapi", derive(ToSchema))] #[cfg_attr(feature = "openapi", schema(as = shuttle_common::models::deployment::Response))] pub struct Response { #[cfg_attr(feature = "openapi", schema(value_type = KnownFormat::Uuid))] pub id: Uuid, - #[cfg_attr(feature = "openapi", schema(value_type = KnownFormat::Uuid))] - pub service_id: Uuid, + #[cfg_attr(feature = "openapi", schema(schema_with = ulid_type))] + pub service_id: Ulid, #[cfg_attr(feature = "openapi", schema(value_type = shuttle_common::deployment::State))] pub state: State, #[cfg_attr(feature = "openapi", schema(value_type = KnownFormat::DateTime))] diff --git a/common/src/models/service.rs b/common/src/models/service.rs index 6e72738f04..823cd46468 100644 --- a/common/src/models/service.rs +++ b/common/src/models/service.rs @@ -2,9 +2,9 @@ use crossterm::style::{Color, Stylize}; use serde::{Deserialize, Serialize}; use std::fmt::Display; use std::str::FromStr; +use ulid::Ulid; #[cfg(feature = "openapi")] use utoipa::ToSchema; -use uuid::Uuid; use crate::models::deployment; @@ -13,7 +13,7 @@ use crate::models::deployment; #[cfg_attr(feature = "openapi", schema(as = shuttle_common::models::service::Response))] pub struct Response { #[cfg_attr(feature = "openapi", schema(value_type = KnownFormat::Uuid))] - pub id: Uuid, + pub id: Ulid, pub name: String, } diff --git a/deployer/Cargo.toml b/deployer/Cargo.toml index 4ab6b52133..0b5b57cf6e 100644 --- a/deployer/Cargo.toml +++ b/deployer/Cargo.toml @@ -53,6 +53,7 @@ tracing-subscriber = { workspace = true, features = [ ] } utoipa = { workspace = true } utoipa-swagger-ui = { workspace = true } +ulid = { workspace = true } uuid = { workspace = true, features = ["v4"] } [dependencies.shuttle-common] diff --git a/deployer/migrations/0004_change_service_id_to_ulid.sql b/deployer/migrations/0004_change_service_id_to_ulid.sql new file mode 100644 index 0000000000..eefafc3a4f --- /dev/null +++ b/deployer/migrations/0004_change_service_id_to_ulid.sql @@ -0,0 +1,107 @@ +-- Copy current service table. Keep the old table around because +-- the rest of the tables are still having an FK on service_id. +CREATE TABLE IF NOT EXISTS services_copy ( + id TEXT PRIMARY KEY, -- Identifier of the service. + name TEXT UNIQUE -- Name of the service. +); + +INSERT INTO services_copy (id, name) +SELECT + uuid_to_ulid(services.id), + services.name +FROM services; + +-- Copy current deployments table without the FK service_id constraint. +CREATE TABLE IF NOT EXISTS deployments_copy ( + id TEXT PRIMARY KEY, -- Identifier of the deployment. + service_id TEXT, -- Identifier of the service this deployment belongs to. + state TEXT, -- Enum indicating the current state of the deployment. + last_update INTEGER, -- Unix epoch of the last status update + address TEXT, -- Address a running deployment is active on + is_next BOOLEAN, -- Whether the deployment is for a shuttle-next runtime + git_commit_id TEXT, -- Deployment git commit id + git_commit_msg TEXT, -- Deployment last git commit msg + git_branch TEXT, -- Deployment git branch + git_dirty BOOLEAN -- Deployment git state is dirty +); + +INSERT INTO deployments_copy (id, service_id, state, last_update, address, is_next) +SELECT + deployments.id, + uuid_to_ulid(deployments.service_id), + deployments.state, + deployments.last_update, + deployments.address, + deployments.is_next, + deployments.git_commit_id, + deployments.git_commit_msg, + deployments.git_branch, + deployments.git_dirty +FROM deployments; + +-- Copy current resource table without the FK service_id constraint. +CREATE TABLE IF NOT EXISTS resources_copy ( + service_id TEXT, -- Identifier of the service this resource belongs to. + type TEXT, -- Type of resource this is. + data TEXT, -- Data about this resource. + config TEXT, -- Resource configuration. + PRIMARY KEY (service_id, type), +); +INSERT INTO resources_copy (service_id, type, data, config) +SELECT + uuid_to_ulid(resources.service_id), + resources.type, + resources.data, + resources.config, +FROM resources; + +-- Copy current secrets table without the FK service_id constraint. +CREATE TABLE IF NOT EXISTS secrets_copy ( + service_id TEXT, -- Identifier of the service this secret belongs to. + key TEXT, -- Key / name of this secret. + value TEXT, -- The actual secret. + last_update INTEGER, -- Unix epoch of the last secret update + PRIMARY KEY (service_id, key), +); +INSERT INTO secrets_copy (service_id, key, value, last_update) +SELECT + uuid_to_ulid(secrets.service_id), + secrets.key, + secrets.value, + secrets.last_update +FROM secrets; + +-- Recreate the deployments table with an FK constraint on the service_id. +DROP TABLE deployments; +CREATE TABLE IF NOT EXISTS deployments ( + id TEXT PRIMARY KEY, -- Identifier of the deployment. + service_id TEXT, -- Identifier of the service this deployment belongs to. + state TEXT, -- Enum indicating the current state of the deployment. + last_update INTEGER, -- Unix epoch of the last status update + address TEXT -- Address a running deployment is active on + is_next BOOLEAN, -- Whether the deployment is for a shuttle-next runtime + git_commit_id TEXT, -- Deployment git commit id + git_commit_msg TEXT, -- Deployment last git commit msg + git_branch TEXT, -- Deployment git branch + git_dirty BOOLEAN -- Deployment git state is dirty + FOREIGN KEY(service_id) REFERENCES services(id) +); +INSERT INTO deployments SELECT * FROM deployments_copy; +DROP TABLE deployments_copy; + +-- Recreate the resources table with an FK constraint on the service_id. +DROP TABLE resources; +CREATE TABLE IF NOT EXISTS resources ( + service_id TEXT, -- Identifier of the service this resource belongs to. + type TEXT, -- Type of resource this is. + data TEXT, -- Data about this resource. + config TEXT, -- Resource configuration. + PRIMARY KEY (service_id, type), + FOREIGN KEY(service_id) REFERENCES services(id) +); +INSERT INTO resources SELECT * FROM resources_copy; +DROP TABLE resources_copy; + +-- Replace the old services table with the updated one. +DROP TABLE services; +ALTER TABLE services_copy RENAME TO services; diff --git a/deployer/src/deployment/deploy_layer.rs b/deployer/src/deployment/deploy_layer.rs index 530fe933d3..a919719aad 100644 --- a/deployer/src/deployment/deploy_layer.rs +++ b/deployer/src/deployment/deploy_layer.rs @@ -327,6 +327,7 @@ mod tests { use tokio::{select, time::sleep}; use tonic::transport::Server; use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + use ulid::Ulid; use uuid::Uuid; use crate::{ @@ -486,7 +487,7 @@ mod tests { async fn insert_secret( &self, - _service_id: &Uuid, + _service_id: &Ulid, _key: &str, _value: &str, ) -> Result<(), Self::Err> { @@ -525,7 +526,7 @@ mod tests { async fn get_active_deployments( &self, - _service_id: &Uuid, + _service_id: &Ulid, ) -> std::result::Result, Self::Err> { Ok(vec![]) } @@ -558,7 +559,7 @@ mod tests { impl SecretGetter for StubSecretGetter { type Err = std::io::Error; - async fn get_secrets(&self, _service_id: &Uuid) -> Result, Self::Err> { + async fn get_secrets(&self, _service_id: &Ulid) -> Result, Self::Err> { Ok(Default::default()) } } @@ -573,7 +574,7 @@ mod tests { async fn insert_resource(&self, _resource: &Resource) -> Result<(), Self::Err> { Ok(()) } - async fn get_resources(&self, _service_id: &Uuid) -> Result, Self::Err> { + async fn get_resources(&self, _service_id: &Ulid) -> Result, Self::Err> { Ok(Vec::new()) } } @@ -825,7 +826,7 @@ mod tests { .run_push(Built { id, service_name: "run-test".to_string(), - service_id: Uuid::new_v4(), + service_id: Ulid::new(), tracing_context: Default::default(), is_next: false, claim: None, @@ -868,7 +869,7 @@ mod tests { .queue_push(Queued { id, service_name: "nil_id".to_string(), - service_id: Uuid::new_v4(), + service_id: Ulid::new(), data: Bytes::from("violets are red").to_vec(), will_run_tests: false, tracing_context: Default::default(), @@ -927,7 +928,7 @@ mod tests { Queued { id: Uuid::new_v4(), service_name: format!("deploy-layer-{name}"), - service_id: Uuid::new_v4(), + service_id: Ulid::new(), data: bytes, will_run_tests: false, tracing_context: Default::default(), diff --git a/deployer/src/deployment/queue.rs b/deployer/src/deployment/queue.rs index a59a20a723..840fed5526 100644 --- a/deployer/src/deployment/queue.rs +++ b/deployer/src/deployment/queue.rs @@ -16,6 +16,7 @@ use tokio::task::JoinSet; use tokio::time::{sleep, timeout}; use tracing::{debug, debug_span, error, info, instrument, trace, warn, Instrument, Span}; use tracing_opentelemetry::OpenTelemetrySpanExt; +use ulid::Ulid; use uuid::Uuid; use std::collections::{BTreeMap, HashMap}; @@ -161,7 +162,7 @@ async fn promote_to_run(mut built: Built, run_send: RunSender) { pub struct Queued { pub id: Uuid, pub service_name: String, - pub service_id: Uuid, + pub service_id: Ulid, pub data: Vec, pub will_run_tests: bool, pub tracing_context: HashMap, @@ -302,7 +303,7 @@ async fn get_secrets(project_path: &Path) -> Result> { #[instrument(skip(secrets, service_id, secret_recorder))] async fn set_secrets( secrets: BTreeMap, - service_id: &Uuid, + service_id: &Ulid, secret_recorder: impl SecretRecorder, ) -> Result<()> { for (key, value) in secrets.into_iter() { diff --git a/deployer/src/deployment/run.rs b/deployer/src/deployment/run.rs index ebcb3b5018..67dfe1e003 100644 --- a/deployer/src/deployment/run.rs +++ b/deployer/src/deployment/run.rs @@ -25,6 +25,7 @@ use tokio::{ use tonic::{transport::Channel, Code}; use tracing::{debug, debug_span, error, info, instrument, trace, warn, Instrument}; use tracing_opentelemetry::OpenTelemetrySpanExt; +use ulid::Ulid; use uuid::Uuid; use super::{RunReceiver, State}; @@ -138,7 +139,7 @@ pub async fn task( #[instrument(skip(active_deployment_getter, runtime_manager))] async fn kill_old_deployments( - service_id: Uuid, + service_id: Ulid, deployment_id: Uuid, active_deployment_getter: impl ActiveDeploymentsGetter, runtime_manager: Arc>, @@ -195,7 +196,7 @@ pub trait ActiveDeploymentsGetter: Clone + Send + Sync + 'static { async fn get_active_deployments( &self, - service_id: &Uuid, + service_id: &Ulid, ) -> std::result::Result, Self::Err>; } @@ -203,7 +204,7 @@ pub trait ActiveDeploymentsGetter: Clone + Send + Sync + 'static { pub struct Built { pub id: Uuid, pub service_name: String, - pub service_id: Uuid, + pub service_id: Ulid, pub tracing_context: HashMap, pub is_next: bool, pub claim: Option, @@ -281,7 +282,7 @@ impl Built { async fn load( service_name: String, - service_id: Uuid, + service_id: Ulid, executable_path: PathBuf, secret_getter: impl SecretGetter, resource_manager: impl ResourceManager, @@ -453,6 +454,7 @@ mod tests { time::sleep, }; use tonic::transport::Server; + use ulid::Ulid; use uuid::Uuid; use crate::{ @@ -534,7 +536,7 @@ mod tests { impl SecretGetter for StubSecretGetter { type Err = std::io::Error; - async fn get_secrets(&self, _service_id: &Uuid) -> Result, Self::Err> { + async fn get_secrets(&self, _service_id: &Ulid) -> Result, Self::Err> { Ok(Default::default()) } } @@ -549,7 +551,7 @@ mod tests { async fn insert_resource(&self, _resource: &Resource) -> Result<(), Self::Err> { Ok(()) } - async fn get_resources(&self, _service_id: &Uuid) -> Result, Self::Err> { + async fn get_resources(&self, _service_id: &Ulid) -> Result, Self::Err> { Ok(Vec::new()) } } @@ -746,7 +748,7 @@ mod tests { Built { id, service_name: crate_name.to_string(), - service_id: Uuid::new_v4(), + service_id: Ulid::new(), tracing_context: Default::default(), is_next: false, claim: None, diff --git a/deployer/src/persistence/deployment.rs b/deployer/src/persistence/deployment.rs index 4496ff8484..d5bb829ecb 100644 --- a/deployer/src/persistence/deployment.rs +++ b/deployer/src/persistence/deployment.rs @@ -4,6 +4,7 @@ use async_trait::async_trait; use chrono::{DateTime, Utc}; use sqlx::{sqlite::SqliteRow, FromRow, Row}; use tracing::error; +use ulid::Ulid; use utoipa::ToSchema; use uuid::Uuid; @@ -13,7 +14,7 @@ use super::state::State; #[derive(Clone, Debug, Default, Eq, PartialEq, ToSchema)] pub struct Deployment { pub id: Uuid, - pub service_id: Uuid, + pub service_id: Ulid, pub state: State, pub last_update: DateTime, pub address: Option, @@ -40,7 +41,8 @@ impl FromRow<'_, SqliteRow> for Deployment { Ok(Self { id: row.try_get("id")?, - service_id: row.try_get("service_id")?, + service_id: Ulid::from_string(row.try_get("service_id")?) + .expect("to have a valid ulid string"), state: row.try_get("state")?, last_update: row.try_get("last_update")?, address, @@ -87,10 +89,22 @@ pub struct DeploymentState { pub last_update: DateTime, } -#[derive(sqlx::FromRow, Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub struct DeploymentRunnable { pub id: Uuid, pub service_name: String, - pub service_id: Uuid, + pub service_id: Ulid, pub is_next: bool, } + +impl FromRow<'_, SqliteRow> for DeploymentRunnable { + fn from_row(row: &SqliteRow) -> Result { + Ok(Self { + service_id: Ulid::from_string(row.try_get("service_id")?) + .expect("to have a valid ulid string"), + service_name: row.try_get("service_name")?, + id: row.try_get("id")?, + is_next: row.try_get("is_next")?, + }) + } +} diff --git a/deployer/src/persistence/mod.rs b/deployer/src/persistence/mod.rs index 72e7a8146d..fa7c87a096 100644 --- a/deployer/src/persistence/mod.rs +++ b/deployer/src/persistence/mod.rs @@ -12,6 +12,7 @@ use crate::deployment::ActiveDeploymentsGetter; use crate::proxy::AddressGetter; use error::{Error, Result}; use sqlx::QueryBuilder; +use ulid::Ulid; use std::net::SocketAddr; use std::path::Path; @@ -173,7 +174,7 @@ impl Persistence { sqlx::query("INSERT INTO deployments VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") .bind(deployment.id) - .bind(deployment.service_id) + .bind(deployment.service_id.to_string()) .bind(deployment.state) .bind(deployment.last_update) .bind(deployment.address.map(|socket| socket.to_string())) @@ -194,14 +195,14 @@ impl Persistence { pub async fn get_deployments( &self, - service_id: &Uuid, + service_id: &Ulid, offset: u32, limit: u32, ) -> Result> { let mut query = QueryBuilder::new("SELECT * FROM deployments WHERE service_id = "); query - .push_bind(service_id) + .push_bind(service_id.to_string()) .push(" ORDER BY last_update DESC LIMIT ") .push_bind(limit); @@ -216,9 +217,9 @@ impl Persistence { .map_err(Error::from) } - pub async fn get_active_deployment(&self, service_id: &Uuid) -> Result> { + pub async fn get_active_deployment(&self, service_id: &Ulid) -> Result> { sqlx::query_as("SELECT * FROM deployments WHERE service_id = ? AND state = ?") - .bind(service_id) + .bind(service_id.to_string()) .bind(State::Running) .fetch_optional(&self.pool) .await @@ -244,12 +245,12 @@ impl Persistence { Ok(service) } else { let service = Service { - id: Uuid::new_v4(), + id: Ulid::new(), name: name.to_string(), }; sqlx::query("INSERT INTO services (id, name) VALUES (?, ?)") - .bind(service.id) + .bind(service.id.to_string()) .bind(&service.name) .execute(&self.pool) .await?; @@ -266,9 +267,9 @@ impl Persistence { .map_err(Error::from) } - pub async fn delete_service(&self, id: &Uuid) -> Result<()> { + pub async fn delete_service(&self, id: &Ulid) -> Result<()> { sqlx::query("DELETE FROM services WHERE id = ?") - .bind(id) + .bind(id.to_string()) .execute(&self.pool) .await .map(|_| ()) @@ -375,7 +376,7 @@ impl ResourceManager for Persistence { sqlx::query( "INSERT OR REPLACE INTO resources (service_id, type, config, data) VALUES (?, ?, ?, ?)", ) - .bind(resource.service_id) + .bind(resource.service_id.to_string()) .bind(resource.r#type.clone()) .bind(&resource.config) .bind(&resource.data) @@ -385,9 +386,9 @@ impl ResourceManager for Persistence { .map_err(Error::from) } - async fn get_resources(&self, service_id: &Uuid) -> Result> { + async fn get_resources(&self, service_id: &Ulid) -> Result> { sqlx::query_as(r#"SELECT * FROM resources WHERE service_id = ?"#) - .bind(service_id) + .bind(service_id.to_string()) .fetch_all(&self.pool) .await .map_err(Error::from) @@ -398,11 +399,11 @@ impl ResourceManager for Persistence { impl SecretRecorder for Persistence { type Err = Error; - async fn insert_secret(&self, service_id: &Uuid, key: &str, value: &str) -> Result<()> { + async fn insert_secret(&self, service_id: &Ulid, key: &str, value: &str) -> Result<()> { sqlx::query( "INSERT OR REPLACE INTO secrets (service_id, key, value, last_update) VALUES (?, ?, ?, ?)", ) - .bind(service_id) + .bind(service_id.to_string()) .bind(key) .bind(value) .bind(Utc::now()) @@ -417,9 +418,9 @@ impl SecretRecorder for Persistence { impl SecretGetter for Persistence { type Err = Error; - async fn get_secrets(&self, service_id: &Uuid) -> Result> { + async fn get_secrets(&self, service_id: &Ulid) -> Result> { sqlx::query_as("SELECT * FROM secrets WHERE service_id = ? ORDER BY key") - .bind(service_id) + .bind(service_id.to_string()) .fetch_all(&self.pool) .await .map_err(Error::from) @@ -492,12 +493,12 @@ impl ActiveDeploymentsGetter for Persistence { async fn get_active_deployments( &self, - service_id: &Uuid, + service_id: &Ulid, ) -> std::result::Result, Self::Err> { let ids: Vec<_> = sqlx::query_as::<_, Deployment>( "SELECT * FROM deployments WHERE service_id = ? AND state = ?", ) - .bind(service_id) + .bind(service_id.to_string()) .bind(State::Running) .fetch_all(&self.pool) .await @@ -1223,19 +1224,19 @@ mod tests { ) // This running item should match .bind(Uuid::new_v4()) - .bind(service_id) + .bind(service_id.to_string()) .bind(State::Running) .bind(Utc::now()) .bind("10.0.0.5:12356") // A stopped item should not match .bind(Uuid::new_v4()) - .bind(service_id) + .bind(service_id.to_string()) .bind(State::Stopped) .bind(Utc::now()) .bind("10.0.0.5:9876") // Another service should not match .bind(Uuid::new_v4()) - .bind(service_other_id) + .bind(service_other_id.to_string()) .bind(State::Running) .bind(Utc::now()) .bind("10.0.0.5:5678") @@ -1322,7 +1323,7 @@ mod tests { "INSERT INTO deployments (id, service_id, state, last_update) VALUES (?, ?, ?, ?)", ) .bind(deployment_id) - .bind(service_id) + .bind(service_id.to_string()) .bind(State::Running) .bind(Utc::now()) .execute(pool) @@ -1331,15 +1332,15 @@ mod tests { Ok(deployment_id) } - async fn add_service(pool: &SqlitePool) -> Result { + async fn add_service(pool: &SqlitePool) -> Result { add_service_named(pool, &get_random_name()).await } - async fn add_service_named(pool: &SqlitePool, name: &str) -> Result { - let service_id = Uuid::new_v4(); + async fn add_service_named(pool: &SqlitePool, name: &str) -> Result { + let service_id = Ulid::new(); sqlx::query("INSERT INTO services (id, name) VALUES (?, ?)") - .bind(service_id) + .bind(service_id.to_string()) .bind(name) .execute(pool) .await?; diff --git a/deployer/src/persistence/resource/mod.rs b/deployer/src/persistence/resource/mod.rs index 88d0658255..8571895a8f 100644 --- a/deployer/src/persistence/resource/mod.rs +++ b/deployer/src/persistence/resource/mod.rs @@ -1,11 +1,11 @@ pub mod database; use sqlx::{ - sqlite::{SqliteArgumentValue, SqliteValueRef}, - Database, Sqlite, + sqlite::{SqliteArgumentValue, SqliteRow, SqliteValueRef}, + Database, FromRow, Row, Sqlite, }; use std::{borrow::Cow, fmt::Display, str::FromStr}; -use uuid::Uuid; +use ulid::Ulid; pub use self::database::Type as DatabaseType; @@ -15,17 +15,29 @@ pub trait ResourceManager: Clone + Send + Sync + 'static { type Err: std::error::Error; async fn insert_resource(&self, resource: &Resource) -> Result<(), Self::Err>; - async fn get_resources(&self, service_id: &Uuid) -> Result, Self::Err>; + async fn get_resources(&self, service_id: &Ulid) -> Result, Self::Err>; } -#[derive(sqlx::FromRow, Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub struct Resource { - pub service_id: Uuid, + pub service_id: Ulid, pub r#type: Type, pub data: serde_json::Value, pub config: serde_json::Value, } +impl FromRow<'_, SqliteRow> for Resource { + fn from_row(row: &SqliteRow) -> Result { + Ok(Self { + service_id: Ulid::from_string(row.try_get("service_id")?) + .expect("to have a valid ulid string"), + r#type: row.try_get("type")?, + data: row.try_get("")?, + config: row.try_get("is_next")?, + }) + } +} + impl From for shuttle_common::resource::Response { fn from(resource: Resource) -> Self { shuttle_common::resource::Response { diff --git a/deployer/src/persistence/secret.rs b/deployer/src/persistence/secret.rs index 3de29f42e0..96dfcee8ca 100644 --- a/deployer/src/persistence/secret.rs +++ b/deployer/src/persistence/secret.rs @@ -1,5 +1,6 @@ use chrono::{DateTime, Utc}; -use uuid::Uuid; +use sqlx::{sqlite::SqliteRow, FromRow, Row}; +use ulid::Ulid; #[async_trait::async_trait] /// Record a secret value for a service with name @@ -8,7 +9,7 @@ pub trait SecretRecorder: Clone + Send + Sync + 'static { async fn insert_secret( &self, - service_id: &Uuid, + service_id: &Ulid, key: &str, value: &str, ) -> Result<(), Self::Err>; @@ -19,12 +20,12 @@ pub trait SecretRecorder: Clone + Send + Sync + 'static { pub trait SecretGetter: Clone + Send + Sync + 'static { type Err: std::error::Error + Send + Sync; - async fn get_secrets(&self, service_id: &Uuid) -> Result, Self::Err>; + async fn get_secrets(&self, service_id: &Ulid) -> Result, Self::Err>; } -#[derive(sqlx::FromRow, Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub struct Secret { - pub service_id: Uuid, + pub service_id: Ulid, pub key: String, pub value: String, pub last_update: DateTime, @@ -38,3 +39,15 @@ impl From for shuttle_common::models::secret::Response { } } } + +impl FromRow<'_, SqliteRow> for Secret { + fn from_row(row: &SqliteRow) -> Result { + Ok(Self { + service_id: Ulid::from_string(row.try_get("service_id")?) + .expect("to have a valid ulid string"), + key: row.try_get("key")?, + value: row.try_get("value")?, + last_update: row.try_get("last_update")?, + }) + } +} diff --git a/deployer/src/persistence/service.rs b/deployer/src/persistence/service.rs index f64b912ddc..836fa4d140 100644 --- a/deployer/src/persistence/service.rs +++ b/deployer/src/persistence/service.rs @@ -1,9 +1,10 @@ use shuttle_common::models::service; -use uuid::Uuid; +use sqlx::{sqlite::SqliteRow, FromRow, Row}; +use ulid::Ulid; -#[derive(Clone, Debug, Eq, PartialEq, sqlx::FromRow)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Service { - pub id: Uuid, + pub id: Ulid, pub name: String, } @@ -15,3 +16,12 @@ impl From for service::Response { } } } + +impl FromRow<'_, SqliteRow> for Service { + fn from_row(row: &SqliteRow) -> Result { + Ok(Self { + id: Ulid::from_string(row.try_get("service_id")?).expect("to have a valid ulid string"), + name: row.try_get("service_name")?, + }) + } +} diff --git a/deployer/ulid0.so b/deployer/ulid0.so new file mode 100755 index 0000000000..8f642f7c12 Binary files /dev/null and b/deployer/ulid0.so differ diff --git a/gateway/ulid0.so b/gateway/ulid0.so index 727110d801..8f642f7c12 100644 Binary files a/gateway/ulid0.so and b/gateway/ulid0.so differ