diff --git a/src/api/admin/api.rs b/src/api/admin/api.rs index cde11bac..3f041208 100644 --- a/src/api/admin/api.rs +++ b/src/api/admin/api.rs @@ -77,6 +77,9 @@ admin_endpoints![ AddBucketAlias, RemoveBucketAlias, + // Node operations + CreateMetadataSnapshot, + // Worker operations ListWorkers, GetWorkerInfo, @@ -91,6 +94,8 @@ admin_endpoints![ ]; local_admin_endpoints![ + // Node operations + CreateMetadataSnapshot, // Background workers ListWorkers, GetWorkerInfo, @@ -623,6 +628,18 @@ pub struct RemoveBucketAliasRequest { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RemoveBucketAliasResponse(pub GetBucketInfoResponse); +// ********************************************** +// Node operations +// ********************************************** + +// ---- CreateMetadataSnapshot ---- + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct LocalCreateMetadataSnapshotRequest; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LocalCreateMetadataSnapshotResponse; + // ********************************************** // Worker operations // ********************************************** diff --git a/src/api/admin/lib.rs b/src/api/admin/lib.rs index e7ee37af..cc673eef 100644 --- a/src/api/admin/lib.rs +++ b/src/api/admin/lib.rs @@ -16,6 +16,7 @@ mod key; mod special; mod block; +mod node; mod worker; use std::sync::Arc; diff --git a/src/api/admin/node.rs b/src/api/admin/node.rs new file mode 100644 index 00000000..8c79acfd --- /dev/null +++ b/src/api/admin/node.rs @@ -0,0 +1,23 @@ +use std::sync::Arc; + +use async_trait::async_trait; + +use garage_model::garage::Garage; + +use crate::api::*; +use crate::error::Error; +use crate::{Admin, RequestHandler}; + +#[async_trait] +impl RequestHandler for LocalCreateMetadataSnapshotRequest { + type Response = LocalCreateMetadataSnapshotResponse; + + async fn handle( + self, + garage: &Arc, + _admin: &Admin, + ) -> Result { + garage_model::snapshot::async_snapshot_metadata(garage).await?; + Ok(LocalCreateMetadataSnapshotResponse) + } +} diff --git a/src/api/admin/router_v2.rs b/src/api/admin/router_v2.rs index 74822007..dac6c5f9 100644 --- a/src/api/admin/router_v2.rs +++ b/src/api/admin/router_v2.rs @@ -59,6 +59,8 @@ impl AdminApiRequest { // Bucket aliases POST AddBucketAlias (body), POST RemoveBucketAlias (body), + // Node APIs + POST CreateMetadataSnapshot (default::body, query::node), // Worker APIs POST ListWorkers (body_field, query::node), POST GetWorkerInfo (body_field, query::node), diff --git a/src/garage/admin/mod.rs b/src/garage/admin/mod.rs index 4f734b1a..87724559 100644 --- a/src/garage/admin/mod.rs +++ b/src/garage/admin/mod.rs @@ -20,10 +20,6 @@ use garage_rpc::*; use garage_model::garage::Garage; use garage_model::helper::error::Error; -use garage_api_admin::api::{AdminApiRequest, TaggedAdminApiResponse}; -use garage_api_admin::RequestHandler as AdminApiEndpoint; -use garage_api_common::generic_server::ApiError; - use crate::cli::*; use crate::repair::online::launch_online_repair; @@ -34,7 +30,6 @@ pub const ADMIN_RPC_PATH: &str = "garage/admin_rpc.rs/Rpc"; pub enum AdminRpc { LaunchRepair(RepairOpt), Stats(StatsOpt), - MetaOperation(MetaOperation), // Replies Ok(String), @@ -319,43 +314,6 @@ impl AdminRpcHandler { t.data.gc_todo_len()? )) } - - // ================ META DB COMMANDS ==================== - - async fn handle_meta_cmd(self: &Arc, mo: &MetaOperation) -> Result { - match mo { - MetaOperation::Snapshot { all: true } => { - let to = self.garage.system.cluster_layout().all_nodes().to_vec(); - - let resps = futures::future::join_all(to.iter().map(|to| async move { - let to = (*to).into(); - self.endpoint - .call( - &to, - AdminRpc::MetaOperation(MetaOperation::Snapshot { all: false }), - PRIO_NORMAL, - ) - .await - })) - .await; - - let mut ret = vec![]; - for (to, resp) in to.iter().zip(resps.iter()) { - let res_str = match resp { - Ok(_) => "ok".to_string(), - Err(e) => format!("error: {}", e), - }; - ret.push(format!("{:?}\t{}", to, res_str)); - } - - Ok(AdminRpc::Ok(format_table_to_string(ret))) - } - MetaOperation::Snapshot { all: false } => { - garage_model::snapshot::async_snapshot_metadata(&self.garage).await?; - Ok(AdminRpc::Ok("Snapshot has been saved.".into())) - } - } - } } #[async_trait] @@ -368,7 +326,6 @@ impl EndpointHandler for AdminRpcHandler { match message { AdminRpc::LaunchRepair(opt) => self.handle_launch_repair(opt.clone()).await, AdminRpc::Stats(opt) => self.handle_stats(opt.clone()).await, - AdminRpc::MetaOperation(mo) => self.handle_meta_cmd(mo).await, m => Err(GarageError::unexpected_rpc_message(m).into()), } } diff --git a/src/garage/cli/cmd.rs b/src/garage/cli/cmd.rs index e5af461c..1a9c7841 100644 --- a/src/garage/cli/cmd.rs +++ b/src/garage/cli/cmd.rs @@ -1,6 +1,3 @@ -use garage_util::error::*; - -use garage_rpc::system::*; use garage_rpc::*; use garage_model::helper::error::Error as HelperError; @@ -22,18 +19,3 @@ pub async fn cmd_admin( } Ok(()) } - -// ---- utility ---- - -pub async fn fetch_status( - rpc_cli: &Endpoint, - rpc_host: NodeID, -) -> Result, Error> { - match rpc_cli - .call(&rpc_host, SystemRpc::GetKnownNodes, PRIO_NORMAL) - .await?? - { - SystemRpc::ReturnKnownNodes(nodes) => Ok(nodes), - resp => Err(Error::unexpected_rpc_message(resp)), - } -} diff --git a/src/garage/cli/layout.rs b/src/garage/cli/layout.rs index bb81d144..15040aaa 100644 --- a/src/garage/cli/layout.rs +++ b/src/garage/cli/layout.rs @@ -260,6 +260,19 @@ pub async fn cmd_layout_skip_dead_nodes( // --- utility --- +pub async fn fetch_status( + rpc_cli: &Endpoint, + rpc_host: NodeID, +) -> Result, Error> { + match rpc_cli + .call(&rpc_host, SystemRpc::GetKnownNodes, PRIO_NORMAL) + .await?? + { + SystemRpc::ReturnKnownNodes(nodes) => Ok(nodes), + resp => Err(Error::unexpected_rpc_message(resp)), + } +} + pub async fn fetch_layout( rpc_cli: &Endpoint, rpc_host: NodeID, diff --git a/src/garage/cli_v2/mod.rs b/src/garage/cli_v2/mod.rs index 462e5722..0de4ead8 100644 --- a/src/garage/cli_v2/mod.rs +++ b/src/garage/cli_v2/mod.rs @@ -4,6 +4,7 @@ pub mod key; pub mod layout; pub mod block; +pub mod node; pub mod worker; use std::convert::TryFrom; @@ -43,6 +44,7 @@ impl Cli { Command::Key(ko) => self.cmd_key(ko).await, Command::Worker(wo) => self.cmd_worker(wo).await, Command::Block(bo) => self.cmd_block(bo).await, + Command::Meta(mo) => self.cmd_meta(mo).await, // TODO Command::Repair(ro) => cli_v1::cmd_admin( @@ -57,13 +59,6 @@ impl Cli { .await .ok_or_message("cli_v1") } - Command::Meta(mo) => cli_v1::cmd_admin( - &self.admin_rpc_endpoint, - self.rpc_host, - AdminRpc::MetaOperation(mo), - ) - .await - .ok_or_message("cli_v1"), _ => unreachable!(), } diff --git a/src/garage/cli_v2/node.rs b/src/garage/cli_v2/node.rs new file mode 100644 index 00000000..c5f28300 --- /dev/null +++ b/src/garage/cli_v2/node.rs @@ -0,0 +1,36 @@ +use format_table::format_table; + +use garage_util::error::*; + +use garage_api_admin::api::*; + +use crate::cli::structs::*; +use crate::cli_v2::*; + +impl Cli { + pub async fn cmd_meta(&self, cmd: MetaOperation) -> Result<(), Error> { + let MetaOperation::Snapshot { all } = cmd; + + let res = self + .api_request(CreateMetadataSnapshotRequest { + node: if all { + "*".to_string() + } else { + hex::encode(self.rpc_host) + }, + body: LocalCreateMetadataSnapshotRequest, + }) + .await?; + + let mut table = vec![]; + for (node, err) in res.error.iter() { + table.push(format!("{:.16}\tError: {}", node, err)); + } + for (node, _) in res.success.iter() { + table.push(format!("{:.16}\tOk", node)); + } + format_table(table); + + Ok(()) + } +}