chore: Convert the migration to use receipt. (#1842)

This commit is contained in:
J M
2022-09-28 13:47:04 -06:00
committed by Aiden McClelland
parent 2ddd38796d
commit 78ad5d5879
7 changed files with 100 additions and 45 deletions

View File

@@ -82,8 +82,8 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<Option<Shutdown>, Error> {
}); });
let mut db = rpc_ctx.db.handle(); let mut db = rpc_ctx.db.handle();
embassy::hostname::sync_hostname(&mut db).await?;
let receipts = embassy::context::rpc::RpcSetNginxReceipts::new(&mut db).await?; let receipts = embassy::context::rpc::RpcSetNginxReceipts::new(&mut db).await?;
embassy::hostname::sync_hostname(&mut db, &receipts.hostname_receipts).await?;
rpc_ctx.set_nginx_conf(&mut db, receipts).await?; rpc_ctx.set_nginx_conf(&mut db, receipts).await?;
drop(db); drop(db);

View File

@@ -23,6 +23,7 @@ use tracing::instrument;
use crate::core::rpc_continuations::{RequestGuid, RestHandler, RpcContinuation}; use crate::core::rpc_continuations::{RequestGuid, RestHandler, RpcContinuation};
use crate::db::model::{Database, InstalledPackageDataEntry, PackageDataEntry}; use crate::db::model::{Database, InstalledPackageDataEntry, PackageDataEntry};
use crate::hostname::HostNameReceipt;
use crate::init::{init_postgres, pgloader}; use crate::init::{init_postgres, pgloader};
use crate::install::cleanup::{cleanup_failed, uninstall, CleanupFailedReceipts}; use crate::install::cleanup::{cleanup_failed, uninstall, CleanupFailedReceipts};
use crate::manager::ManagerMap; use crate::manager::ManagerMap;
@@ -175,6 +176,7 @@ impl RpcCleanReceipts {
} }
pub struct RpcSetNginxReceipts { pub struct RpcSetNginxReceipts {
pub hostname_receipts: HostNameReceipt,
server_info: LockReceipt<crate::db::model::ServerInfo, ()>, server_info: LockReceipt<crate::db::model::ServerInfo, ()>,
} }
@@ -189,12 +191,14 @@ impl RpcSetNginxReceipts {
pub fn setup( pub fn setup(
locks: &mut Vec<patch_db::LockTargetId>, locks: &mut Vec<patch_db::LockTargetId>,
) -> impl FnOnce(&patch_db::Verifier) -> Result<Self, Error> { ) -> impl FnOnce(&patch_db::Verifier) -> Result<Self, Error> {
let hostname_receipts = HostNameReceipt::setup(locks);
let server_info = crate::db::DatabaseModel::new() let server_info = crate::db::DatabaseModel::new()
.server_info() .server_info()
.make_locker(LockType::Read) .make_locker(LockType::Read)
.add_to_keys(locks); .add_to_keys(locks);
move |skeleton_key| { move |skeleton_key| {
Ok(Self { Ok(Self {
hostname_receipts: hostname_receipts(skeleton_key)?,
server_info: server_info.verify(skeleton_key)?, server_info: server_info.verify(skeleton_key)?,
}) })
} }

View File

@@ -56,36 +56,83 @@ pub async fn set_hostname(hostname: &Hostname) -> Result<(), Error> {
Ok(()) Ok(())
} }
#[instrument(skip(handle))] #[instrument(skip(handle, receipts))]
pub async fn get_id<Db: DbHandle>(handle: &mut Db) -> Result<String, Error> { pub async fn get_id<Db: DbHandle>(
let id = crate::db::DatabaseModel::new() handle: &mut Db,
.server_info() receipts: &HostNameReceipt,
.id() ) -> Result<String, Error> {
.get(handle, false) let id = receipts.id.get(handle).await?;
.await?; Ok(id)
Ok(id.to_string())
} }
pub async fn get_hostname<Db: DbHandle>(handle: &mut Db) -> Result<Hostname, Error> { pub async fn get_hostname<Db: DbHandle>(
if let Ok(hostname) = crate::db::DatabaseModel::new() handle: &mut Db,
.server_info() receipts: &HostNameReceipt,
.hostname() ) -> Result<Hostname, Error> {
.get(handle, false) if let Ok(hostname) = receipts.hostname.get(handle).await {
.await
{
if let Some(hostname) = hostname.to_owned() { if let Some(hostname) = hostname.to_owned() {
return Ok(Hostname(hostname)); return Ok(Hostname(hostname));
} }
} }
let id = get_id(handle).await?; let id = get_id(handle, receipts).await?;
if id.len() != 8 { if id.len() != 8 {
return Ok(generate_hostname()); return Ok(generate_hostname());
} }
return Ok(Hostname(format!("embassy-{}", id))); return Ok(Hostname(format!("embassy-{}", id)));
} }
#[instrument(skip(handle))]
pub async fn sync_hostname<Db: DbHandle>(handle: &mut Db) -> Result<(), Error> { pub async fn ensure_hostname_is_set<Db: DbHandle>(
set_hostname(&get_hostname(handle).await?).await?; handle: &mut Db,
receipts: &HostNameReceipt,
) -> Result<(), Error> {
let hostname = get_hostname(handle, &receipts).await?;
receipts.hostname.set(handle, Some(hostname.0)).await?;
Ok(())
}
#[derive(Clone)]
pub struct HostNameReceipt {
hostname: patch_db::LockReceipt<Option<String>, ()>,
pub id: patch_db::LockReceipt<String, ()>,
}
impl HostNameReceipt {
pub async fn new<'a>(db: &'a mut impl DbHandle) -> Result<Self, Error> {
let mut locks = Vec::new();
let setup = Self::setup(&mut locks);
setup(&db.lock_all(locks).await?)
}
pub fn setup(
locks: &mut Vec<patch_db::LockTargetId>,
) -> impl FnOnce(&patch_db::Verifier) -> Result<Self, Error> {
use patch_db::LockType;
let hostname = crate::db::DatabaseModel::new()
.server_info()
.hostname()
.make_locker(LockType::Write)
.add_to_keys(locks);
let id = crate::db::DatabaseModel::new()
.server_info()
.id()
.make_locker(LockType::Write)
.add_to_keys(locks);
move |skeleton_key| {
Ok(Self {
hostname: hostname.verify(skeleton_key)?,
id: id.verify(skeleton_key)?,
})
}
}
}
#[instrument(skip(handle, receipts))]
pub async fn sync_hostname<Db: DbHandle>(
handle: &mut Db,
receipts: &HostNameReceipt,
) -> Result<(), Error> {
set_hostname(&get_hostname(handle, receipts).await?).await?;
Command::new("systemctl") Command::new("systemctl")
.arg("restart") .arg("restart")
.arg("avahi-daemon") .arg("avahi-daemon")

View File

@@ -66,7 +66,9 @@ impl NetController {
None => SslManager::init(db, handle).await, None => SslManager::init(db, handle).await,
Some(a) => SslManager::import_root_ca(db, a.0, a.1).await, Some(a) => SslManager::import_root_ca(db, a.0, a.1).await,
}?; }?;
let hostname = get_hostname(handle).await?;
let hostname_receipts = crate::hostname::HostNameReceipt::new(handle).await?;
let hostname = get_hostname(handle, &hostname_receipts).await?;
Ok(Self { Ok(Self {
tor: TorController::init(embassyd_addr, embassyd_tor_key, tor_control).await?, tor: TorController::init(embassyd_addr, embassyd_tor_key, tor_control).await?,
#[cfg(feature = "avahi")] #[cfg(feature = "avahi")]

View File

@@ -165,7 +165,8 @@ impl SslManager {
#[instrument(skip(db, handle))] #[instrument(skip(db, handle))]
pub async fn init<Db: DbHandle>(db: PgPool, handle: &mut Db) -> Result<Self, Error> { pub async fn init<Db: DbHandle>(db: PgPool, handle: &mut Db) -> Result<Self, Error> {
let store = SslStore::new(db)?; let store = SslStore::new(db)?;
let id = crate::hostname::get_id(handle).await?; let receipts = crate::hostname::HostNameReceipt::new(handle).await?;
let id = crate::hostname::get_id(handle, &receipts).await?;
let (root_key, root_cert) = match store.load_root_certificate().await? { let (root_key, root_cert) = match store.load_root_certificate().await? {
None => { None => {
let root_key = generate_key()?; let root_key = generate_key()?;
@@ -528,7 +529,7 @@ fn make_leaf_cert(
// let root_cert1 = mgr.root_cert; // let root_cert1 = mgr.root_cert;
// let int_key1 = mgr.int_key; // let int_key1 = mgr.int_key;
// let int_cert1 = mgr.int_cert; // let int_cert1 = mgr.int_cert;
// //
// assert_eq!(root_cert0.to_pem()?, root_cert1.to_pem()?); // assert_eq!(root_cert0.to_pem()?, root_cert1.to_pem()?);
// assert_eq!( // assert_eq!(
// int_key0.private_key_to_pem_pkcs8()?, // int_key0.private_key_to_pem_pkcs8()?,
@@ -537,7 +538,7 @@ fn make_leaf_cert(
// assert_eq!(int_cert0.to_pem()?, int_cert1.to_pem()?); // assert_eq!(int_cert0.to_pem()?, int_cert1.to_pem()?);
// Ok(()) // Ok(())
// } // }
// //
// #[tokio::test] // #[tokio::test]
// async fn certificate_details_persist() -> Result<(), Error> { // async fn certificate_details_persist() -> Result<(), Error> {
// let pool = sqlx::Pool::<sqlx::Postgres>::connect("postgres::memory:").await?; // let pool = sqlx::Pool::<sqlx::Postgres>::connect("postgres::memory:").await?;
@@ -549,7 +550,7 @@ fn make_leaf_cert(
// let package_id = "bitcoind".parse().unwrap(); // let package_id = "bitcoind".parse().unwrap();
// let (key0, cert_chain0) = mgr.certificate_for("start9", &package_id).await?; // let (key0, cert_chain0) = mgr.certificate_for("start9", &package_id).await?;
// let (key1, cert_chain1) = mgr.certificate_for("start9", &package_id).await?; // let (key1, cert_chain1) = mgr.certificate_for("start9", &package_id).await?;
// //
// assert_eq!( // assert_eq!(
// key0.private_key_to_pem_pkcs8()?, // key0.private_key_to_pem_pkcs8()?,
// key1.private_key_to_pem_pkcs8()? // key1.private_key_to_pem_pkcs8()?

View File

@@ -38,7 +38,7 @@ use crate::disk::mount::filesystem::ReadOnly;
use crate::disk::mount::guard::TmpMountGuard; use crate::disk::mount::guard::TmpMountGuard;
use crate::disk::util::{pvscan, recovery_info, DiskInfo, EmbassyOsRecoveryInfo}; use crate::disk::util::{pvscan, recovery_info, DiskInfo, EmbassyOsRecoveryInfo};
use crate::disk::REPAIR_DISK_PATH; use crate::disk::REPAIR_DISK_PATH;
use crate::hostname::{get_hostname, Hostname}; use crate::hostname::{get_hostname, HostNameReceipt, Hostname};
use crate::id::Id; use crate::id::Id;
use crate::init::init; use crate::init::init;
use crate::install::PKG_PUBLIC_DIR; use crate::install::PKG_PUBLIC_DIR;
@@ -158,7 +158,9 @@ pub async fn attach(
db_tx.commit().await?; db_tx.commit().await?;
secrets_tx.commit().await?; secrets_tx.commit().await?;
let hostname = get_hostname(&mut db_handle).await?;
let hostname_receipts = HostNameReceipt::new(&mut db_handle).await?;
let hostname = get_hostname(&mut db_handle, &hostname_receipts).await?;
let (_, root_ca) = SslManager::init(secrets, &mut db_handle) let (_, root_ca) = SslManager::init(secrets, &mut db_handle)
.await? .await?
@@ -321,9 +323,10 @@ pub async fn complete(#[context] ctx: SetupContext) -> Result<SetupResult, Error
}; };
let secrets = ctx.secret_store().await?; let secrets = ctx.secret_store().await?;
let mut db = ctx.db(&secrets).await?.handle(); let mut db = ctx.db(&secrets).await?.handle();
let hostname = crate::hostname::get_hostname(&mut db).await?; let receipts = crate::hostname::HostNameReceipt::new(&mut db).await?;
let hostname = crate::hostname::get_hostname(&mut db, &receipts).await?;
let si = crate::db::DatabaseModel::new().server_info(); let si = crate::db::DatabaseModel::new().server_info();
let id = crate::hostname::get_id(&mut db).await?; let id = crate::hostname::get_id(&mut db, &receipts).await?;
si.clone().id().put(&mut db, &id).await?; si.clone().id().put(&mut db, &id).await?;
si.lan_address() si.lan_address()
.put(&mut db, &hostname.lan_address().parse().unwrap()) .put(&mut db, &hostname.lan_address().parse().unwrap())
@@ -378,7 +381,11 @@ pub async fn execute_inner(
let db = init(&RpcContextConfig::load(ctx.config_path.as_ref()).await?) let db = init(&RpcContextConfig::load(ctx.config_path.as_ref()).await?)
.await? .await?
.db; .db;
let hostname = get_hostname(&mut db.handle()).await?; let hostname = {
let mut handle = db.handle();
let receipts = crate::hostname::HostNameReceipt::new(&mut handle).await?;
get_hostname(&mut handle, &receipts).await?
};
let res = (hostname.clone(), tor_addr, root_ca.clone()); let res = (hostname.clone(), tor_addr, root_ca.clone());
tokio::spawn(async move { tokio::spawn(async move {
if let Err(e) = recover_fut if let Err(e) = recover_fut
@@ -412,15 +419,17 @@ pub async fn execute_inner(
let db = init(&RpcContextConfig::load(ctx.config_path.as_ref()).await?) let db = init(&RpcContextConfig::load(ctx.config_path.as_ref()).await?)
.await? .await?
.db; .db;
let mut handle = db.handle();
let receipts = crate::hostname::HostNameReceipt::new(&mut handle).await?;
*ctx.setup_result.write().await = Some(( *ctx.setup_result.write().await = Some((
guid, guid,
SetupResult { SetupResult {
tor_address: format!("http://{}", tor_addr), tor_address: format!("http://{}", tor_addr),
lan_address: get_hostname(&mut db.handle()).await?.lan_address(), lan_address: get_hostname(&mut handle, &receipts).await?.lan_address(),
root_ca: String::from_utf8(root_ca.to_pem()?)?, root_ca: String::from_utf8(root_ca.to_pem()?)?,
}, },
)); ));
let hostname = get_hostname(&mut db.handle()).await?; let hostname = get_hostname(&mut handle, &receipts).await?;
(hostname, tor_addr, root_ca) (hostname, tor_addr, root_ca)
}; };

View File

@@ -1,6 +1,6 @@
use emver::VersionRange; use emver::VersionRange;
use crate::hostname::{generate_id, get_hostname, sync_hostname}; use crate::hostname::{generate_id, sync_hostname};
use super::v0_3_0::V0_3_0_COMPAT; use super::v0_3_0::V0_3_0_COMPAT;
use super::*; use super::*;
@@ -22,19 +22,11 @@ impl VersionT for Version {
&*V0_3_0_COMPAT &*V0_3_0_COMPAT
} }
async fn up<Db: DbHandle>(&self, db: &mut Db) -> Result<(), Error> { async fn up<Db: DbHandle>(&self, db: &mut Db) -> Result<(), Error> {
let hostname = get_hostname(db).await?; let receipts = crate::hostname::HostNameReceipt::new(db).await?;
crate::db::DatabaseModel::new() crate::hostname::ensure_hostname_is_set(db, &receipts).await?;
.server_info() receipts.id.set(db, generate_id()).await?;
.hostname()
.put(db, &Some(hostname.0))
.await?;
crate::db::DatabaseModel::new()
.server_info()
.id()
.put(db, &generate_id())
.await?;
sync_hostname(db).await?; sync_hostname(db, &receipts).await?;
Ok(()) Ok(())
} }
async fn down<Db: DbHandle>(&self, _db: &mut Db) -> Result<(), Error> { async fn down<Db: DbHandle>(&self, _db: &mut Db) -> Result<(), Error> {