Skip to content

Commit f461c45

Browse files
committed
feat: update to latest shared managament logic
1 parent 6b25d9d commit f461c45

5 files changed

Lines changed: 40 additions & 182 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ dotenvy = "=0.15.7"
1515
clap = { version = "=4.5.40", features = ["derive"] }
1616

1717
# Management access
18-
docbox-management = { version = "0.7.0" }
18+
docbox-management = { version = "0.8.0" }
1919

2020
# Asynchronous runtime & Helpers
2121
tokio = { version = "=1.48.0", features = ["full"] }
@@ -44,4 +44,4 @@ inherits = "release"
4444
lto = "thin"
4545

4646
# [patch.crates-io]
47-
# docbox-management = { version = "0.7.0", path = "../docbox/packages/docbox-management" }
47+
# docbox-management = { version = "0.8.0", path = "../docbox/packages/docbox-management" }

cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"dotenvy",
99
"indicatif",
1010
"reqwest",
11-
"Jacobtread"
11+
"Jacobtread",
12+
"rustls"
1213
]
1314
}

src/database.rs

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/main.rs

Lines changed: 33 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,28 @@
11
use clap::{Parser, Subcommand, ValueEnum};
22
use comfy_table::{Cell, Table, modifiers::UTF8_ROUND_CORNERS, presets::UTF8_FULL};
33
use docbox_management::{
4+
config::{ServerConfigData, load_server_config_data_secret},
45
core::{
5-
aws::{SqsClient, aws_config},
6-
events::{EventPublisherFactory, sqs::SqsEventPublisherFactory},
6+
aws::aws_config,
77
tenant::rebuild_tenant_index::{rebuild_tenant_index, recreate_search_index_data},
88
},
9-
database::{
10-
DatabasePoolCache, DatabasePoolCacheConfig, DatabaseProvider, close_pool_on_drop,
11-
models::tenant::TenantId,
12-
},
13-
search::{SearchIndexFactory, SearchIndexFactoryConfig},
14-
secrets::{SecretManager, SecretsManagerConfig, aws::AwsSecretManagerConfig},
15-
storage::{StorageLayerFactory, StorageLayerFactoryConfig},
9+
database::{DatabaseProvider, close_pool_on_drop, models::tenant::TenantId},
10+
server::{ManagedServer, load_managed_server},
1611
tenant::{
1712
create_tenant::CreateTenantConfig,
1813
delete_tenant::{DeleteTenant, DeleteTenantOptions},
14+
flush_tenant_cache::flush_tenant_cache,
1915
get_tenant::get_tenant,
2016
migrate_tenants::MigrateTenantsConfig,
2117
migrate_tenants_search::{MigrateTenantsSearchConfig, migrate_tenants_search},
2218
},
2319
};
2420
use eyre::{Context, ContextCompat};
25-
use reqwest::header::HeaderValue;
26-
use serde::{Deserialize, Serialize};
2721
use serde_json::json;
28-
use std::{path::PathBuf, sync::Arc};
22+
use std::path::PathBuf;
2923
use tracing_indicatif::IndicatifLayer;
3024
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
3125

