11use clap:: { Parser , Subcommand , ValueEnum } ;
22use comfy_table:: { Cell , Table , modifiers:: UTF8_ROUND_CORNERS , presets:: UTF8_FULL } ;
33use 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} ;
2420use eyre:: { Context , ContextCompat } ;
25- use reqwest:: header:: HeaderValue ;
26- use serde:: { Deserialize , Serialize } ;
2721use serde_json:: json;
28- use std:: { path:: PathBuf , sync :: Arc } ;
22+ use std:: path:: PathBuf ;
2923use tracing_indicatif:: IndicatifLayer ;
3024use 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 ) ]
3828struct 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 ) ]
9756pub 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