2021-03-12 14:40:54 +00:00
use std ::collections ::HashMap ;
2021-03-12 17:16:03 +00:00
use std ::fmt ::Write ;
use std ::sync ::Arc ;
2020-04-19 15:15:48 +00:00
2021-10-14 09:50:12 +00:00
use async_trait ::async_trait ;
2020-04-19 15:15:48 +00:00
use serde ::{ Deserialize , Serialize } ;
2020-04-24 10:10:01 +00:00
use garage_util ::error ::Error ;
2020-04-23 17:05:46 +00:00
2021-05-02 21:13:08 +00:00
use garage_table ::crdt ::Crdt ;
2021-03-12 14:40:54 +00:00
use garage_table ::replication ::* ;
2021-03-12 17:16:03 +00:00
use garage_table ::* ;
2020-04-19 15:15:48 +00:00
2021-10-14 09:50:12 +00:00
use garage_rpc ::* ;
2020-04-23 17:05:46 +00:00
2020-07-07 11:59:22 +00:00
use garage_model ::bucket_table ::* ;
use garage_model ::garage ::Garage ;
use garage_model ::key_table ::* ;
2020-04-23 17:05:46 +00:00
2021-03-12 17:12:31 +00:00
use crate ::cli ::* ;
2021-03-12 17:16:03 +00:00
use crate ::repair ::Repair ;
2020-04-19 15:15:48 +00:00
2021-10-14 09:50:12 +00:00
pub const ADMIN_RPC_PATH : & str = " garage/admin_rpc.rs/Rpc " ;
2020-04-19 15:15:48 +00:00
#[ derive(Debug, Serialize, Deserialize) ]
2021-04-23 20:41:24 +00:00
pub enum AdminRpc {
2020-04-19 15:15:48 +00:00
BucketOperation ( BucketOperation ) ,
2020-04-23 18:36:12 +00:00
KeyOperation ( KeyOperation ) ,
2020-04-21 16:40:17 +00:00
LaunchRepair ( RepairOpt ) ,
2021-03-12 14:40:54 +00:00
Stats ( StatsOpt ) ,
2020-04-19 15:15:48 +00:00
// Replies
2020-04-19 17:59:59 +00:00
Ok ( String ) ,
2020-04-19 15:15:48 +00:00
BucketList ( Vec < String > ) ,
BucketInfo ( Bucket ) ,
2020-04-23 20:25:45 +00:00
KeyList ( Vec < ( String , String ) > ) ,
KeyInfo ( Key ) ,
2020-04-19 15:15:48 +00:00
}
2021-10-15 09:05:09 +00:00
impl Rpc for AdminRpc {
type Response = Result < AdminRpc , Error > ;
2021-10-14 09:50:12 +00:00
}
2020-04-19 15:15:48 +00:00
pub struct AdminRpcHandler {
garage : Arc < Garage > ,
2021-10-14 09:50:12 +00:00
endpoint : Arc < Endpoint < AdminRpc , Self > > ,
2020-04-19 15:15:48 +00:00
}
impl AdminRpcHandler {
pub fn new ( garage : Arc < Garage > ) -> Arc < Self > {
2021-10-14 09:50:12 +00:00
let endpoint = garage . system . netapp . endpoint ( ADMIN_RPC_PATH . into ( ) ) ;
let admin = Arc ::new ( Self { garage , endpoint } ) ;
admin . endpoint . set_handler ( admin . clone ( ) ) ;
admin
2020-04-19 15:15:48 +00:00
}
2021-10-14 09:50:12 +00:00
async fn handle_bucket_cmd ( & self , cmd : & BucketOperation ) -> Result < AdminRpc , Error > {
2020-04-19 15:15:48 +00:00
match cmd {
BucketOperation ::List = > {
let bucket_names = self
. garage
. bucket_table
2020-11-20 19:11:04 +00:00
. get_range ( & EmptyKey , None , Some ( DeletedFilter ::NotDeleted ) , 10000 )
2020-04-19 15:15:48 +00:00
. await ?
. iter ( )
. map ( | b | b . name . to_string ( ) )
. collect ::< Vec < _ > > ( ) ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::BucketList ( bucket_names ) )
2020-04-19 15:15:48 +00:00
}
BucketOperation ::Info ( query ) = > {
2020-04-23 20:25:45 +00:00
let bucket = self . get_existing_bucket ( & query . name ) . await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::BucketInfo ( bucket ) )
2020-04-19 15:15:48 +00:00
}
BucketOperation ::Create ( query ) = > {
2020-11-20 22:01:12 +00:00
let bucket = match self . garage . bucket_table . get ( & EmptyKey , & query . name ) . await ? {
Some ( mut bucket ) = > {
if ! bucket . is_deleted ( ) {
2021-05-02 21:13:08 +00:00
return Err ( Error ::BadRpc ( format! (
2020-11-20 22:01:12 +00:00
" Bucket {} already exists " ,
query . name
) ) ) ;
}
bucket
. state
2020-12-14 20:46:49 +00:00
. update ( BucketState ::Present ( BucketParams ::new ( ) ) ) ;
2020-11-20 22:01:12 +00:00
bucket
}
None = > Bucket ::new ( query . name . clone ( ) ) ,
2020-04-19 15:15:48 +00:00
} ;
2020-11-20 22:01:12 +00:00
self . garage . bucket_table . insert ( & bucket ) . await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( format! ( " Bucket {} was created. " , query . name ) ) )
2020-04-19 15:15:48 +00:00
}
BucketOperation ::Delete ( query ) = > {
2020-11-20 22:01:12 +00:00
let mut bucket = self . get_existing_bucket ( & query . name ) . await ? ;
2020-04-19 15:15:48 +00:00
let objects = self
. garage
. object_table
2020-11-20 19:11:04 +00:00
. get_range ( & query . name , None , Some ( DeletedFilter ::NotDeleted ) , 10 )
2020-04-19 15:15:48 +00:00
. await ? ;
if ! objects . is_empty ( ) {
2021-05-02 21:13:08 +00:00
return Err ( Error ::BadRpc ( format! ( " Bucket {} is not empty " , query . name ) ) ) ;
2020-04-19 15:15:48 +00:00
}
if ! query . yes {
2021-05-02 21:13:08 +00:00
return Err ( Error ::BadRpc (
2021-04-23 20:41:24 +00:00
" Add --yes flag to really perform this operation " . to_string ( ) ,
) ) ;
2020-04-19 15:15:48 +00:00
}
2020-04-23 20:25:45 +00:00
// --- done checking, now commit ---
2020-11-20 22:01:12 +00:00
for ( key_id , _ , _ ) in bucket . authorized_keys ( ) {
if let Some ( key ) = self . garage . key_table . get ( & EmptyKey , key_id ) . await ? {
2020-11-20 20:15:24 +00:00
if ! key . deleted . get ( ) {
2021-03-15 18:14:26 +00:00
self . update_key_bucket ( & key , & bucket . name , false , false )
2020-04-23 20:25:45 +00:00
. await ? ;
}
} else {
2020-11-20 22:01:12 +00:00
return Err ( Error ::Message ( format! ( " Key not found: {} " , key_id ) ) ) ;
2020-04-23 20:25:45 +00:00
}
}
2020-11-20 22:01:12 +00:00
bucket . state . update ( BucketState ::Deleted ) ;
self . garage . bucket_table . insert ( & bucket ) . await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( format! ( " Bucket {} was deleted. " , query . name ) ) )
2020-04-19 15:15:48 +00:00
}
2020-04-23 20:25:45 +00:00
BucketOperation ::Allow ( query ) = > {
2021-03-15 18:14:26 +00:00
let key = self . get_existing_key ( & query . key_pattern ) . await ? ;
2020-04-23 20:25:45 +00:00
let bucket = self . get_existing_bucket ( & query . bucket ) . await ? ;
let allow_read = query . read | | key . allow_read ( & query . bucket ) ;
let allow_write = query . write | | key . allow_write ( & query . bucket ) ;
2021-03-15 18:14:26 +00:00
self . update_key_bucket ( & key , & query . bucket , allow_read , allow_write )
2020-04-23 20:25:45 +00:00
. await ? ;
2021-03-15 18:14:26 +00:00
self . update_bucket_key ( bucket , & key . key_id , allow_read , allow_write )
2020-04-23 20:25:45 +00:00
. await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( format! (
2020-04-23 20:25:45 +00:00
" New permissions for {} on {}: read {}, write {}. " ,
2021-03-15 18:14:26 +00:00
& key . key_id , & query . bucket , allow_read , allow_write
2020-04-23 20:25:45 +00:00
) ) )
}
BucketOperation ::Deny ( query ) = > {
2021-03-15 18:14:26 +00:00
let key = self . get_existing_key ( & query . key_pattern ) . await ? ;
2020-04-23 20:25:45 +00:00
let bucket = self . get_existing_bucket ( & query . bucket ) . await ? ;
let allow_read = ! query . read & & key . allow_read ( & query . bucket ) ;
let allow_write = ! query . write & & key . allow_write ( & query . bucket ) ;
2021-03-15 18:14:26 +00:00
self . update_key_bucket ( & key , & query . bucket , allow_read , allow_write )
2020-04-23 20:25:45 +00:00
. await ? ;
2021-03-15 18:14:26 +00:00
self . update_bucket_key ( bucket , & key . key_id , allow_read , allow_write )
2020-04-23 20:25:45 +00:00
. await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( format! (
2020-04-23 20:25:45 +00:00
" New permissions for {} on {}: read {}, write {}. " ,
2021-03-15 18:14:26 +00:00
& key . key_id , & query . bucket , allow_read , allow_write
2020-04-23 20:25:45 +00:00
) ) )
2020-04-19 15:15:48 +00:00
}
2020-12-10 17:13:32 +00:00
BucketOperation ::Website ( query ) = > {
2020-12-15 11:48:24 +00:00
let mut bucket = self . get_existing_bucket ( & query . bucket ) . await ? ;
if ! ( query . allow ^ query . deny ) {
2021-04-23 20:41:24 +00:00
return Err ( Error ::Message (
" You must specify exactly one flag, either --allow or --deny " . to_string ( ) ,
) ) ;
2020-12-12 16:00:31 +00:00
}
2020-12-15 11:48:24 +00:00
if let BucketState ::Present ( state ) = bucket . state . get_mut ( ) {
state . website . update ( query . allow ) ;
2020-12-15 12:23:22 +00:00
self . garage . bucket_table . insert ( & bucket ) . await ? ;
2020-12-15 11:48:24 +00:00
let msg = if query . allow {
format! ( " Website access allowed for {} " , & query . bucket )
2020-12-12 16:00:31 +00:00
} else {
2020-12-15 11:48:24 +00:00
format! ( " Website access denied for {} " , & query . bucket )
} ;
2020-12-12 16:00:31 +00:00
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( msg ) )
2020-12-12 16:00:31 +00:00
} else {
2021-01-15 14:44:44 +00:00
unreachable! ( ) ;
2020-12-15 11:48:24 +00:00
}
2020-12-10 17:13:32 +00:00
}
2020-04-19 15:15:48 +00:00
}
}
2020-04-19 20:36:36 +00:00
2021-10-14 09:50:12 +00:00
async fn handle_key_cmd ( & self , cmd : & KeyOperation ) -> Result < AdminRpc , Error > {
2020-04-23 20:25:45 +00:00
match cmd {
KeyOperation ::List = > {
let key_ids = self
. garage
. key_table
2021-03-15 22:14:12 +00:00
. get_range (
& EmptyKey ,
None ,
Some ( KeyFilter ::Deleted ( DeletedFilter ::NotDeleted ) ) ,
10000 ,
)
2020-04-23 20:25:45 +00:00
. await ?
. iter ( )
2020-11-20 20:15:24 +00:00
. map ( | k | ( k . key_id . to_string ( ) , k . name . get ( ) . clone ( ) ) )
2020-04-23 20:25:45 +00:00
. collect ::< Vec < _ > > ( ) ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::KeyList ( key_ids ) )
2020-04-23 20:25:45 +00:00
}
KeyOperation ::Info ( query ) = > {
2021-03-15 18:14:26 +00:00
let key = self . get_existing_key ( & query . key_pattern ) . await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::KeyInfo ( key ) )
2020-04-23 20:25:45 +00:00
}
KeyOperation ::New ( query ) = > {
2021-10-14 09:50:12 +00:00
let key = Key ::new ( query . name . clone ( ) ) ;
2020-04-23 20:25:45 +00:00
self . garage . key_table . insert ( & key ) . await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::KeyInfo ( key ) )
2020-04-23 20:25:45 +00:00
}
KeyOperation ::Rename ( query ) = > {
2021-03-15 18:14:26 +00:00
let mut key = self . get_existing_key ( & query . key_pattern ) . await ? ;
2021-10-14 09:50:12 +00:00
key . name . update ( query . new_name . clone ( ) ) ;
2020-04-23 20:25:45 +00:00
self . garage . key_table . insert ( & key ) . await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::KeyInfo ( key ) )
2020-04-23 20:25:45 +00:00
}
KeyOperation ::Delete ( query ) = > {
2021-03-15 18:14:26 +00:00
let key = self . get_existing_key ( & query . key_pattern ) . await ? ;
2020-04-23 20:25:45 +00:00
if ! query . yes {
2021-05-02 21:13:08 +00:00
return Err ( Error ::BadRpc (
2021-04-23 20:41:24 +00:00
" Add --yes flag to really perform this operation " . to_string ( ) ,
) ) ;
2020-04-23 20:25:45 +00:00
}
// --- done checking, now commit ---
2020-11-20 20:15:24 +00:00
for ( ab_name , _ , _ ) in key . authorized_buckets . items ( ) . iter ( ) {
2020-11-20 22:01:12 +00:00
if let Some ( bucket ) = self . garage . bucket_table . get ( & EmptyKey , ab_name ) . await ? {
if ! bucket . is_deleted ( ) {
2020-04-23 20:25:45 +00:00
self . update_bucket_key ( bucket , & key . key_id , false , false )
. await ? ;
}
} else {
2020-11-20 20:15:24 +00:00
return Err ( Error ::Message ( format! ( " Bucket not found: {} " , ab_name ) ) ) ;
2020-04-23 20:25:45 +00:00
}
}
2021-03-15 18:14:26 +00:00
let del_key = Key ::delete ( key . key_id . to_string ( ) ) ;
2020-04-23 20:25:45 +00:00
self . garage . key_table . insert ( & del_key ) . await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( format! (
2020-04-23 20:25:45 +00:00
" Key {} was deleted successfully. " ,
2021-03-15 18:14:26 +00:00
key . key_id
2020-04-23 20:25:45 +00:00
) ) )
}
2021-03-18 18:24:59 +00:00
KeyOperation ::Import ( query ) = > {
2021-04-05 17:55:53 +00:00
let prev_key = self . garage . key_table . get ( & EmptyKey , & query . key_id ) . await ? ;
2021-03-18 18:24:59 +00:00
if prev_key . is_some ( ) {
return Err ( Error ::Message ( format! ( " Key {} already exists in data store. Even if it is deleted, we can't let you create a new key with the same ID. Sorry. " , query . key_id ) ) ) ;
}
let imported_key = Key ::import ( & query . key_id , & query . secret_key , & query . name ) ;
self . garage . key_table . insert ( & imported_key ) . await ? ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::KeyInfo ( imported_key ) )
2021-03-18 18:24:59 +00:00
}
2020-04-23 20:25:45 +00:00
}
}
2021-04-23 20:41:24 +00:00
#[ allow(clippy::ptr_arg) ]
2020-04-23 20:25:45 +00:00
async fn get_existing_bucket ( & self , bucket : & String ) -> Result < Bucket , Error > {
self . garage
. bucket_table
. get ( & EmptyKey , bucket )
. await ?
2020-11-20 22:01:12 +00:00
. filter ( | b | ! b . is_deleted ( ) )
2020-04-23 20:25:45 +00:00
. map ( Ok )
2021-05-02 21:13:08 +00:00
. unwrap_or_else ( | | Err ( Error ::BadRpc ( format! ( " Bucket {} does not exist " , bucket ) ) ) )
2020-04-23 20:25:45 +00:00
}
2021-03-15 18:14:26 +00:00
async fn get_existing_key ( & self , pattern : & str ) -> Result < Key , Error > {
2021-03-15 22:14:12 +00:00
let candidates = self
. garage
2020-04-23 20:25:45 +00:00
. key_table
2021-03-15 22:14:12 +00:00
. get_range (
& EmptyKey ,
None ,
Some ( KeyFilter ::Matches ( pattern . to_string ( ) ) ) ,
10 ,
)
2020-04-23 20:25:45 +00:00
. await ?
2021-03-15 18:14:26 +00:00
. into_iter ( )
2020-11-20 20:15:24 +00:00
. filter ( | k | ! k . deleted . get ( ) )
2021-03-15 18:14:26 +00:00
. collect ::< Vec < _ > > ( ) ;
if candidates . len ( ) ! = 1 {
2021-03-15 22:14:12 +00:00
Err ( Error ::Message ( format! (
" {} matching keys " ,
candidates . len ( )
) ) )
2021-03-15 18:14:26 +00:00
} else {
Ok ( candidates . into_iter ( ) . next ( ) . unwrap ( ) )
}
2020-04-23 20:25:45 +00:00
}
2020-12-15 11:48:24 +00:00
/// Update **bucket table** to inform of the new linked key
2020-04-23 20:25:45 +00:00
async fn update_bucket_key (
& self ,
mut bucket : Bucket ,
2021-04-23 20:41:24 +00:00
key_id : & str ,
2020-04-23 20:25:45 +00:00
allow_read : bool ,
allow_write : bool ,
) -> Result < ( ) , Error > {
2020-12-14 20:46:49 +00:00
if let BucketState ::Present ( params ) = bucket . state . get_mut ( ) {
let ak = & mut params . authorized_keys ;
2020-11-20 22:01:12 +00:00
let old_ak = ak . take_and_clear ( ) ;
ak . merge ( & old_ak . update_mutator (
key_id . to_string ( ) ,
PermissionSet {
allow_read ,
allow_write ,
} ,
) ) ;
} else {
2021-04-23 20:41:24 +00:00
return Err ( Error ::Message (
" Bucket is deleted in update_bucket_key " . to_string ( ) ,
) ) ;
2020-11-20 22:01:12 +00:00
}
2020-11-20 22:09:32 +00:00
self . garage . bucket_table . insert ( & bucket ) . await ? ;
2020-04-23 20:25:45 +00:00
Ok ( ( ) )
}
2020-12-12 16:00:31 +00:00
/// Update **key table** to inform of the new linked bucket
2020-04-23 20:25:45 +00:00
async fn update_key_bucket (
& self ,
2021-03-15 18:14:26 +00:00
key : & Key ,
2021-04-23 20:41:24 +00:00
bucket : & str ,
2020-04-23 20:25:45 +00:00
allow_read : bool ,
allow_write : bool ,
) -> Result < ( ) , Error > {
2021-03-15 18:14:26 +00:00
let mut key = key . clone ( ) ;
2020-11-20 20:15:24 +00:00
let old_map = key . authorized_buckets . take_and_clear ( ) ;
2020-11-20 22:01:12 +00:00
key . authorized_buckets . merge ( & old_map . update_mutator (
2021-04-23 20:41:24 +00:00
bucket . to_string ( ) ,
2020-11-20 22:01:12 +00:00
PermissionSet {
allow_read ,
allow_write ,
} ,
) ) ;
2020-04-23 20:25:45 +00:00
self . garage . key_table . insert ( & key ) . await ? ;
Ok ( ( ) )
2020-04-23 18:36:12 +00:00
}
2021-04-23 20:41:24 +00:00
async fn handle_launch_repair ( self : & Arc < Self > , opt : RepairOpt ) -> Result < AdminRpc , Error > {
2020-04-21 16:40:17 +00:00
if ! opt . yes {
2021-05-02 21:13:08 +00:00
return Err ( Error ::BadRpc (
2021-04-23 20:41:24 +00:00
" Please provide the --yes flag to initiate repair operations. " . to_string ( ) ,
) ) ;
2020-04-21 16:40:17 +00:00
}
if opt . all_nodes {
let mut opt_to_send = opt . clone ( ) ;
opt_to_send . all_nodes = false ;
2020-04-19 20:36:36 +00:00
let mut failures = vec! [ ] ;
let ring = self . garage . system . ring . borrow ( ) . clone ( ) ;
2021-11-09 11:24:04 +00:00
for node in ring . layout . node_ids ( ) . iter ( ) {
2021-10-15 09:05:09 +00:00
let node = ( * node ) . into ( ) ;
let resp = self
2021-10-14 09:50:12 +00:00
. endpoint
2020-04-21 16:40:17 +00:00
. call (
2021-10-14 09:50:12 +00:00
& node ,
& AdminRpc ::LaunchRepair ( opt_to_send . clone ( ) ) ,
PRIO_NORMAL ,
2020-04-21 16:40:17 +00:00
)
2021-10-15 09:05:09 +00:00
. await ;
2021-10-19 14:16:10 +00:00
if ! matches! ( resp , Ok ( Ok ( _ ) ) ) {
2021-10-14 09:50:12 +00:00
failures . push ( node ) ;
2020-04-19 20:36:36 +00:00
}
}
if failures . is_empty ( ) {
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( " Repair launched on all nodes " . to_string ( ) ) )
2020-04-19 20:36:36 +00:00
} else {
Err ( Error ::Message ( format! (
" Could not launch repair on nodes: {:?} (launched successfully on other nodes) " ,
failures
) ) )
}
} else {
2020-04-23 18:36:12 +00:00
let repair = Repair {
garage : self . garage . clone ( ) ,
} ;
2020-04-19 21:27:08 +00:00
self . garage
. system
. background
2020-04-19 21:33:38 +00:00
. spawn_worker ( " Repair worker " . into ( ) , move | must_exit | async move {
2020-04-23 18:36:12 +00:00
repair . repair_worker ( opt , must_exit ) . await
2021-03-11 12:47:21 +00:00
} ) ;
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( format! (
2020-04-19 20:36:36 +00:00
" Repair launched on {:?} " ,
self . garage . system . id
) ) )
}
}
2021-03-12 14:40:54 +00:00
2021-04-23 20:41:24 +00:00
async fn handle_stats ( & self , opt : StatsOpt ) -> Result < AdminRpc , Error > {
2021-03-12 14:40:54 +00:00
if opt . all_nodes {
let mut ret = String ::new ( ) ;
let ring = self . garage . system . ring . borrow ( ) . clone ( ) ;
2021-11-09 11:24:04 +00:00
for node in ring . layout . node_ids ( ) . iter ( ) {
2021-03-12 14:40:54 +00:00
let mut opt = opt . clone ( ) ;
opt . all_nodes = false ;
writeln! ( & mut ret , " \n ====================== " ) . unwrap ( ) ;
writeln! ( & mut ret , " Stats for node {:?}: " , node ) . unwrap ( ) ;
2021-10-15 09:05:09 +00:00
let node_id = ( * node ) . into ( ) ;
2021-03-12 14:40:54 +00:00
match self
2021-10-14 09:50:12 +00:00
. endpoint
2021-10-15 09:05:09 +00:00
. call ( & node_id , & AdminRpc ::Stats ( opt ) , PRIO_NORMAL )
. await ?
2021-03-12 14:40:54 +00:00
{
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( s ) ) = > writeln! ( & mut ret , " {} " , s ) . unwrap ( ) ,
2021-03-12 14:40:54 +00:00
Ok ( x ) = > writeln! ( & mut ret , " Bad answer: {:?} " , x ) . unwrap ( ) ,
Err ( e ) = > writeln! ( & mut ret , " Error: {} " , e ) . unwrap ( ) ,
}
}
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( ret ) )
2021-03-12 14:40:54 +00:00
} else {
2021-04-23 20:41:24 +00:00
Ok ( AdminRpc ::Ok ( self . gather_stats_local ( opt ) ) )
2021-03-12 14:40:54 +00:00
}
}
2021-04-23 20:41:24 +00:00
fn gather_stats_local ( & self , opt : StatsOpt ) -> String {
2021-03-12 14:40:54 +00:00
let mut ret = String ::new ( ) ;
2021-03-12 17:16:03 +00:00
writeln! (
& mut ret ,
" \n Garage version: {} " ,
2021-10-04 16:27:57 +00:00
option_env! ( " GIT_VERSION " ) . unwrap_or ( git_version ::git_version! (
2021-10-11 12:26:54 +00:00
prefix = " git: " ,
cargo_prefix = " cargo: " ,
fallback = " unknown "
2021-10-04 16:27:57 +00:00
) )
2021-03-12 17:16:03 +00:00
)
. unwrap ( ) ;
2021-03-12 14:40:54 +00:00
// Gather ring statistics
let ring = self . garage . system . ring . borrow ( ) . clone ( ) ;
let mut ring_nodes = HashMap ::new ( ) ;
2021-05-28 10:36:22 +00:00
for ( _i , loc ) in ring . partitions ( ) . iter ( ) {
for n in ring . get_nodes ( loc , ring . replication_factor ) . iter ( ) {
2021-03-12 14:40:54 +00:00
if ! ring_nodes . contains_key ( n ) {
ring_nodes . insert ( * n , 0 usize ) ;
}
* ring_nodes . get_mut ( n ) . unwrap ( ) + = 1 ;
}
}
writeln! ( & mut ret , " \n Ring nodes & partition count: " ) . unwrap ( ) ;
for ( n , c ) in ring_nodes . iter ( ) {
writeln! ( & mut ret , " {:?} {} " , n , c ) . unwrap ( ) ;
}
2021-04-23 20:41:24 +00:00
self . gather_table_stats ( & mut ret , & self . garage . bucket_table , & opt ) ;
self . gather_table_stats ( & mut ret , & self . garage . key_table , & opt ) ;
self . gather_table_stats ( & mut ret , & self . garage . object_table , & opt ) ;
self . gather_table_stats ( & mut ret , & self . garage . version_table , & opt ) ;
self . gather_table_stats ( & mut ret , & self . garage . block_ref_table , & opt ) ;
2021-03-12 14:40:54 +00:00
writeln! ( & mut ret , " \n Block manager stats: " ) . unwrap ( ) ;
2021-03-16 15:35:10 +00:00
if opt . detailed {
writeln! (
& mut ret ,
2021-10-28 12:32:55 +00:00
" number of RC entries (~= number of blocks): {} " ,
2021-03-16 15:35:10 +00:00
self . garage . block_manager . rc_len ( )
)
. unwrap ( ) ;
}
2021-03-12 17:16:03 +00:00
writeln! (
& mut ret ,
" resync queue length: {} " ,
2021-03-15 18:51:16 +00:00
self . garage . block_manager . resync_queue_len ( )
2021-03-12 17:16:03 +00:00
)
. unwrap ( ) ;
2021-03-12 14:40:54 +00:00
2021-04-23 20:41:24 +00:00
ret
2021-03-12 14:40:54 +00:00
}
2021-04-23 20:41:24 +00:00
fn gather_table_stats < F , R > ( & self , to : & mut String , t : & Arc < Table < F , R > > , opt : & StatsOpt )
2021-03-16 10:43:58 +00:00
where
F : TableSchema + 'static ,
R : TableReplication + 'static ,
{
2021-03-12 14:40:54 +00:00
writeln! ( to , " \n Table stats for {} " , t . data . name ) . unwrap ( ) ;
2021-03-16 15:35:10 +00:00
if opt . detailed {
writeln! ( to , " number of items: {} " , t . data . store . len ( ) ) . unwrap ( ) ;
writeln! (
to ,
" Merkle tree size: {} " ,
t . merkle_updater . merkle_tree_len ( )
)
. unwrap ( ) ;
}
2021-03-12 17:16:03 +00:00
writeln! (
to ,
" Merkle updater todo queue length: {} " ,
2021-03-16 10:43:58 +00:00
t . merkle_updater . todo_len ( )
2021-03-12 17:16:03 +00:00
)
. unwrap ( ) ;
2021-03-15 22:14:12 +00:00
writeln! ( to , " GC todo queue length: {} " , t . data . gc_todo_len ( ) ) . unwrap ( ) ;
2021-03-12 14:40:54 +00:00
}
2021-10-15 09:05:09 +00:00
}
2021-10-14 09:50:12 +00:00
2021-10-15 09:05:09 +00:00
#[ async_trait ]
impl EndpointHandler < AdminRpc > for AdminRpcHandler {
async fn handle (
self : & Arc < Self > ,
message : & AdminRpc ,
_from : NodeID ,
) -> Result < AdminRpc , Error > {
match message {
2021-10-14 09:50:12 +00:00
AdminRpc ::BucketOperation ( bo ) = > self . handle_bucket_cmd ( bo ) . await ,
AdminRpc ::KeyOperation ( ko ) = > self . handle_key_cmd ( ko ) . await ,
AdminRpc ::LaunchRepair ( opt ) = > self . handle_launch_repair ( opt . clone ( ) ) . await ,
AdminRpc ::Stats ( opt ) = > self . handle_stats ( opt . clone ( ) ) . await ,
_ = > Err ( Error ::BadRpc ( " Invalid RPC " . to_string ( ) ) ) ,
}
}
}