aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <lx@deuxfleurs.fr>2025-02-05 14:22:10 +0100
committerAlex Auvolat <lx@deuxfleurs.fr>2025-02-05 14:22:10 +0100
commit9f468b4439bdd5e2e67a6215f941556310877155 (patch)
tree7524ac5326e069d014fd25b624d794d52aa5e745
parent97be7b38fa3bd3172895f6ab44157e5236d65cd6 (diff)
downloadgarage-9f468b4439bdd5e2e67a6215f941556310877155.tar.gz
garage-9f468b4439bdd5e2e67a6215f941556310877155.zip
cli_v2: implement CreateMetadataSnapshot
-rw-r--r--src/api/admin/api.rs17
-rw-r--r--src/api/admin/lib.rs1
-rw-r--r--src/api/admin/node.rs23
-rw-r--r--src/api/admin/router_v2.rs2
-rw-r--r--src/garage/admin/mod.rs43
-rw-r--r--src/garage/cli/cmd.rs18
-rw-r--r--src/garage/cli/layout.rs13
-rw-r--r--src/garage/cli_v2/mod.rs9
-rw-r--r--src/garage/cli_v2/node.rs36
9 files changed, 94 insertions, 68 deletions
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,
@@ -624,6 +629,18 @@ pub struct RemoveBucketAliasRequest {
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<Garage>,
+ _admin: &Admin,
+ ) -> Result<LocalCreateMetadataSnapshotResponse, Error> {
+ 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<Self>, mo: &MetaOperation) -> Result<AdminRpc, Error> {
- 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<AdminRpc> 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<SystemRpc, ()>,
- rpc_host: NodeID,
-) -> Result<Vec<KnownNodeInfo>, 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<SystemRpc, ()>,
+ rpc_host: NodeID,
+) -> Result<Vec<KnownNodeInfo>, 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<SystemRpc, ()>,
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(())
+ }
+}