32-
use crate::database::CliDatabaseProvider;
33-
34-
mod database;
35-
3626
#[derive(Parser)]
3727
#[command(version, about, long_about = None)]
3828
struct Args {
@@ -62,37 +52,6 @@ pub enum OutputFormat {
6252
Json,
6353
}
6454

65-
#[derive(Clone, Deserialize)]
66-
pub struct CliConfiguration {
67-
pub api: ApiConfig,
68-
pub database: AdminDatabaseConfiguration,
69-
pub secrets: SecretsManagerConfig,
70-
pub search: SearchIndexFactoryConfig,
71-
pub storage: StorageLayerFactoryConfig,
72-
}
73-
74-
#[derive(Clone, Deserialize, Serialize)]
75-
pub struct ApiConfig {
76-
pub url: String,
77-
pub api_key: Option<String>,
78-
}
79-
80-
#[derive(Clone, Deserialize, Serialize)]
81-
pub struct AdminDatabaseConfiguration {
82-
pub host: String,
83-
pub port: u16,
84-
pub setup_user: Option<AdminDatabaseSetupUserConfig>,
85-
pub setup_user_secret_name: Option<String>,
86-
pub root_secret_name: String,
87-
}
88-
89-
#[derive(Clone, Deserialize, Serialize)]
90-
pub struct AdminDatabaseSetupUserConfig {
91-
#[serde(alias = "user")]
92-
pub username: String,
93-
pub password: String,
94-
}
95-
9655
#[derive(Subcommand)]
9756
pub enum Commands {
9857
/// Initialize the root docbox database
@@ -283,93 +242,30 @@ async fn app(args: Args) -> eyre::Result<()> {
283242
let aws_config = aws_config().await;
284243

285244
// Load the config data
286-
let config: CliConfiguration = match (args.config, args.aws_config_secret) {
245+
let config: ServerConfigData = match (args.config, args.aws_config_secret) {
287246
(Some(config_path), _) => {
288247
let config_raw = tokio::fs::read(config_path).await?;
289-
let config: CliConfiguration =
248+
let config: ServerConfigData =
290249
serde_json::from_slice(&config_raw).context("failed to parse config")?;
291250
config
292251
}
293252
(_, Some(config_secret_name)) => {
294-
let secrets = SecretManager::from_config(
295-
&aws_config,
296-
SecretsManagerConfig::Aws(
297-
AwsSecretManagerConfig::from_env()
298-
.context("failed to load aws secrets manager config")?,
299-
),
300-
);
301-
secrets
302-
.parsed_secret(&config_secret_name)
303-
.await
304-
.context("failed to get config secret")?
305-
.context("config secret not found")?
253+
load_server_config_data_secret(&aws_config, &config_secret_name).await?
306254
}
307255

308256
_ => eyre::bail!(
309257
"must provided either --config or --aws-config-secret check --help for more details"
310258
),
311259
};
312260

313-
let secrets = SecretManager::from_config(&aws_config, config.secrets.clone());
314-
315-
// Create the SQS client
316-
// Warning: Will panic if the configuration provided is invalid
317-
let sqs_client = SqsClient::new(&aws_config);
318-
319-
// Setup event publisher factories
320-
let sqs_publisher_factory = SqsEventPublisherFactory::new(sqs_client.clone());
321-
let events = EventPublisherFactory::new(sqs_publisher_factory);
322-
323-
// Setup database cache / connector
324-
let db_cache = Arc::new(DatabasePoolCache::from_config(
325-
DatabasePoolCacheConfig {
326-
host: config.database.host.clone(),
327-
port: config.database.port,
328-
root_secret_name: config.database.root_secret_name.clone(),
329-
max_connections: None,
330-
..Default::default()
331-
},
332-
secrets.clone(),
333-
));
334-
335-
let search_factory = SearchIndexFactory::from_config(
336-
&aws_config,
337-
secrets.clone(),
261+
let ManagedServer {
338262
db_cache,
339-
config.search.clone(),
340-
)?;
341-
let storage_factory = StorageLayerFactory::from_config(&aws_config, config.storage.clone());
342-
343-
let db_provider = match (
344-
config.database.setup_user.as_ref(),
345-
config.database.setup_user_secret_name.as_deref(),
346-
) {
347-
(Some(setup_user), _) => CliDatabaseProvider {
348-
config: config.database.clone(),
349-
username: setup_user.username.clone(),
350-
password: setup_user.password.clone(),
351-
},
352-
(_, Some(setup_user_secret_name)) => {
353-
let secret: AdminDatabaseSetupUserConfig = secrets
354-
.parsed_secret(setup_user_secret_name)
355-
.await
356-
.context("failed to get setup user database secret")?
357-
.context("setup user database secret not found")?;
358-
359-
tracing::debug!("loaded database secrets from secret manager");
360-
361-
CliDatabaseProvider {
362-
config: config.database.clone(),
363-
username: secret.username.clone(),
364-
password: secret.password.clone(),
365-
}
366-
}
367-
(None, None) => {
368-
return Err(eyre::eyre!(
369-
"must provided either setup_user or setup_user_secret_name in database config"
370-
));
371-
}
372-
};
263+
db_provider,
264+
secrets,
265+
search,
266+
storage,
267+
events,
268+
} = load_managed_server(&aws_config, &config).await.unwrap();
373269

374270
match args.command {
375271
Commands::CreateRoot => {
@@ -434,8 +330,8 @@ async fn app(args: Args) -> eyre::Result<()> {
434330

435331
let tenant = docbox_management::tenant::create_tenant::create_tenant(
436332
&db_provider,
437-
&search_factory,
438-
&storage_factory,
333+
&search,
334+
&storage,
439335
&secrets,
440336
tenant_config,
441337
)
@@ -478,15 +374,24 @@ async fn app(args: Args) -> eyre::Result<()> {
478374
delete_storage,
479375
permanently_delete_secret,
480376
} => {
377+
let tenant =
378+
docbox_management::tenant::get_tenant::get_tenant(&db_provider, &env, tenant_id)
379+
.await?
380+
.context("tenant not found")?;
381+
382+
// Must close the connections in advance to ensure the tenant
383+
// database can be deleted
384+
db_cache.close_tenant_pool(&tenant).await;
385+
481386
// Tell the API server to flush and close its database pools
482387
flush_tenant_cache(&config.api)
483388
.await
484389
.context("failed to flush tenant cache")?;
485390

486391
docbox_management::tenant::delete_tenant::delete_tenant(
487392
&db_provider,
488-
&search_factory,
489-
&storage_factory,
393+
&search,
394+
&storage,
490395
&events,
491396
&secrets,
492397
DeleteTenant {
@@ -680,7 +585,7 @@ async fn app(args: Args) -> eyre::Result<()> {
680585
} => {
681586
let outcome = migrate_tenants_search(
682587
&db_provider,
683-
&search_factory,
588+
&search,
684589
MigrateTenantsSearchConfig {
685590
env: Some(env),
686591
tenant_id,
@@ -735,8 +640,8 @@ async fn app(args: Args) -> eyre::Result<()> {
735640
.await?
736641
.context("tenant not found")?;
737642

738-
let search = search_factory.create_search_index(&tenant);
739-
let storage = storage_factory.create_storage_layer(&tenant);
643+
let search = search.create_search_index(&tenant);
644+
let storage = storage.create_storage_layer(&tenant);
740645

741646
// Connect to the tenant database
742647
let db = db_provider
@@ -773,7 +678,7 @@ async fn app(args: Args) -> eyre::Result<()> {
773678
.await?
774679
.context("tenant not found")?;
775680

776-
let storage = storage_factory.create_storage_layer(&tenant);
681+
let storage = storage.create_storage_layer(&tenant);
777682

778683
storage.set_bucket_cors_origins(origin).await?;
779684

@@ -795,31 +700,3 @@ async fn app(args: Args) -> eyre::Result<()> {
795700
}
796701
}
797702
}
798-
799-
/// Makes a request to the docbox API server telling it to flush its
800-
/// database cache
801-
pub async fn flush_tenant_cache(api: &ApiConfig) -> eyre::Result<()> {
802-
let client = reqwest::Client::new();
803-
804-
let url = format!("{}/admin/flush-db-cache", &api.url);
805-
let mut req_builder = client.post(&url);
806-
807-
if let Some(api_key) = api.api_key.as_ref() {
808-
req_builder = req_builder.header(
809-
reqwest::header::HeaderName::from_static("x-docbox-api-key"),
810-
HeaderValue::from_str(api_key).context("failed to make header value")?,
811-
);
812-
}
813-
814-
let response = req_builder
815-
.send()
816-
.await
817-
.inspect_err(|error| tracing::error!(?error, "failed to request docbox"))
818-
.context("failed to request docbox")?;
819-
820-
response
821-
.error_for_status()
822-
.context("error response flushing db cache")?;
823-
824-
Ok(())
825-
}

0 commit comments

Comments
 (0)