2020-04-19 17:59:59 +00:00
#![ recursion_limit = " 1024 " ]
2021-04-06 03:25:28 +00:00
//! Garage CLI, used to interact with a running Garage instance, and to launch a Garage instance
2020-04-19 17:59:59 +00:00
2020-04-21 12:54:55 +00:00
#[ macro_use ]
extern crate log ;
2021-10-19 14:16:10 +00:00
mod admin ;
2021-03-12 17:16:03 +00:00
mod cli ;
2020-04-24 10:10:01 +00:00
mod repair ;
2020-04-10 20:01:48 +00:00
mod server ;
2020-04-05 21:33:42 +00:00
2021-10-26 09:22:28 +00:00
use std ::net ::SocketAddr ;
2021-10-19 14:16:10 +00:00
use std ::path ::PathBuf ;
2020-04-05 21:33:42 +00:00
use structopt ::StructOpt ;
2021-10-19 14:16:10 +00:00
use netapp ::util ::parse_and_resolve_peer_addr ;
2021-10-14 09:50:12 +00:00
use netapp ::NetworkKey ;
2021-10-19 14:16:10 +00:00
use garage_util ::error ::* ;
2020-04-23 17:05:46 +00:00
2021-10-14 09:50:12 +00:00
use garage_rpc ::system ::* ;
use garage_rpc ::* ;
2020-04-19 11:22:28 +00:00
2022-01-03 12:58:05 +00:00
use garage_model ::helper ::error ::Error as HelperError ;
2021-10-19 14:16:10 +00:00
use admin ::* ;
2021-03-12 17:16:03 +00:00
use cli ::* ;
2020-04-19 15:15:48 +00:00
2020-04-05 21:33:42 +00:00
#[ derive(StructOpt, Debug) ]
#[ structopt(name = " garage " ) ]
2021-03-26 21:36:23 +00:00
struct Opt {
2021-10-14 09:50:12 +00:00
/// Host to connect to for admin operations, in the format:
/// <public-key>@<ip>:<port>
2021-10-28 15:13:13 +00:00
#[ structopt(short = " h " , long = " rpc-host " , env = " GARAGE_RPC_HOST " ) ]
2021-10-14 09:50:12 +00:00
pub rpc_host : Option < String > ,
2020-04-06 17:55:39 +00:00
2021-10-14 09:50:12 +00:00
/// RPC secret network key for admin operations
2021-10-28 15:13:13 +00:00
#[ structopt(short = " s " , long = " rpc-secret " , env = " GARAGE_RPC_SECRET " ) ]
2021-10-14 09:50:12 +00:00
pub rpc_secret : Option < String > ,
2020-04-12 17:41:19 +00:00
2021-10-19 14:16:10 +00:00
/// Configuration file (garage.toml)
2021-10-28 15:13:13 +00:00
#[ structopt(
short = " c " ,
long = " config " ,
env = " GARAGE_CONFIG_FILE " ,
default_value = " /etc/garage.toml "
) ]
2021-10-19 14:16:10 +00:00
pub config_file : PathBuf ,
2020-04-07 14:26:22 +00:00
#[ structopt(subcommand) ]
cmd : Command ,
2020-04-05 21:33:42 +00:00
}
#[ tokio::main ]
async fn main ( ) {
2021-10-26 09:22:28 +00:00
if std ::env ::var ( " RUST_LOG " ) . is_err ( ) {
std ::env ::set_var ( " RUST_LOG " , " garage=info " )
}
2020-04-21 12:54:55 +00:00
pretty_env_logger ::init ( ) ;
2021-10-15 09:05:09 +00:00
sodiumoxide ::init ( ) . expect ( " Unable to init sodiumoxide " ) ;
2020-04-21 12:54:55 +00:00
2020-04-05 21:33:42 +00:00
let opt = Opt ::from_args ( ) ;
2021-10-19 14:16:10 +00:00
let res = match opt . cmd {
Command ::Server = > {
// Abort on panic (same behavior as in Go)
std ::panic ::set_hook ( Box ::new ( | panic_info | {
error! ( " {} " , panic_info . to_string ( ) ) ;
std ::process ::abort ( ) ;
} ) ) ;
server ::run_server ( opt . config_file ) . await
}
2021-11-09 11:24:04 +00:00
Command ::Node ( NodeOperation ::NodeId ( node_id_opt ) ) = > {
node_id_command ( opt . config_file , node_id_opt . quiet )
}
2021-10-19 14:16:10 +00:00
_ = > cli_command ( opt ) . await ,
2021-03-12 17:12:31 +00:00
} ;
if let Err ( e ) = res {
2021-10-19 14:16:10 +00:00
eprintln! ( " Error: {} " , e ) ;
std ::process ::exit ( 1 ) ;
2021-03-12 17:12:31 +00:00
}
}
async fn cli_command ( opt : Opt ) -> Result < ( ) , Error > {
2021-10-19 14:16:10 +00:00
let config = if opt . rpc_secret . is_none ( ) | | opt . rpc_host . is_none ( ) {
Some ( garage_util ::config ::read_config ( opt . config_file . clone ( ) )
. err_context ( format! ( " Unable to read configuration file {} . Configuration file is needed because -h or -s is not provided on the command line. " , opt . config_file . to_string_lossy ( ) ) ) ? )
} else {
None
} ;
// Find and parse network RPC secret
let net_key_hex_str = opt
. rpc_secret
. as_ref ( )
. or_else ( | | config . as_ref ( ) . map ( | c | & c . rpc_secret ) )
. ok_or ( " No RPC secret provided " ) ? ;
2021-10-14 09:50:12 +00:00
let network_key = NetworkKey ::from_slice (
2021-10-19 14:16:10 +00:00
& hex ::decode ( net_key_hex_str ) . err_context ( " Invalid RPC secret key (bad hex) " ) ? [ .. ] ,
2021-10-14 09:50:12 +00:00
)
2021-10-19 14:16:10 +00:00
. ok_or ( " Invalid RPC secret provided (wrong length) " ) ? ;
// Generate a temporary keypair for our RPC client
2021-10-14 09:50:12 +00:00
let ( _pk , sk ) = sodiumoxide ::crypto ::sign ::ed25519 ::gen_keypair ( ) ;
let netapp = NetApp ::new ( network_key , sk ) ;
2021-10-19 14:16:10 +00:00
// Find and parse the address of the target host
let ( id , addr ) = if let Some ( h ) = opt . rpc_host {
let ( id , addrs ) = parse_and_resolve_peer_addr ( & h ) . ok_or_else ( | | format! ( " Invalid RPC remote node identifier: {} . Expected format is <pubkey>@<IP or hostname>:<port>. " , h ) ) ? ;
( id , addrs [ 0 ] )
} else {
2021-10-26 09:22:28 +00:00
let node_id = garage_rpc ::system ::read_node_id ( & config . as_ref ( ) . unwrap ( ) . metadata_dir )
. err_context ( READ_KEY_ERROR ) ? ;
if let Some ( a ) = config . as_ref ( ) . map ( | c | c . rpc_public_addr ) . flatten ( ) {
( node_id , a )
} else {
let default_addr = SocketAddr ::new (
" 127.0.0.1 " . parse ( ) . unwrap ( ) ,
config . as_ref ( ) . unwrap ( ) . rpc_bind_addr . port ( ) ,
) ;
warn! (
" Trying to contact Garage node at default address {} " ,
default_addr
) ;
warn! ( " If this doesn't work, consider adding rpc_public_addr in your config file or specifying the -h command line parameter. " ) ;
( node_id , default_addr )
}
2021-10-19 14:16:10 +00:00
} ;
// Connect to target host
netapp . clone ( ) . try_connect ( addr , id ) . await
. err_context ( " Unable to connect to destination RPC host. Check that you are using the same value of rpc_secret as them, and that you have their correct public key. " ) ? ;
2021-10-14 09:50:12 +00:00
let system_rpc_endpoint = netapp . endpoint ::< SystemRpc , ( ) > ( SYSTEM_RPC_PATH . into ( ) ) ;
let admin_rpc_endpoint = netapp . endpoint ::< AdminRpc , ( ) > ( ADMIN_RPC_PATH . into ( ) ) ;
2022-01-03 12:58:05 +00:00
match cli_command_dispatch ( opt . cmd , & system_rpc_endpoint , & admin_rpc_endpoint , id ) . await {
2022-01-03 18:06:04 +00:00
Err ( HelperError ::Internal ( i ) ) = > Err ( Error ::Message ( format! ( " Internal error: {} " , i ) ) ) ,
Err ( HelperError ::BadRequest ( b ) ) = > Err ( Error ::Message ( b ) ) ,
2022-01-03 12:58:05 +00:00
Ok ( x ) = > Ok ( x ) ,
}
2021-06-01 17:05:15 +00:00
}