From 9ec8c8a0d966c2bcbc7627eab050ee6d8ec3532b Mon Sep 17 00:00:00 2001
From: Georgy Moshkin <gmoshkin@picodata.io>
Date: Tue, 23 Jan 2024 15:57:45 +0300
Subject: [PATCH] feat: .proc_raft_info

---
 src/info.rs                    | 40 ++++++++++++++++++++++++++++++++++
 test/int/test_basics.py        | 17 +++++++++++++++
 test/int/test_uninitialized.py |  1 +
 3 files changed, 58 insertions(+)

diff --git a/src/info.rs b/src/info.rs
index f63201ff78..c5b057c461 100644
--- a/src/info.rs
+++ b/src/info.rs
@@ -140,3 +140,43 @@ impl crate::rpc::RequestArgs for InstanceInfoRequest {
     const PROC_NAME: &'static str = crate::stringify_cfunc!(proc_instance_info);
     type Response = InstanceInfo;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// RaftInfo
+////////////////////////////////////////////////////////////////////////////////
+
+#[derive(Clone, Debug, ::serde::Serialize, ::serde::Deserialize)]
+pub struct RaftInfo {
+    pub id: RaftId,
+    pub term: RaftTerm,
+    pub applied: RaftIndex,
+    pub leader_id: RaftId,
+    pub state: node::RaftState,
+}
+
+impl tarantool::tuple::Encode for RaftInfo {}
+
+impl RaftInfo {
+    #[inline]
+    pub fn get(node: &node::Node) -> Self {
+        let raft_status = node.status();
+        RaftInfo {
+            id: raft_status.id,
+            term: raft_status.term,
+            applied: node.get_index(),
+            leader_id: raft_status.leader_id.unwrap_or(0),
+            state: raft_status.raft_state,
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// .proc_raft_info
+////////////////////////////////////////////////////////////////////////////////
+
+#[proc]
+pub fn proc_raft_info() -> Result<RaftInfo, Error> {
+    let node = node::global()?;
+
+    Ok(RaftInfo::get(node))
+}
diff --git a/test/int/test_basics.py b/test/int/test_basics.py
index afcf32eba2..5dd78ad268 100644
--- a/test/int/test_basics.py
+++ b/test/int/test_basics.py
@@ -373,3 +373,20 @@ def test_proc_instance_info(cluster: Cluster):
     with pytest.raises(TarantoolError) as e:
         i1.call(".proc_instance_info", "i3")
     assert 'instance with id "i3" not found' in str(e)
+
+
+def test_proc_raft_info(instance: Instance):
+    info = instance.call(".proc_raft_info")
+
+    assert isinstance(info["applied"], int)
+    # This field is super volatile, don't want to be updating it every time we
+    # add a bootstrap entry.
+    info["applied"] = 69
+
+    assert info == dict(
+        id=1,
+        term=2,
+        applied=69,
+        leader_id=1,
+        state="Leader",
+    )
diff --git a/test/int/test_uninitialized.py b/test/int/test_uninitialized.py
index 3b996649fa..a59eaa64ee 100644
--- a/test/int/test_uninitialized.py
+++ b/test/int/test_uninitialized.py
@@ -31,6 +31,7 @@ def uninitialized_instance(cluster: Cluster) -> Generator[Instance, None, None]:
 def test_raft_api(uninitialized_instance: Instance):
     functions: list[Callable[[Instance], Any]] = [
         lambda i: i._raft_status(),
+        lambda i: i.call(".proc_raft_info"),
         lambda i: i.raft_get_index(),
         lambda i: i.raft_read_index(),
         lambda i: i.raft_wait_index(0),
-- 
GitLab